From fe4cb86cdea781e969f37b9aa9db95577ff485f2 Mon Sep 17 00:00:00 2001 From: Jérémy Lefaure Date: Fri, 16 Dec 2016 19:25:27 -0500 Subject: ALSA: cs5535audio: fix unused warnings on resume/suspend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When CONFIG_PM_SLEEP is disabled, SIMPLE_DEV_PM_OPS does not use snd_cs5535audio_resume and snd_cs5535audio_suspend functions: sound/pci/cs5535audio/cs5535audio_pm.c:77:12: warning: ‘snd_cs5535audio_resume’ defined but not used [-Wunused-function] static int snd_cs5535audio_resume(struct device *dev) ^~~~~~~~~~~~~~~~~~~~~~ sound/pci/cs5535audio/cs5535audio_pm.c:58:12: warning: ‘snd_cs5535audio_suspend’ defined but not used [-Wunused-function] static int snd_cs5535audio_suspend(struct device *dev) ^~~~~~~~~~~~~~~~~~~~~~~ Adding __maybe_unused to the declaration of these functions removes the warnings. Signed-off-by: Jérémy Lefaure Signed-off-by: Takashi Iwai --- sound/pci/cs5535audio/cs5535audio_pm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/cs5535audio/cs5535audio_pm.c b/sound/pci/cs5535audio/cs5535audio_pm.c index 06ac5d8da362..82bd10b68a77 100644 --- a/sound/pci/cs5535audio/cs5535audio_pm.c +++ b/sound/pci/cs5535audio/cs5535audio_pm.c @@ -55,7 +55,7 @@ static void snd_cs5535audio_stop_hardware(struct cs5535audio *cs5535au) } -static int snd_cs5535audio_suspend(struct device *dev) +static int __maybe_unused snd_cs5535audio_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct cs5535audio *cs5535au = card->private_data; @@ -74,7 +74,7 @@ static int snd_cs5535audio_suspend(struct device *dev) return 0; } -static int snd_cs5535audio_resume(struct device *dev) +static int __maybe_unused snd_cs5535audio_resume(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct cs5535audio *cs5535au = card->private_data; -- cgit v1.2.3 From f93a1c9e5e6a8ce05391708157af5bfd71fe6c21 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 16 Dec 2016 16:59:44 -0800 Subject: ALSA: synth: use designated initializers Prepare to mark sensitive kernel structures for randomization by making sure they're using designated initializers. These were identified during allyesconfig builds of x86, arm, and arm64, with most initializer fixes extracted from grsecurity. Signed-off-by: Kees Cook Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/synth/emux/emux_seq.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/synth/emux/emux_seq.c b/sound/synth/emux/emux_seq.c index a0209204ae48..55579f6b8cb2 100644 --- a/sound/synth/emux/emux_seq.c +++ b/sound/synth/emux/emux_seq.c @@ -33,13 +33,13 @@ static int snd_emux_unuse(void *private_data, struct snd_seq_port_subscribe *inf * MIDI emulation operators */ static struct snd_midi_op emux_ops = { - snd_emux_note_on, - snd_emux_note_off, - snd_emux_key_press, - snd_emux_terminate_note, - snd_emux_control, - snd_emux_nrpn, - snd_emux_sysex, + .note_on = snd_emux_note_on, + .note_off = snd_emux_note_off, + .key_press = snd_emux_key_press, + .note_terminate = snd_emux_terminate_note, + .control = snd_emux_control, + .nrpn = snd_emux_nrpn, + .sysex = snd_emux_sysex, }; -- cgit v1.2.3 From 3eff682d765b496ce2f9727bb1e001ec77b21453 Mon Sep 17 00:00:00 2001 From: Jussi Laako Date: Sat, 17 Dec 2016 23:51:41 +0200 Subject: ALSA: usb-audio: Support both DSD LE/BE Amanero firmware versions Add DSD support for both little endian (DSD_U32_LE) and big endian (DSD_U32_BE) version of the Amanero firmware. Signed-off-by: Jussi Laako Signed-off-by: Takashi Iwai --- sound/usb/quirks.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index b3fd2382fdd9..f5c68ea0468e 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1359,6 +1359,21 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, if (fp->altsetting == 3) return SNDRV_PCM_FMTBIT_DSD_U32_BE; break; + + /* Amanero Combo384 USB interface with native DSD support */ + case USB_ID(0x16d0, 0x071a): + if (fp->altsetting == 2) { + switch (chip->dev->descriptor.bcdDevice) { + case 0x199: + return SNDRV_PCM_FMTBIT_DSD_U32_LE; + case 0x19b: + return SNDRV_PCM_FMTBIT_DSD_U32_BE; + default: + break; + } + } + break; + default: break; } -- cgit v1.2.3 From 1c623c2409b105c3960d60f450ccc0b37d8cb89a Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Sat, 24 Dec 2016 23:28:34 +0800 Subject: ALSA: mixart: fix a comment typo Fix a comment typo in mixart.h. Signed-off-by: Geliang Tang Signed-off-by: Takashi Iwai --- sound/pci/mixart/mixart.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/mixart/mixart.h b/sound/pci/mixart/mixart.h index 0cc17e0ea34a..426743871540 100644 --- a/sound/pci/mixart/mixart.h +++ b/sound/pci/mixart/mixart.h @@ -86,7 +86,7 @@ struct mixart_mgr { u32 msg_fifo[MSG_FIFO_SIZE]; int msg_fifo_readptr; int msg_fifo_writeptr; - atomic_t msg_processed; /* number of messages to be processed in takslet */ + atomic_t msg_processed; /* number of messages to be processed in tasklet */ struct mutex lock; /* interrupt lock */ struct mutex msg_lock; /* mailbox lock */ -- cgit v1.2.3 From 972aa2c708703c21f14eb958b37e82aae2530e44 Mon Sep 17 00:00:00 2001 From: Gabriele Mazzotta Date: Sat, 24 Dec 2016 19:50:00 +0100 Subject: ALSA: hda - Apply ALC269_FIXUP_NO_SHUTUP on HDA_FIXUP_ACT_PROBE Setting shutup when the action is HDA_FIXUP_ACT_PRE_PROBE might not have the desired effect since it could be overridden by another more generic shutup function. Prevent this by setting the more specific shutup function on HDA_FIXUP_ACT_PROBE. Signed-off-by: Gabriele Mazzotta Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 9448daff9d8b..937c2bbe8b50 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4400,7 +4400,7 @@ static void alc_no_shutup(struct hda_codec *codec) static void alc_fixup_no_shutup(struct hda_codec *codec, const struct hda_fixup *fix, int action) { - if (action == HDA_FIXUP_ACT_PRE_PROBE) { + if (action == HDA_FIXUP_ACT_PROBE) { struct alc_spec *spec = codec->spec; spec->shutup = alc_no_shutup; } -- cgit v1.2.3 From 823ff161fe51179cc9ad1a3f6c7e4532901e0444 Mon Sep 17 00:00:00 2001 From: Gabriele Mazzotta Date: Sat, 24 Dec 2016 19:50:01 +0100 Subject: ALSA: hda - Fix click noises on Samsung Ativ Book 8 The Samsung Ativ Book 8 makes a loud click noise on boot, shutdown and when the audio card enters or exits power saving states. All these noises disappear applying ALC269_FIXUP_NO_SHUTUP. In addition to that, fix the loud click noise that the laptop makes when inserting or removing the headphone jack by automuting via amp instead of pinctl. Signed-off-by: Gabriele Mazzotta Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 937c2bbe8b50..1ae29fd7a78b 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4856,6 +4856,7 @@ enum { ALC292_FIXUP_TPT460, ALC298_FIXUP_SPK_VOLUME, ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER, + ALC269_FIXUP_ATIV_BOOK_8, }; static const struct hda_fixup alc269_fixups[] = { @@ -5528,6 +5529,12 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE }, + [ALC269_FIXUP_ATIV_BOOK_8] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_auto_mute_via_amp, + .chained = true, + .chain_id = ALC269_FIXUP_NO_SHUTUP + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -5664,6 +5671,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { 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(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC), + SND_PCI_QUIRK(0x144d, 0xc740, "Samsung Ativ book 8 (NP870Z5G)", ALC269_FIXUP_ATIV_BOOK_8), 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(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE), -- cgit v1.2.3 From 03abd33a11e3598dffbc821b2826ffc5fb6e980f Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 3 Jan 2017 11:36:08 +0900 Subject: ALSA: oxfw: add support for Mackie Onyx 1640i As of kernel 4.10, ALSA OXFW driver has no entry for Onyx 1640i produced by Mackie (Loud Technologies). This commit supplement it. I note that there're two models produced by Mackie (Loud Technologies), which have the same name 'Onyx 1640i'. The former model based on OXFW970, the latter model based on Dice. This is probably due to low quality of communication of OXFW series. Additionally, the tester reports his or her experiences to get unexpected result at higher sampling transmission frequency as 88.2/96.0 kHz. We didn't have further investigation yet[0]. $ ./linux-firewire-utils/src/crpp < config_rom ROM header and bus information block ----------------------------------------------------------------- 400 042525ce bus_info_length 4, crc_length 37, crc 9678 404 31333934 bus_name "1394" 408 20ff5003 irmc 0, cmc 0, isc 1, bmc 0, cyc_clk_acc 255, max_rec 5 (64) 40c 000ff205 company_id 000ff2 | 410 00000fcf device_id 0500000fcf | EUI-64 000ff20500000fcf root directory ----------------------------------------------------------------- 414 0006c1b7 directory_length 6, crc 49591 418 03000ff2 vendor 41c 8100000a --> descriptor leaf at 444 420 17001640 model 424 81000011 --> descriptor leaf at 468 428 0c0083c0 node capabilities per IEEE 1394 42c d1000001 --> unit directory at 430 unit directory at 430 ----------------------------------------------------------------- 430 00040b97 directory_length 4, crc 2967 434 1200a02d specifier id: 1394 TA 438 13010001 version: AV/C 43c 17001640 model 440 81000010 --> descriptor leaf at 480 descriptor leaf at 444 ----------------------------------------------------------------- 444 0008a886 leaf_length 8, crc 43142 448 00000000 textual descriptor 44c 00000000 minimal ASCII 450 4c6f7564 "Loud" 454 20546563 " Tec" 458 686e6f6c "hnol" 45c 6f676965 "ogie" 460 7320496e "s In" 464 632e0000 "c." descriptor leaf at 468 ----------------------------------------------------------------- 468 00059fcf leaf_length 5, crc 40911 46c 00000000 textual descriptor 470 00000000 minimal ASCII 474 4f6e7978 "Onyx" 478 20313634 " 164" 47c 30690000 "0i" descriptor leaf at 480 ----------------------------------------------------------------- 480 00059fcf leaf_length 5, crc 40911 484 00000000 textual descriptor 488 00000000 minimal ASCII 48c 4f6e7978 "Onyx" 490 20313634 " 164" 494 30690000 "0i" [0]: [FFADO-user] Mackie 1640i issues (finer details) https://sourceforge.net/p/ffado/mailman/message/35229260/ Tested-by: Seth O'Bannion Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/Kconfig | 1 + sound/firewire/oxfw/oxfw.c | 1 + 2 files changed, 2 insertions(+) diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig index ab894ed1ff67..9f00696c4e4a 100644 --- a/sound/firewire/Kconfig +++ b/sound/firewire/Kconfig @@ -34,6 +34,7 @@ config SND_OXFW * LaCie Firewire Speakers * Behringer F-Control Audio 202 * Mackie(Loud) Onyx-i series (former models) + * Mackie(Loud) Onyx 1640i (former model) * Mackie(Loud) Onyx Satellite * Mackie(Loud) Tapco Link.Firewire * Mackie(Loud) d.2 pro/d.4 pro diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index e629b88f7d93..74d7fb6efce6 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -43,6 +43,7 @@ static bool detect_loud_models(struct fw_unit *unit) const char *const models[] = { "Onyxi", "Onyx-i", + "Onyx 1640i", "d.Pro", "Mackie Onyx Satellite", "Tapco LINK.firewire 4x6", -- cgit v1.2.3 From b0e159fe34f76abf4ae23a6c799f43b8c520695b Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 3 Jan 2017 12:44:43 +0900 Subject: ALSA: dice: ensure transmission speed for transmitted packets As of kernel 4.10, ALSA dice driver is expected to be used in default speed. In most cases, it's S400. While, IEEE 1394 specification describes the other speed such as S800. According to 'TCD30XX User Guide', its link layer controller supports several transmission speed up to S800[0]. In Dice software interface, transmission speed in output direction can be configured by asynchronous transaction to 'TX_SPEED' offset in its address space. S800 may be available. This commit improves configuration of transmission unit before starting packet streaming for this purpose. The value of 'max_speed' in 'fw_device' data structure has available maximum speed decided in bus arbitration, thus it's within capacity of the unit. [0] TCD3xx User Guide - TCAT 1394 LLC, Revision 0.9.0-41360 (TC Applied Technologies, May 6 2015) http://www.tctechnologies.tc/index.php/support/support-hardware/dice-iii-detailed-documentation Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/dice/dice-interface.h | 1 + sound/firewire/dice/dice-stream.c | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/sound/firewire/dice/dice-interface.h b/sound/firewire/dice/dice-interface.h index 27b044f84c81..47f2c0a6f5d9 100644 --- a/sound/firewire/dice/dice-interface.h +++ b/sound/firewire/dice/dice-interface.h @@ -251,6 +251,7 @@ /* * The speed at which the packets are sent, SCODE_100-_400; read/write. + * SCODE_800 is only available in Dice III. */ #define TX_SPEED 0x014 diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index ec4db3a514fc..8573289c381e 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c @@ -195,6 +195,7 @@ static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir, unsigned int i, pcm_chs, midi_ports; struct amdtp_stream *streams; struct fw_iso_resources *resources; + struct fw_device *fw_dev = fw_parent_device(dice->unit); int err = 0; if (dir == AMDTP_IN_STREAM) { @@ -237,8 +238,17 @@ static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir, if (err < 0) return err; + if (dir == AMDTP_IN_STREAM) { + reg[0] = cpu_to_be32(fw_dev->max_speed); + err = snd_dice_transaction_write_tx(dice, + params->size * i + TX_SPEED, + reg, sizeof(reg[0])); + if (err < 0) + return err; + } + err = amdtp_stream_start(&streams[i], resources[i].channel, - fw_parent_device(dice->unit)->max_speed); + fw_dev->max_speed); if (err < 0) return err; } -- cgit v1.2.3 From 28f1f9b26cee161ddd3985b3eb78e3ffada08dda Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Wed, 4 Jan 2017 14:49:07 +0800 Subject: ALSA: hda/realtek - Add new codec ID ALC299 ALC299 was similar as ALC225. Add headset support for ALC299. ALC3271 was for Dell rename. Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 1ae29fd7a78b..3c6964793206 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -337,6 +337,7 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) case 0x10ec0288: case 0x10ec0295: case 0x10ec0298: + case 0x10ec0299: alc_update_coef_idx(codec, 0x10, 1<<9, 0); break; case 0x10ec0285: @@ -912,6 +913,7 @@ static struct alc_codec_rename_pci_table rename_pci_tbl[] = { { 0x10ec0256, 0x1028, 0, "ALC3246" }, { 0x10ec0225, 0x1028, 0, "ALC3253" }, { 0x10ec0295, 0x1028, 0, "ALC3254" }, + { 0x10ec0299, 0x1028, 0, "ALC3271" }, { 0x10ec0670, 0x1025, 0, "ALC669X" }, { 0x10ec0676, 0x1025, 0, "ALC679X" }, { 0x10ec0282, 0x1043, 0, "ALC3229" }, @@ -3716,6 +3718,7 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) break; case 0x10ec0225: case 0x10ec0295: + case 0x10ec0299: alc_process_coef_fw(codec, coef0225); break; case 0x10ec0867: @@ -3823,6 +3826,7 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, break; case 0x10ec0225: case 0x10ec0295: + case 0x10ec0299: alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x31<<10); snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); alc_process_coef_fw(codec, coef0225); @@ -3881,6 +3885,7 @@ static void alc_headset_mode_default(struct hda_codec *codec) switch (codec->core.vendor_id) { case 0x10ec0225: case 0x10ec0295: + case 0x10ec0299: alc_process_coef_fw(codec, coef0225); break; case 0x10ec0255: @@ -3996,6 +4001,7 @@ static void alc_headset_mode_ctia(struct hda_codec *codec) break; case 0x10ec0225: case 0x10ec0295: + case 0x10ec0299: alc_process_coef_fw(codec, coef0225); break; case 0x10ec0867: @@ -4089,6 +4095,7 @@ static void alc_headset_mode_omtp(struct hda_codec *codec) break; case 0x10ec0225: case 0x10ec0295: + case 0x10ec0299: alc_process_coef_fw(codec, coef0225); break; } @@ -4173,6 +4180,7 @@ static void alc_determine_headset_type(struct hda_codec *codec) break; case 0x10ec0225: case 0x10ec0295: + case 0x10ec0299: alc_process_coef_fw(codec, coef0225); msleep(800); val = alc_read_coef_idx(codec, 0x46); @@ -6219,6 +6227,7 @@ static int patch_alc269(struct hda_codec *codec) break; case 0x10ec0225: case 0x10ec0295: + case 0x10ec0299: spec->codec_variant = ALC269_TYPE_ALC225; break; case 0x10ec0234: @@ -7256,6 +7265,7 @@ static const struct hda_device_id snd_hda_id_realtek[] = { HDA_CODEC_ENTRY(0x10ec0294, "ALC294", patch_alc269), HDA_CODEC_ENTRY(0x10ec0295, "ALC295", patch_alc269), HDA_CODEC_ENTRY(0x10ec0298, "ALC298", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0299, "ALC299", patch_alc269), HDA_CODEC_REV_ENTRY(0x10ec0861, 0x100340, "ALC660", patch_alc861), HDA_CODEC_ENTRY(0x10ec0660, "ALC660-VD", patch_alc861vd), HDA_CODEC_ENTRY(0x10ec0861, "ALC861", patch_alc861), -- cgit v1.2.3 From ab949d519601880fd46e8bc1445d6a453bf2dc09 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 2 Jan 2017 11:37:04 +0100 Subject: ALSA: hda - Fix deadlock of controller device lock at unbinding Imre Deak reported a deadlock of HD-audio driver at unbinding while it's still in probing. Since we probe the codecs asynchronously in a work, the codec driver probe may still be kicked off while the controller itself is being unbound. And, azx_remove() tries to process all pending tasks via cancel_work_sync() for fixing the other races (see commit [0b8c82190c12: ALSA: hda - Cancel probe work instead of flush at remove]), now we may meet a bizarre deadlock: Unbind snd_hda_intel via sysfs: device_release_driver() -> device_lock(snd_hda_intel) -> azx_remove() -> cancel_work_sync(azx_probe_work) azx_probe_work(): codec driver probe() -> __driver_attach() -> device_lock(snd_hda_intel) This deadlock is caused by the fact that both device_release_driver() and driver_probe_device() take both the device and its parent locks at the same time. The codec device sets the controller device as its parent, and this lock is taken before the probe() callback is called, while the controller remove() callback gets called also with the same lock. In this patch, as an ugly workaround, we unlock the controller device temporarily during cancel_work_sync() call. The race against another bind call should be still suppressed by the parent's device lock. Reported-by: Imre Deak Fixes: 0b8c82190c12 ("ALSA: hda - Cancel probe work instead of flush at remove") Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index c64d986009a9..2587c197e353 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2155,7 +2155,20 @@ static void azx_remove(struct pci_dev *pci) /* cancel the pending probing work */ chip = card->private_data; hda = container_of(chip, struct hda_intel, chip); + /* FIXME: below is an ugly workaround. + * Both device_release_driver() and driver_probe_device() + * take *both* the device's and its parent's lock before + * calling the remove() and probe() callbacks. The codec + * probe takes the locks of both the codec itself and its + * parent, i.e. the PCI controller dev. Meanwhile, when + * the PCI controller is unbound, it takes its lock, too + * ==> ouch, a deadlock! + * As a workaround, we unlock temporarily here the controller + * device during cancel_work_sync() call. + */ + device_unlock(&pci->dev); cancel_work_sync(&hda->probe_work); + device_lock(&pci->dev); snd_card_free(card); } -- cgit v1.2.3 From 874e1f6fad9a5184b67f4cee37c1335cd2cc5677 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 4 Jan 2017 12:19:15 +0100 Subject: ALSA: vx: Fix possible transfer overflow The pseudo DMA transfer codes in VX222 and VX-pocket driver have a slight bug where they check the buffer boundary wrongly, and may overflow. Also, the zero sample count might be handled badly for the playback (although it shouldn't happen in theory). This patch addresses these issues. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=141541 Signed-off-by: Takashi Iwai --- sound/drivers/vx/vx_pcm.c | 6 ++++-- sound/pci/vx222/vx222_ops.c | 12 ++++++------ sound/pcmcia/vx/vxp_ops.c | 12 ++++++------ 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c index 11467272089e..41a617886cc7 100644 --- a/sound/drivers/vx/vx_pcm.c +++ b/sound/drivers/vx/vx_pcm.c @@ -1048,8 +1048,10 @@ static void vx_pcm_capture_update(struct vx_core *chip, struct snd_pcm_substream /* ok, let's accelerate! */ int align = pipe->align * 3; space = (count / align) * align; - vx_pseudo_dma_read(chip, runtime, pipe, space); - count -= space; + if (space > 0) { + vx_pseudo_dma_read(chip, runtime, pipe, space); + count -= space; + } } /* read the rest of bytes */ while (count > 0) { diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c index af83b3b38052..8e457ea27f89 100644 --- a/sound/pci/vx222/vx222_ops.c +++ b/sound/pci/vx222/vx222_ops.c @@ -269,12 +269,12 @@ static void vx2_dma_write(struct vx_core *chip, struct snd_pcm_runtime *runtime, /* Transfer using pseudo-dma. */ - if (offset + count > pipe->buffer_bytes) { + if (offset + count >= pipe->buffer_bytes) { int length = pipe->buffer_bytes - offset; count -= length; length >>= 2; /* in 32bit words */ /* Transfer using pseudo-dma. */ - while (length-- > 0) { + for (; length > 0; length--) { outl(cpu_to_le32(*addr), port); addr++; } @@ -284,7 +284,7 @@ static void vx2_dma_write(struct vx_core *chip, struct snd_pcm_runtime *runtime, pipe->hw_ptr += count; count >>= 2; /* in 32bit words */ /* Transfer using pseudo-dma. */ - while (count-- > 0) { + for (; count > 0; count--) { outl(cpu_to_le32(*addr), port); addr++; } @@ -307,12 +307,12 @@ static void vx2_dma_read(struct vx_core *chip, struct snd_pcm_runtime *runtime, vx2_setup_pseudo_dma(chip, 0); /* Transfer using pseudo-dma. */ - if (offset + count > pipe->buffer_bytes) { + if (offset + count >= pipe->buffer_bytes) { int length = pipe->buffer_bytes - offset; count -= length; length >>= 2; /* in 32bit words */ /* Transfer using pseudo-dma. */ - while (length-- > 0) + for (; length > 0; length--) *addr++ = le32_to_cpu(inl(port)); addr = (u32 *)runtime->dma_area; pipe->hw_ptr = 0; @@ -320,7 +320,7 @@ static void vx2_dma_read(struct vx_core *chip, struct snd_pcm_runtime *runtime, pipe->hw_ptr += count; count >>= 2; /* in 32bit words */ /* Transfer using pseudo-dma. */ - while (count-- > 0) + for (; count > 0; count--) *addr++ = le32_to_cpu(inl(port)); vx2_release_pseudo_dma(chip); diff --git a/sound/pcmcia/vx/vxp_ops.c b/sound/pcmcia/vx/vxp_ops.c index 281972913c32..56aa1ba73ccc 100644 --- a/sound/pcmcia/vx/vxp_ops.c +++ b/sound/pcmcia/vx/vxp_ops.c @@ -369,12 +369,12 @@ static void vxp_dma_write(struct vx_core *chip, struct snd_pcm_runtime *runtime, unsigned short *addr = (unsigned short *)(runtime->dma_area + offset); vx_setup_pseudo_dma(chip, 1); - if (offset + count > pipe->buffer_bytes) { + if (offset + count >= pipe->buffer_bytes) { int length = pipe->buffer_bytes - offset; count -= length; length >>= 1; /* in 16bit words */ /* Transfer using pseudo-dma. */ - while (length-- > 0) { + for (; length > 0; length--) { outw(cpu_to_le16(*addr), port); addr++; } @@ -384,7 +384,7 @@ static void vxp_dma_write(struct vx_core *chip, struct snd_pcm_runtime *runtime, pipe->hw_ptr += count; count >>= 1; /* in 16bit words */ /* Transfer using pseudo-dma. */ - while (count-- > 0) { + for (; count > 0; count--) { outw(cpu_to_le16(*addr), port); addr++; } @@ -411,12 +411,12 @@ static void vxp_dma_read(struct vx_core *chip, struct snd_pcm_runtime *runtime, if (snd_BUG_ON(count % 2)) return; vx_setup_pseudo_dma(chip, 0); - if (offset + count > pipe->buffer_bytes) { + if (offset + count >= pipe->buffer_bytes) { int length = pipe->buffer_bytes - offset; count -= length; length >>= 1; /* in 16bit words */ /* Transfer using pseudo-dma. */ - while (length-- > 0) + for (; length > 0; length--) *addr++ = le16_to_cpu(inw(port)); addr = (unsigned short *)runtime->dma_area; pipe->hw_ptr = 0; @@ -424,7 +424,7 @@ static void vxp_dma_read(struct vx_core *chip, struct snd_pcm_runtime *runtime, pipe->hw_ptr += count; count >>= 1; /* in 16bit words */ /* Transfer using pseudo-dma. */ - while (count-- > 1) + for (; count > 1; count--) *addr++ = le16_to_cpu(inw(port)); /* Disable DMA */ pchip->regDIALOG &= ~VXP_DLG_DMAREAD_SEL_MASK; -- cgit v1.2.3 From ed3c177d960bb5881b945ca6f784868126bb90db Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 4 Jan 2017 12:34:14 +0100 Subject: ALSA: vx: Don't try to update capture stream before running The update of stream costs significantly, and we should avoid it unless the stream really has started. Check pipe->running flag instead of pipe->prepared. Signed-off-by: Takashi Iwai --- sound/drivers/vx/vx_pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c index 41a617886cc7..ea7b377f0378 100644 --- a/sound/drivers/vx/vx_pcm.c +++ b/sound/drivers/vx/vx_pcm.c @@ -1015,7 +1015,7 @@ static void vx_pcm_capture_update(struct vx_core *chip, struct snd_pcm_substream int size, space, count; struct snd_pcm_runtime *runtime = subs->runtime; - if (! pipe->prepared || (chip->chip_status & VX_STAT_IS_STALE)) + if (!pipe->running || (chip->chip_status & VX_STAT_IS_STALE)) return; size = runtime->buffer_size - snd_pcm_capture_avail(runtime); -- cgit v1.2.3 From 4780f774f99129f1650d250e346d5bfba98d9f4f Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Thu, 5 Jan 2017 21:48:07 +0900 Subject: ALSA: bebob: enclose identifiers referred by single function Some identifiers are referred just by one functions. In this case, they can be put into the function definition. This brings two merits; readers can easily follow codes related to the identifiers, developers are free from name conflict. This commit moves such identifiers to each function definition. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob_hwdep.c | 17 ++++++------- sound/firewire/bebob/bebob_midi.c | 26 +++++++++---------- sound/firewire/bebob/bebob_pcm.c | 51 +++++++++++++++++++------------------- 3 files changed, 45 insertions(+), 49 deletions(-) diff --git a/sound/firewire/bebob/bebob_hwdep.c b/sound/firewire/bebob/bebob_hwdep.c index ce731f4d8b4f..2b367c21b80c 100644 --- a/sound/firewire/bebob/bebob_hwdep.c +++ b/sound/firewire/bebob/bebob_hwdep.c @@ -172,16 +172,15 @@ hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file, #define hwdep_compat_ioctl NULL #endif -static const struct snd_hwdep_ops hwdep_ops = { - .read = hwdep_read, - .release = hwdep_release, - .poll = hwdep_poll, - .ioctl = hwdep_ioctl, - .ioctl_compat = hwdep_compat_ioctl, -}; - int snd_bebob_create_hwdep_device(struct snd_bebob *bebob) { + static const struct snd_hwdep_ops ops = { + .read = hwdep_read, + .release = hwdep_release, + .poll = hwdep_poll, + .ioctl = hwdep_ioctl, + .ioctl_compat = hwdep_compat_ioctl, + }; struct snd_hwdep *hwdep; int err; @@ -190,7 +189,7 @@ int snd_bebob_create_hwdep_device(struct snd_bebob *bebob) goto end; strcpy(hwdep->name, "BeBoB"); hwdep->iface = SNDRV_HWDEP_IFACE_FW_BEBOB; - hwdep->ops = hwdep_ops; + hwdep->ops = ops; hwdep->private_data = bebob; hwdep->exclusive = true; end: diff --git a/sound/firewire/bebob/bebob_midi.c b/sound/firewire/bebob/bebob_midi.c index 868eb0decbec..7e5fb4b990bd 100644 --- a/sound/firewire/bebob/bebob_midi.c +++ b/sound/firewire/bebob/bebob_midi.c @@ -106,18 +106,6 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up) spin_unlock_irqrestore(&bebob->lock, flags); } -static struct snd_rawmidi_ops midi_capture_ops = { - .open = midi_capture_open, - .close = midi_capture_close, - .trigger = midi_capture_trigger, -}; - -static struct snd_rawmidi_ops midi_playback_ops = { - .open = midi_playback_open, - .close = midi_playback_close, - .trigger = midi_playback_trigger, -}; - static void set_midi_substream_names(struct snd_bebob *bebob, struct snd_rawmidi_str *str) { @@ -132,6 +120,16 @@ static void set_midi_substream_names(struct snd_bebob *bebob, int snd_bebob_create_midi_devices(struct snd_bebob *bebob) { + static struct snd_rawmidi_ops capture_ops = { + .open = midi_capture_open, + .close = midi_capture_close, + .trigger = midi_capture_trigger, + }; + static struct snd_rawmidi_ops playback_ops = { + .open = midi_playback_open, + .close = midi_playback_close, + .trigger = midi_playback_trigger, + }; struct snd_rawmidi *rmidi; struct snd_rawmidi_str *str; int err; @@ -151,7 +149,7 @@ int snd_bebob_create_midi_devices(struct snd_bebob *bebob) rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT; snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, - &midi_capture_ops); + &capture_ops); str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]; @@ -162,7 +160,7 @@ int snd_bebob_create_midi_devices(struct snd_bebob *bebob) rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT; snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, - &midi_playback_ops); + &playback_ops); str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]; diff --git a/sound/firewire/bebob/bebob_pcm.c b/sound/firewire/bebob/bebob_pcm.c index 5d7b9343fa85..9e27eb8e1dd4 100644 --- a/sound/firewire/bebob/bebob_pcm.c +++ b/sound/firewire/bebob/bebob_pcm.c @@ -359,32 +359,31 @@ pcm_playback_pointer(struct snd_pcm_substream *sbstrm) return amdtp_stream_pcm_pointer(&bebob->rx_stream); } -static const struct snd_pcm_ops pcm_capture_ops = { - .open = pcm_open, - .close = pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = pcm_capture_hw_params, - .hw_free = pcm_capture_hw_free, - .prepare = pcm_capture_prepare, - .trigger = pcm_capture_trigger, - .pointer = pcm_capture_pointer, - .page = snd_pcm_lib_get_vmalloc_page, -}; -static const struct snd_pcm_ops pcm_playback_ops = { - .open = pcm_open, - .close = pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = pcm_playback_hw_params, - .hw_free = pcm_playback_hw_free, - .prepare = pcm_playback_prepare, - .trigger = pcm_playback_trigger, - .pointer = pcm_playback_pointer, - .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, -}; - int snd_bebob_create_pcm_devices(struct snd_bebob *bebob) { + static const struct snd_pcm_ops capture_ops = { + .open = pcm_open, + .close = pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = pcm_capture_hw_params, + .hw_free = pcm_capture_hw_free, + .prepare = pcm_capture_prepare, + .trigger = pcm_capture_trigger, + .pointer = pcm_capture_pointer, + .page = snd_pcm_lib_get_vmalloc_page, + }; + static const struct snd_pcm_ops playback_ops = { + .open = pcm_open, + .close = pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = pcm_playback_hw_params, + .hw_free = pcm_playback_hw_free, + .prepare = pcm_playback_prepare, + .trigger = pcm_playback_trigger, + .pointer = pcm_playback_pointer, + .page = snd_pcm_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, + }; struct snd_pcm *pcm; int err; @@ -395,8 +394,8 @@ int snd_bebob_create_pcm_devices(struct snd_bebob *bebob) pcm->private_data = bebob; snprintf(pcm->name, sizeof(pcm->name), "%s PCM", bebob->card->shortname); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_playback_ops); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops); end: return err; } -- cgit v1.2.3 From 7cdc887a00d79a1553009eb7afd308882e4b74d5 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Thu, 5 Jan 2017 21:48:08 +0900 Subject: ALSA: fireworks: enclose identifiers referred by single function Some identifiers are referred just by one functions. In this case, they can be put into the function definition. This brings two merits; readers can easily follow codes related to the identifiers, developers are free from name conflict. This commit moves such identifiers to each function definition. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireworks/fireworks_hwdep.c | 19 ++++++----- sound/firewire/fireworks/fireworks_midi.c | 26 +++++++-------- sound/firewire/fireworks/fireworks_pcm.c | 52 ++++++++++++++---------------- 3 files changed, 46 insertions(+), 51 deletions(-) diff --git a/sound/firewire/fireworks/fireworks_hwdep.c b/sound/firewire/fireworks/fireworks_hwdep.c index 2e1d9a23920c..a3a3a16f5e08 100644 --- a/sound/firewire/fireworks/fireworks_hwdep.c +++ b/sound/firewire/fireworks/fireworks_hwdep.c @@ -303,17 +303,16 @@ hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file, #define hwdep_compat_ioctl NULL #endif -static const struct snd_hwdep_ops hwdep_ops = { - .read = hwdep_read, - .write = hwdep_write, - .release = hwdep_release, - .poll = hwdep_poll, - .ioctl = hwdep_ioctl, - .ioctl_compat = hwdep_compat_ioctl, -}; - int snd_efw_create_hwdep_device(struct snd_efw *efw) { + static const struct snd_hwdep_ops ops = { + .read = hwdep_read, + .write = hwdep_write, + .release = hwdep_release, + .poll = hwdep_poll, + .ioctl = hwdep_ioctl, + .ioctl_compat = hwdep_compat_ioctl, + }; struct snd_hwdep *hwdep; int err; @@ -322,7 +321,7 @@ int snd_efw_create_hwdep_device(struct snd_efw *efw) goto end; strcpy(hwdep->name, "Fireworks"); hwdep->iface = SNDRV_HWDEP_IFACE_FW_FIREWORKS; - hwdep->ops = hwdep_ops; + hwdep->ops = ops; hwdep->private_data = efw; hwdep->exclusive = true; end: diff --git a/sound/firewire/fireworks/fireworks_midi.c b/sound/firewire/fireworks/fireworks_midi.c index 3e8c4cf9fe1e..2873eca22bfc 100644 --- a/sound/firewire/fireworks/fireworks_midi.c +++ b/sound/firewire/fireworks/fireworks_midi.c @@ -107,18 +107,6 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up) spin_unlock_irqrestore(&efw->lock, flags); } -static struct snd_rawmidi_ops midi_capture_ops = { - .open = midi_capture_open, - .close = midi_capture_close, - .trigger = midi_capture_trigger, -}; - -static struct snd_rawmidi_ops midi_playback_ops = { - .open = midi_playback_open, - .close = midi_playback_close, - .trigger = midi_playback_trigger, -}; - static void set_midi_substream_names(struct snd_efw *efw, struct snd_rawmidi_str *str) { @@ -132,6 +120,16 @@ static void set_midi_substream_names(struct snd_efw *efw, int snd_efw_create_midi_devices(struct snd_efw *efw) { + static struct snd_rawmidi_ops capture_ops = { + .open = midi_capture_open, + .close = midi_capture_close, + .trigger = midi_capture_trigger, + }; + static struct snd_rawmidi_ops playback_ops = { + .open = midi_playback_open, + .close = midi_playback_close, + .trigger = midi_playback_trigger, + }; struct snd_rawmidi *rmidi; struct snd_rawmidi_str *str; int err; @@ -151,7 +149,7 @@ int snd_efw_create_midi_devices(struct snd_efw *efw) rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT; snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, - &midi_capture_ops); + &capture_ops); str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]; @@ -162,7 +160,7 @@ int snd_efw_create_midi_devices(struct snd_efw *efw) rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT; snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, - &midi_playback_ops); + &playback_ops); str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]; diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c index f4fbf75ed198..9171702f7d0b 100644 --- a/sound/firewire/fireworks/fireworks_pcm.c +++ b/sound/firewire/fireworks/fireworks_pcm.c @@ -383,33 +383,31 @@ static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm) return amdtp_stream_pcm_pointer(&efw->rx_stream); } -static const struct snd_pcm_ops pcm_capture_ops = { - .open = pcm_open, - .close = pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = pcm_capture_hw_params, - .hw_free = pcm_capture_hw_free, - .prepare = pcm_capture_prepare, - .trigger = pcm_capture_trigger, - .pointer = pcm_capture_pointer, - .page = snd_pcm_lib_get_vmalloc_page, -}; - -static const struct snd_pcm_ops pcm_playback_ops = { - .open = pcm_open, - .close = pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = pcm_playback_hw_params, - .hw_free = pcm_playback_hw_free, - .prepare = pcm_playback_prepare, - .trigger = pcm_playback_trigger, - .pointer = pcm_playback_pointer, - .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, -}; - int snd_efw_create_pcm_devices(struct snd_efw *efw) { + static const struct snd_pcm_ops capture_ops = { + .open = pcm_open, + .close = pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = pcm_capture_hw_params, + .hw_free = pcm_capture_hw_free, + .prepare = pcm_capture_prepare, + .trigger = pcm_capture_trigger, + .pointer = pcm_capture_pointer, + .page = snd_pcm_lib_get_vmalloc_page, + }; + static const struct snd_pcm_ops playback_ops = { + .open = pcm_open, + .close = pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = pcm_playback_hw_params, + .hw_free = pcm_playback_hw_free, + .prepare = pcm_playback_prepare, + .trigger = pcm_playback_trigger, + .pointer = pcm_playback_pointer, + .page = snd_pcm_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, + }; struct snd_pcm *pcm; int err; @@ -419,8 +417,8 @@ int snd_efw_create_pcm_devices(struct snd_efw *efw) pcm->private_data = efw; snprintf(pcm->name, sizeof(pcm->name), "%s PCM", efw->card->shortname); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_playback_ops); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops); end: return err; } -- cgit v1.2.3 From 39feaf2d0a2e1844a7d4c26ac1fac66176a15515 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Thu, 5 Jan 2017 21:48:09 +0900 Subject: ALSA: oxfw: enclose identifiers referred by single function Some identifiers are referred just by one functions. In this case, they can be put into the function definition. This brings two merits; readers can easily follow codes related to the identifiers, developers are free from name conflict. This commit moves such identifiers to each function definition. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/oxfw/oxfw-midi.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/sound/firewire/oxfw/oxfw-midi.c b/sound/firewire/oxfw/oxfw-midi.c index 8665e1043d41..076a1a977275 100644 --- a/sound/firewire/oxfw/oxfw-midi.c +++ b/sound/firewire/oxfw/oxfw-midi.c @@ -116,18 +116,6 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up) spin_unlock_irqrestore(&oxfw->lock, flags); } -static struct snd_rawmidi_ops midi_capture_ops = { - .open = midi_capture_open, - .close = midi_capture_close, - .trigger = midi_capture_trigger, -}; - -static struct snd_rawmidi_ops midi_playback_ops = { - .open = midi_playback_open, - .close = midi_playback_close, - .trigger = midi_playback_trigger, -}; - static void set_midi_substream_names(struct snd_oxfw *oxfw, struct snd_rawmidi_str *str) { @@ -142,6 +130,16 @@ static void set_midi_substream_names(struct snd_oxfw *oxfw, int snd_oxfw_create_midi(struct snd_oxfw *oxfw) { + static struct snd_rawmidi_ops capture_ops = { + .open = midi_capture_open, + .close = midi_capture_close, + .trigger = midi_capture_trigger, + }; + static struct snd_rawmidi_ops playback_ops = { + .open = midi_playback_open, + .close = midi_playback_close, + .trigger = midi_playback_trigger, + }; struct snd_rawmidi *rmidi; struct snd_rawmidi_str *str; int err; @@ -164,7 +162,7 @@ int snd_oxfw_create_midi(struct snd_oxfw *oxfw) rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT; snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, - &midi_capture_ops); + &capture_ops); str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]; @@ -175,7 +173,7 @@ int snd_oxfw_create_midi(struct snd_oxfw *oxfw) rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT; snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, - &midi_playback_ops); + &playback_ops); str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]; -- cgit v1.2.3 From fcbe08d469bd3778e691e3b0f156d51f8b1ba2e4 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Thu, 5 Jan 2017 21:48:10 +0900 Subject: ALSA: dice: enclose identifiers referred by single function Some identifiers are referred just by one functions. In this case, they can be put into the function definition. This brings two merits; readers can easily follow codes related to the identifiers, developers are free from name conflict. This commit moves such identifiers to each function definition. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/dice/dice-midi.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/sound/firewire/dice/dice-midi.c b/sound/firewire/dice/dice-midi.c index a040617505a7..cdf71c211342 100644 --- a/sound/firewire/dice/dice-midi.c +++ b/sound/firewire/dice/dice-midi.c @@ -78,18 +78,6 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up) spin_unlock_irqrestore(&dice->lock, flags); } -static struct snd_rawmidi_ops capture_ops = { - .open = midi_open, - .close = midi_close, - .trigger = midi_capture_trigger, -}; - -static struct snd_rawmidi_ops playback_ops = { - .open = midi_open, - .close = midi_close, - .trigger = midi_playback_trigger, -}; - static void set_midi_substream_names(struct snd_dice *dice, struct snd_rawmidi_str *str) { @@ -103,6 +91,16 @@ static void set_midi_substream_names(struct snd_dice *dice, int snd_dice_create_midi(struct snd_dice *dice) { + static struct snd_rawmidi_ops capture_ops = { + .open = midi_open, + .close = midi_close, + .trigger = midi_capture_trigger, + }; + static struct snd_rawmidi_ops playback_ops = { + .open = midi_open, + .close = midi_close, + .trigger = midi_playback_trigger, + }; __be32 reg; struct snd_rawmidi *rmidi; struct snd_rawmidi_str *str; -- cgit v1.2.3 From a4e86cba09c9e2bb64af018544a7aed4a6a1b538 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Thu, 5 Jan 2017 21:48:11 +0900 Subject: ALSA: firewire-digi00x: enclose identifiers referred by single function Some identifiers are referred just by one functions. In this case, they can be put into the function definition. This brings two merits; readers can easily follow codes related to the identifiers, developers are free from name conflict. This commit moves such identifiers to each function definition. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/digi00x/digi00x-hwdep.c | 17 ++++++----- sound/firewire/digi00x/digi00x-midi.c | 52 ++++++++++++++++------------------ sound/firewire/digi00x/digi00x-pcm.c | 52 ++++++++++++++++------------------ 3 files changed, 57 insertions(+), 64 deletions(-) diff --git a/sound/firewire/digi00x/digi00x-hwdep.c b/sound/firewire/digi00x/digi00x-hwdep.c index f188e4758fd2..463c6b8e864d 100644 --- a/sound/firewire/digi00x/digi00x-hwdep.c +++ b/sound/firewire/digi00x/digi00x-hwdep.c @@ -173,16 +173,15 @@ static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file, #define hwdep_compat_ioctl NULL #endif -static const struct snd_hwdep_ops hwdep_ops = { - .read = hwdep_read, - .release = hwdep_release, - .poll = hwdep_poll, - .ioctl = hwdep_ioctl, - .ioctl_compat = hwdep_compat_ioctl, -}; - int snd_dg00x_create_hwdep_device(struct snd_dg00x *dg00x) { + static const struct snd_hwdep_ops ops = { + .read = hwdep_read, + .release = hwdep_release, + .poll = hwdep_poll, + .ioctl = hwdep_ioctl, + .ioctl_compat = hwdep_compat_ioctl, + }; struct snd_hwdep *hwdep; int err; @@ -192,7 +191,7 @@ int snd_dg00x_create_hwdep_device(struct snd_dg00x *dg00x) strcpy(hwdep->name, "Digi00x"); hwdep->iface = SNDRV_HWDEP_IFACE_FW_DIGI00X; - hwdep->ops = hwdep_ops; + hwdep->ops = ops; hwdep->private_data = dg00x; hwdep->exclusive = true; diff --git a/sound/firewire/digi00x/digi00x-midi.c b/sound/firewire/digi00x/digi00x-midi.c index 1a72a382b384..8689c3bb4c6a 100644 --- a/sound/firewire/digi00x/digi00x-midi.c +++ b/sound/firewire/digi00x/digi00x-midi.c @@ -76,18 +76,6 @@ static void midi_phys_playback_trigger(struct snd_rawmidi_substream *substream, spin_unlock_irqrestore(&dg00x->lock, flags); } -static struct snd_rawmidi_ops midi_phys_capture_ops = { - .open = midi_phys_open, - .close = midi_phys_close, - .trigger = midi_phys_capture_trigger, -}; - -static struct snd_rawmidi_ops midi_phys_playback_ops = { - .open = midi_phys_open, - .close = midi_phys_close, - .trigger = midi_phys_playback_trigger, -}; - static int midi_ctl_open(struct snd_rawmidi_substream *substream) { /* Do nothing. */ @@ -139,18 +127,6 @@ static void midi_ctl_playback_trigger(struct snd_rawmidi_substream *substream, spin_unlock_irqrestore(&dg00x->lock, flags); } -static struct snd_rawmidi_ops midi_ctl_capture_ops = { - .open = midi_ctl_open, - .close = midi_ctl_capture_close, - .trigger = midi_ctl_capture_trigger, -}; - -static struct snd_rawmidi_ops midi_ctl_playback_ops = { - .open = midi_ctl_open, - .close = midi_ctl_playback_close, - .trigger = midi_ctl_playback_trigger, -}; - static void set_midi_substream_names(struct snd_dg00x *dg00x, struct snd_rawmidi_str *str, bool is_ctl) @@ -172,6 +148,26 @@ static void set_midi_substream_names(struct snd_dg00x *dg00x, int snd_dg00x_create_midi_devices(struct snd_dg00x *dg00x) { + static struct snd_rawmidi_ops phys_capture_ops = { + .open = midi_phys_open, + .close = midi_phys_close, + .trigger = midi_phys_capture_trigger, + }; + static struct snd_rawmidi_ops phys_playback_ops = { + .open = midi_phys_open, + .close = midi_phys_close, + .trigger = midi_phys_playback_trigger, + }; + static struct snd_rawmidi_ops ctl_capture_ops = { + .open = midi_ctl_open, + .close = midi_ctl_capture_close, + .trigger = midi_ctl_capture_trigger, + }; + static struct snd_rawmidi_ops ctl_playback_ops = { + .open = midi_ctl_open, + .close = midi_ctl_playback_close, + .trigger = midi_ctl_playback_trigger, + }; struct snd_rawmidi *rmidi[2]; struct snd_rawmidi_str *str; unsigned int i; @@ -187,9 +183,9 @@ int snd_dg00x_create_midi_devices(struct snd_dg00x *dg00x) "%s MIDI", dg00x->card->shortname); snd_rawmidi_set_ops(rmidi[0], SNDRV_RAWMIDI_STREAM_INPUT, - &midi_phys_capture_ops); + &phys_capture_ops); snd_rawmidi_set_ops(rmidi[0], SNDRV_RAWMIDI_STREAM_OUTPUT, - &midi_phys_playback_ops); + &phys_playback_ops); /* Add a pair of control midi ports. */ err = snd_rawmidi_new(dg00x->card, dg00x->card->driver, 1, @@ -201,9 +197,9 @@ int snd_dg00x_create_midi_devices(struct snd_dg00x *dg00x) "%s control", dg00x->card->shortname); snd_rawmidi_set_ops(rmidi[1], SNDRV_RAWMIDI_STREAM_INPUT, - &midi_ctl_capture_ops); + &ctl_capture_ops); snd_rawmidi_set_ops(rmidi[1], SNDRV_RAWMIDI_STREAM_OUTPUT, - &midi_ctl_playback_ops); + &ctl_playback_ops); for (i = 0; i < ARRAY_SIZE(rmidi); i++) { rmidi[i]->private_data = dg00x; diff --git a/sound/firewire/digi00x/digi00x-pcm.c b/sound/firewire/digi00x/digi00x-pcm.c index 613f05872770..68d1c52db051 100644 --- a/sound/firewire/digi00x/digi00x-pcm.c +++ b/sound/firewire/digi00x/digi00x-pcm.c @@ -329,33 +329,31 @@ static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm) return amdtp_stream_pcm_pointer(&dg00x->rx_stream); } -static const struct snd_pcm_ops pcm_capture_ops = { - .open = pcm_open, - .close = pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = pcm_capture_hw_params, - .hw_free = pcm_capture_hw_free, - .prepare = pcm_capture_prepare, - .trigger = pcm_capture_trigger, - .pointer = pcm_capture_pointer, - .page = snd_pcm_lib_get_vmalloc_page, -}; - -static const struct snd_pcm_ops pcm_playback_ops = { - .open = pcm_open, - .close = pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = pcm_playback_hw_params, - .hw_free = pcm_playback_hw_free, - .prepare = pcm_playback_prepare, - .trigger = pcm_playback_trigger, - .pointer = pcm_playback_pointer, - .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, -}; - int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x) { + static const struct snd_pcm_ops capture_ops = { + .open = pcm_open, + .close = pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = pcm_capture_hw_params, + .hw_free = pcm_capture_hw_free, + .prepare = pcm_capture_prepare, + .trigger = pcm_capture_trigger, + .pointer = pcm_capture_pointer, + .page = snd_pcm_lib_get_vmalloc_page, + }; + static const struct snd_pcm_ops playback_ops = { + .open = pcm_open, + .close = pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = pcm_playback_hw_params, + .hw_free = pcm_playback_hw_free, + .prepare = pcm_playback_prepare, + .trigger = pcm_playback_trigger, + .pointer = pcm_playback_pointer, + .page = snd_pcm_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, + }; struct snd_pcm *pcm; int err; @@ -366,8 +364,8 @@ int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x) pcm->private_data = dg00x; snprintf(pcm->name, sizeof(pcm->name), "%s PCM", dg00x->card->shortname); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_playback_ops); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops); return 0; } -- cgit v1.2.3 From 921282360b9c9bf34c75cd18bb90f298c4f4ebc8 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Thu, 5 Jan 2017 21:48:12 +0900 Subject: ALSA: firewire-tascam: enclose identifiers referred by single function Some identifiers are referred just by one functions. In this case, they can be put into the function definition. This brings two merits; readers can easily follow codes related to the identifiers, developers are free from name conflict. This commit moves such identifiers to each function definition. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/tascam/tascam-hwdep.c | 17 ++++++------ sound/firewire/tascam/tascam-midi.c | 26 +++++++++--------- sound/firewire/tascam/tascam-pcm.c | 52 +++++++++++++++++------------------- 3 files changed, 45 insertions(+), 50 deletions(-) diff --git a/sound/firewire/tascam/tascam-hwdep.c b/sound/firewire/tascam/tascam-hwdep.c index 106406cbfaa3..8c4437d0051d 100644 --- a/sound/firewire/tascam/tascam-hwdep.c +++ b/sound/firewire/tascam/tascam-hwdep.c @@ -163,16 +163,15 @@ static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file, #define hwdep_compat_ioctl NULL #endif -static const struct snd_hwdep_ops hwdep_ops = { - .read = hwdep_read, - .release = hwdep_release, - .poll = hwdep_poll, - .ioctl = hwdep_ioctl, - .ioctl_compat = hwdep_compat_ioctl, -}; - int snd_tscm_create_hwdep_device(struct snd_tscm *tscm) { + static const struct snd_hwdep_ops ops = { + .read = hwdep_read, + .release = hwdep_release, + .poll = hwdep_poll, + .ioctl = hwdep_ioctl, + .ioctl_compat = hwdep_compat_ioctl, + }; struct snd_hwdep *hwdep; int err; @@ -182,7 +181,7 @@ int snd_tscm_create_hwdep_device(struct snd_tscm *tscm) strcpy(hwdep->name, "Tascam"); hwdep->iface = SNDRV_HWDEP_IFACE_FW_TASCAM; - hwdep->ops = hwdep_ops; + hwdep->ops = ops; hwdep->private_data = tscm; hwdep->exclusive = true; diff --git a/sound/firewire/tascam/tascam-midi.c b/sound/firewire/tascam/tascam-midi.c index 41f842079d9d..7fdc71e4763e 100644 --- a/sound/firewire/tascam/tascam-midi.c +++ b/sound/firewire/tascam/tascam-midi.c @@ -68,20 +68,18 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up) spin_unlock_irqrestore(&tscm->lock, flags); } -static struct snd_rawmidi_ops midi_capture_ops = { - .open = midi_capture_open, - .close = midi_capture_close, - .trigger = midi_capture_trigger, -}; - -static struct snd_rawmidi_ops midi_playback_ops = { - .open = midi_playback_open, - .close = midi_playback_close, - .trigger = midi_playback_trigger, -}; - int snd_tscm_create_midi_devices(struct snd_tscm *tscm) { + static struct snd_rawmidi_ops capture_ops = { + .open = midi_capture_open, + .close = midi_capture_close, + .trigger = midi_capture_trigger, + }; + static struct snd_rawmidi_ops playback_ops = { + .open = midi_playback_open, + .close = midi_playback_close, + .trigger = midi_playback_trigger, + }; struct snd_rawmidi *rmidi; struct snd_rawmidi_str *stream; struct snd_rawmidi_substream *subs; @@ -100,7 +98,7 @@ int snd_tscm_create_midi_devices(struct snd_tscm *tscm) rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT; snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, - &midi_capture_ops); + &capture_ops); stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]; /* Set port names for MIDI input. */ @@ -116,7 +114,7 @@ int snd_tscm_create_midi_devices(struct snd_tscm *tscm) rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT; snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, - &midi_playback_ops); + &playback_ops); stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]; /* Set port names for MIDI ourput. */ diff --git a/sound/firewire/tascam/tascam-pcm.c b/sound/firewire/tascam/tascam-pcm.c index 79db1b651f5c..f5dd6ce6b6f1 100644 --- a/sound/firewire/tascam/tascam-pcm.c +++ b/sound/firewire/tascam/tascam-pcm.c @@ -268,33 +268,31 @@ static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm) return amdtp_stream_pcm_pointer(&tscm->rx_stream); } -static const struct snd_pcm_ops pcm_capture_ops = { - .open = pcm_open, - .close = pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = pcm_capture_hw_params, - .hw_free = pcm_capture_hw_free, - .prepare = pcm_capture_prepare, - .trigger = pcm_capture_trigger, - .pointer = pcm_capture_pointer, - .page = snd_pcm_lib_get_vmalloc_page, -}; - -static const struct snd_pcm_ops pcm_playback_ops = { - .open = pcm_open, - .close = pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = pcm_playback_hw_params, - .hw_free = pcm_playback_hw_free, - .prepare = pcm_playback_prepare, - .trigger = pcm_playback_trigger, - .pointer = pcm_playback_pointer, - .page = snd_pcm_lib_get_vmalloc_page, - .mmap = snd_pcm_lib_mmap_vmalloc, -}; - int snd_tscm_create_pcm_devices(struct snd_tscm *tscm) { + static const struct snd_pcm_ops capture_ops = { + .open = pcm_open, + .close = pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = pcm_capture_hw_params, + .hw_free = pcm_capture_hw_free, + .prepare = pcm_capture_prepare, + .trigger = pcm_capture_trigger, + .pointer = pcm_capture_pointer, + .page = snd_pcm_lib_get_vmalloc_page, + }; + static const struct snd_pcm_ops playback_ops = { + .open = pcm_open, + .close = pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = pcm_playback_hw_params, + .hw_free = pcm_playback_hw_free, + .prepare = pcm_playback_prepare, + .trigger = pcm_playback_trigger, + .pointer = pcm_playback_pointer, + .page = snd_pcm_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, + }; struct snd_pcm *pcm; int err; @@ -305,8 +303,8 @@ int snd_tscm_create_pcm_devices(struct snd_tscm *tscm) pcm->private_data = tscm; snprintf(pcm->name, sizeof(pcm->name), "%s PCM", tscm->card->shortname); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_playback_ops); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops); return 0; } -- cgit v1.2.3 From 46a049dae771b95e77ac6c823330f4a60f600236 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 11 Jan 2017 14:39:44 +0100 Subject: ALSA: hda/ca0132 - fix possible NULL pointer use gcc-7 caught what it considers a NULL pointer dereference: sound/pci/hda/patch_ca0132.c: In function 'dspio_scp.constprop': sound/pci/hda/patch_ca0132.c:1487:4: error: argument 1 null where non-null expected [-Werror=nonnull] This is plausible from looking at the function, as we compare 'reply' to NULL earlier in it. I have not tried to analyze if there are constraints that make it impossible to hit the bug, but adding another NULL check in the end kills the warning and makes the function more robust. Signed-off-by: Arnd Bergmann Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 11b9b2f17a2e..9ec4dba8a793 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -1482,6 +1482,9 @@ static int dspio_scp(struct hda_codec *codec, } else if (ret_size != reply_data_size) { codec_dbg(codec, "RetLen and HdrLen .NE.\n"); return -EINVAL; + } else if (!reply) { + codec_dbg(codec, "NULL reply\n"); + return -EINVAL; } else { *reply_len = ret_size*sizeof(unsigned int); memcpy(reply, scp_reply.data, *reply_len); -- cgit v1.2.3 From 6ba79b853289289052b4c4c2c68de4418cd8c57d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 5 Jan 2017 17:01:14 +0100 Subject: ALSA: rawmidi: Add const to snd_rawmidi_ops Make snd_rawmidi_substream.ops to be a const pointer to be safer and allow more optimization. The patches to constify each rawmidi ops will follow. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- include/sound/rawmidi.h | 4 ++-- sound/core/rawmidi.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h index f730b91e472f..492a3ca7f17b 100644 --- a/include/sound/rawmidi.h +++ b/include/sound/rawmidi.h @@ -103,7 +103,7 @@ struct snd_rawmidi_substream { struct snd_rawmidi_runtime *runtime; struct pid *pid; /* hardware layer */ - struct snd_rawmidi_ops *ops; + const struct snd_rawmidi_ops *ops; }; struct snd_rawmidi_file { @@ -155,7 +155,7 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device, int output_count, int input_count, struct snd_rawmidi **rmidi); void snd_rawmidi_set_ops(struct snd_rawmidi *rmidi, int stream, - struct snd_rawmidi_ops *ops); + const struct snd_rawmidi_ops *ops); /* callbacks */ diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 2096bb0835c8..8da9cb245d01 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -1749,7 +1749,7 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device) * Sets the rawmidi operators for the given stream direction. */ void snd_rawmidi_set_ops(struct snd_rawmidi *rmidi, int stream, - struct snd_rawmidi_ops *ops) + const struct snd_rawmidi_ops *ops) { struct snd_rawmidi_substream *substream; -- cgit v1.2.3 From c62a57004abd819d93772377ea6b4b4fe8412770 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 5 Jan 2017 17:27:17 +0100 Subject: ALSA: seq: Constify snd_rawmidi_ops Now snd_rawmidi_ops is maintained as a const pointer in snd_rawmidi, we can constify the definitions. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/core/seq/seq_virmidi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index c82ed3e70506..52f31f1498f9 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -349,13 +349,13 @@ static int snd_virmidi_unuse(void *private_data, * Register functions */ -static struct snd_rawmidi_ops snd_virmidi_input_ops = { +static const struct snd_rawmidi_ops snd_virmidi_input_ops = { .open = snd_virmidi_input_open, .close = snd_virmidi_input_close, .trigger = snd_virmidi_input_trigger, }; -static struct snd_rawmidi_ops snd_virmidi_output_ops = { +static const struct snd_rawmidi_ops snd_virmidi_output_ops = { .open = snd_virmidi_output_open, .close = snd_virmidi_output_close, .trigger = snd_virmidi_output_trigger, -- cgit v1.2.3 From c36f486d7bc71d41ec6b9521574136a280c17803 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 5 Jan 2017 17:28:39 +0100 Subject: ALSA: drivers: Constify snd_rawmidi_ops Now snd_rawmidi_ops is maintained as a const pointer in snd_rawmidi, we can constify the definitions. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/drivers/mpu401/mpu401_uart.c | 4 ++-- sound/drivers/mtpav.c | 4 ++-- sound/drivers/mts64.c | 4 ++-- sound/drivers/portman2x4.c | 4 ++-- sound/drivers/serial-u16550.c | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c index 776596b5ee05..3a7c317ae012 100644 --- a/sound/drivers/mpu401/mpu401_uart.c +++ b/sound/drivers/mpu401/mpu401_uart.c @@ -481,14 +481,14 @@ snd_mpu401_uart_output_trigger(struct snd_rawmidi_substream *substream, int up) */ -static struct snd_rawmidi_ops snd_mpu401_uart_output = +static const struct snd_rawmidi_ops snd_mpu401_uart_output = { .open = snd_mpu401_uart_output_open, .close = snd_mpu401_uart_output_close, .trigger = snd_mpu401_uart_output_trigger, }; -static struct snd_rawmidi_ops snd_mpu401_uart_input = +static const struct snd_rawmidi_ops snd_mpu401_uart_input = { .open = snd_mpu401_uart_input_open, .close = snd_mpu401_uart_input_close, diff --git a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c index 30e8a1d5bc87..00b31f92c504 100644 --- a/sound/drivers/mtpav.c +++ b/sound/drivers/mtpav.c @@ -600,13 +600,13 @@ static int snd_mtpav_get_ISA(struct mtpav *mcard) /* */ -static struct snd_rawmidi_ops snd_mtpav_output = { +static const struct snd_rawmidi_ops snd_mtpav_output = { .open = snd_mtpav_output_open, .close = snd_mtpav_output_close, .trigger = snd_mtpav_output_trigger, }; -static struct snd_rawmidi_ops snd_mtpav_input = { +static const struct snd_rawmidi_ops snd_mtpav_input = { .open = snd_mtpav_input_open, .close = snd_mtpav_input_close, .trigger = snd_mtpav_input_trigger, diff --git a/sound/drivers/mts64.c b/sound/drivers/mts64.c index fd4d18df84d3..f32e81342247 100644 --- a/sound/drivers/mts64.c +++ b/sound/drivers/mts64.c @@ -749,13 +749,13 @@ static void snd_mts64_rawmidi_input_trigger(struct snd_rawmidi_substream *substr spin_unlock_irqrestore(&mts->lock, flags); } -static struct snd_rawmidi_ops snd_mts64_rawmidi_output_ops = { +static const struct snd_rawmidi_ops snd_mts64_rawmidi_output_ops = { .open = snd_mts64_rawmidi_open, .close = snd_mts64_rawmidi_close, .trigger = snd_mts64_rawmidi_output_trigger }; -static struct snd_rawmidi_ops snd_mts64_rawmidi_input_ops = { +static const struct snd_rawmidi_ops snd_mts64_rawmidi_input_ops = { .open = snd_mts64_rawmidi_open, .close = snd_mts64_rawmidi_close, .trigger = snd_mts64_rawmidi_input_trigger diff --git a/sound/drivers/portman2x4.c b/sound/drivers/portman2x4.c index 189e3e7028af..ec8a94325ef6 100644 --- a/sound/drivers/portman2x4.c +++ b/sound/drivers/portman2x4.c @@ -546,13 +546,13 @@ static void snd_portman_midi_output_trigger(struct snd_rawmidi_substream *substr spin_unlock_irqrestore(&pm->reg_lock, flags); } -static struct snd_rawmidi_ops snd_portman_midi_output = { +static const struct snd_rawmidi_ops snd_portman_midi_output = { .open = snd_portman_midi_open, .close = snd_portman_midi_close, .trigger = snd_portman_midi_output_trigger, }; -static struct snd_rawmidi_ops snd_portman_midi_input = { +static const struct snd_rawmidi_ops snd_portman_midi_input = { .open = snd_portman_midi_open, .close = snd_portman_midi_close, .trigger = snd_portman_midi_input_trigger, diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c index 1927b89e1d1f..60d51ac4ccfe 100644 --- a/sound/drivers/serial-u16550.c +++ b/sound/drivers/serial-u16550.c @@ -752,14 +752,14 @@ static void snd_uart16550_output_trigger(struct snd_rawmidi_substream *substream snd_uart16550_output_write(substream); } -static struct snd_rawmidi_ops snd_uart16550_output = +static const struct snd_rawmidi_ops snd_uart16550_output = { .open = snd_uart16550_output_open, .close = snd_uart16550_output_close, .trigger = snd_uart16550_output_trigger, }; -static struct snd_rawmidi_ops snd_uart16550_input = +static const struct snd_rawmidi_ops snd_uart16550_input = { .open = snd_uart16550_input_open, .close = snd_uart16550_input_close, -- cgit v1.2.3 From 9021b2b8fd8f352abfc9470249eca9b36356a155 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 5 Jan 2017 17:29:07 +0100 Subject: ALSA: isa: Constify snd_rawmidi_ops Now snd_rawmidi_ops is maintained as a const pointer in snd_rawmidi, we can constify the definitions. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- include/sound/snd_wavefront.h | 4 ++-- sound/isa/gus/gus_uart.c | 4 ++-- sound/isa/msnd/msnd_midi.c | 2 +- sound/isa/sb/sb8_midi.c | 4 ++-- sound/isa/wavefront/wavefront_midi.c | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/sound/snd_wavefront.h b/include/sound/snd_wavefront.h index 35e94b3d1ec7..cd0bab1ef6f1 100644 --- a/include/sound/snd_wavefront.h +++ b/include/sound/snd_wavefront.h @@ -37,8 +37,8 @@ struct _snd_wavefront_midi { #define MPU_ACK 0xFE #define UART_MODE_ON 0x3F -extern struct snd_rawmidi_ops snd_wavefront_midi_output; -extern struct snd_rawmidi_ops snd_wavefront_midi_input; +extern const struct snd_rawmidi_ops snd_wavefront_midi_output; +extern const struct snd_rawmidi_ops snd_wavefront_midi_input; extern void snd_wavefront_midi_enable_virtual (snd_wavefront_card_t *); extern void snd_wavefront_midi_disable_virtual (snd_wavefront_card_t *); diff --git a/sound/isa/gus/gus_uart.c b/sound/isa/gus/gus_uart.c index 3992912743f5..ac5f5687d1a3 100644 --- a/sound/isa/gus/gus_uart.c +++ b/sound/isa/gus/gus_uart.c @@ -227,14 +227,14 @@ static void snd_gf1_uart_output_trigger(struct snd_rawmidi_substream *substream, spin_unlock_irqrestore(&gus->uart_cmd_lock, flags); } -static struct snd_rawmidi_ops snd_gf1_uart_output = +static const struct snd_rawmidi_ops snd_gf1_uart_output = { .open = snd_gf1_uart_output_open, .close = snd_gf1_uart_output_close, .trigger = snd_gf1_uart_output_trigger, }; -static struct snd_rawmidi_ops snd_gf1_uart_input = +static const struct snd_rawmidi_ops snd_gf1_uart_input = { .open = snd_gf1_uart_input_open, .close = snd_gf1_uart_input_close, diff --git a/sound/isa/msnd/msnd_midi.c b/sound/isa/msnd/msnd_midi.c index ffc67fd80c23..912b5a9ccbab 100644 --- a/sound/isa/msnd/msnd_midi.c +++ b/sound/isa/msnd/msnd_midi.c @@ -142,7 +142,7 @@ void snd_msndmidi_input_read(void *mpuv) } EXPORT_SYMBOL(snd_msndmidi_input_read); -static struct snd_rawmidi_ops snd_msndmidi_input = { +static const struct snd_rawmidi_ops snd_msndmidi_input = { .open = snd_msndmidi_input_open, .close = snd_msndmidi_input_close, .trigger = snd_msndmidi_input_trigger, diff --git a/sound/isa/sb/sb8_midi.c b/sound/isa/sb/sb8_midi.c index d551c50e549f..bd672abb4854 100644 --- a/sound/isa/sb/sb8_midi.c +++ b/sound/isa/sb/sb8_midi.c @@ -247,14 +247,14 @@ static void snd_sb8dsp_midi_output_trigger(struct snd_rawmidi_substream *substre snd_sb8dsp_midi_output_write(substream); } -static struct snd_rawmidi_ops snd_sb8dsp_midi_output = +static const struct snd_rawmidi_ops snd_sb8dsp_midi_output = { .open = snd_sb8dsp_midi_output_open, .close = snd_sb8dsp_midi_output_close, .trigger = snd_sb8dsp_midi_output_trigger, }; -static struct snd_rawmidi_ops snd_sb8dsp_midi_input = +static const struct snd_rawmidi_ops snd_sb8dsp_midi_input = { .open = snd_sb8dsp_midi_input_open, .close = snd_sb8dsp_midi_input_close, diff --git a/sound/isa/wavefront/wavefront_midi.c b/sound/isa/wavefront/wavefront_midi.c index 8a80fc6a616b..2aa05f3aaa38 100644 --- a/sound/isa/wavefront/wavefront_midi.c +++ b/sound/isa/wavefront/wavefront_midi.c @@ -559,14 +559,14 @@ snd_wavefront_midi_start (snd_wavefront_card_t *card) return 0; } -struct snd_rawmidi_ops snd_wavefront_midi_output = +const struct snd_rawmidi_ops snd_wavefront_midi_output = { .open = snd_wavefront_midi_output_open, .close = snd_wavefront_midi_output_close, .trigger = snd_wavefront_midi_output_trigger, }; -struct snd_rawmidi_ops snd_wavefront_midi_input = +const struct snd_rawmidi_ops snd_wavefront_midi_input = { .open = snd_wavefront_midi_input_open, .close = snd_wavefront_midi_input_close, -- cgit v1.2.3 From 485885b9d0474ac374297e637f479c22930bb593 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 5 Jan 2017 17:29:31 +0100 Subject: ALSA: pci: Constify snd_rawmidi_ops Now snd_rawmidi_ops is maintained as a const pointer in snd_rawmidi, we can constify the definitions. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/ca0106/ca_midi.c | 4 ++-- sound/pci/cs4281.c | 4 ++-- sound/pci/cs46xx/cs46xx_lib.c | 4 ++-- sound/pci/echoaudio/midi.c | 4 ++-- sound/pci/emu10k1/emu10k1x.c | 4 ++-- sound/pci/emu10k1/emumpu401.c | 4 ++-- sound/pci/ens1370.c | 4 ++-- sound/pci/ice1712/ice1724.c | 4 ++-- sound/pci/rme9652/hdsp.c | 4 ++-- sound/pci/rme9652/hdspm.c | 4 ++-- 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/sound/pci/ca0106/ca_midi.c b/sound/pci/ca0106/ca_midi.c index b91c7f6d19f9..4d4d385205eb 100644 --- a/sound/pci/ca0106/ca_midi.c +++ b/sound/pci/ca0106/ca_midi.c @@ -255,14 +255,14 @@ static void ca_midi_output_trigger(struct snd_rawmidi_substream *substream, int } } -static struct snd_rawmidi_ops ca_midi_output = +static const struct snd_rawmidi_ops ca_midi_output = { .open = ca_midi_output_open, .close = ca_midi_output_close, .trigger = ca_midi_output_trigger, }; -static struct snd_rawmidi_ops ca_midi_input = +static const struct snd_rawmidi_ops ca_midi_input = { .open = ca_midi_input_open, .close = ca_midi_input_close, diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 8f0f5f24e40e..fa7c51684dd2 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -1767,14 +1767,14 @@ static void snd_cs4281_midi_output_trigger(struct snd_rawmidi_substream *substre spin_unlock_irqrestore(&chip->reg_lock, flags); } -static struct snd_rawmidi_ops snd_cs4281_midi_output = +static const struct snd_rawmidi_ops snd_cs4281_midi_output = { .open = snd_cs4281_midi_output_open, .close = snd_cs4281_midi_output_close, .trigger = snd_cs4281_midi_output_trigger, }; -static struct snd_rawmidi_ops snd_cs4281_midi_input = +static const struct snd_rawmidi_ops snd_cs4281_midi_input = { .open = snd_cs4281_midi_input_open, .close = snd_cs4281_midi_input_close, diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index fde3cd48258c..e561fd536f5b 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -2683,14 +2683,14 @@ static void snd_cs46xx_midi_output_trigger(struct snd_rawmidi_substream *substre spin_unlock_irqrestore(&chip->reg_lock, flags); } -static struct snd_rawmidi_ops snd_cs46xx_midi_output = +static const struct snd_rawmidi_ops snd_cs46xx_midi_output = { .open = snd_cs46xx_midi_output_open, .close = snd_cs46xx_midi_output_close, .trigger = snd_cs46xx_midi_output_trigger, }; -static struct snd_rawmidi_ops snd_cs46xx_midi_input = +static const struct snd_rawmidi_ops snd_cs46xx_midi_input = { .open = snd_cs46xx_midi_input_open, .close = snd_cs46xx_midi_input_close, diff --git a/sound/pci/echoaudio/midi.c b/sound/pci/echoaudio/midi.c index a8fe58335ddc..8c685ddb1a41 100644 --- a/sound/pci/echoaudio/midi.c +++ b/sound/pci/echoaudio/midi.c @@ -288,13 +288,13 @@ static int snd_echo_midi_output_close(struct snd_rawmidi_substream *substream) -static struct snd_rawmidi_ops snd_echo_midi_input = { +static const struct snd_rawmidi_ops snd_echo_midi_input = { .open = snd_echo_midi_input_open, .close = snd_echo_midi_input_close, .trigger = snd_echo_midi_input_trigger, }; -static struct snd_rawmidi_ops snd_echo_midi_output = { +static const struct snd_rawmidi_ops snd_echo_midi_output = { .open = snd_echo_midi_output_open, .close = snd_echo_midi_output_close, .trigger = snd_echo_midi_output_trigger, diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 921037ed8468..32842734ada6 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -1486,14 +1486,14 @@ static void snd_emu10k1x_midi_output_trigger(struct snd_rawmidi_substream *subst */ -static struct snd_rawmidi_ops snd_emu10k1x_midi_output = +static const struct snd_rawmidi_ops snd_emu10k1x_midi_output = { .open = snd_emu10k1x_midi_output_open, .close = snd_emu10k1x_midi_output_close, .trigger = snd_emu10k1x_midi_output_trigger, }; -static struct snd_rawmidi_ops snd_emu10k1x_midi_input = +static const struct snd_rawmidi_ops snd_emu10k1x_midi_input = { .open = snd_emu10k1x_midi_input_open, .close = snd_emu10k1x_midi_input_close, diff --git a/sound/pci/emu10k1/emumpu401.c b/sound/pci/emu10k1/emumpu401.c index fdf2b0ada489..b6650f5c1621 100644 --- a/sound/pci/emu10k1/emumpu401.c +++ b/sound/pci/emu10k1/emumpu401.c @@ -308,14 +308,14 @@ static void snd_emu10k1_midi_output_trigger(struct snd_rawmidi_substream *substr */ -static struct snd_rawmidi_ops snd_emu10k1_midi_output = +static const struct snd_rawmidi_ops snd_emu10k1_midi_output = { .open = snd_emu10k1_midi_output_open, .close = snd_emu10k1_midi_output_close, .trigger = snd_emu10k1_midi_output_trigger, }; -static struct snd_rawmidi_ops snd_emu10k1_midi_input = +static const struct snd_rawmidi_ops snd_emu10k1_midi_input = { .open = snd_emu10k1_midi_input_open, .close = snd_emu10k1_midi_input_close, diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index 51736c2b5a00..164adad91650 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -2317,14 +2317,14 @@ static void snd_ensoniq_midi_output_trigger(struct snd_rawmidi_substream *substr spin_unlock_irqrestore(&ensoniq->reg_lock, flags); } -static struct snd_rawmidi_ops snd_ensoniq_midi_output = +static const struct snd_rawmidi_ops snd_ensoniq_midi_output = { .open = snd_ensoniq_midi_output_open, .close = snd_ensoniq_midi_output_close, .trigger = snd_ensoniq_midi_output_trigger, }; -static struct snd_rawmidi_ops snd_ensoniq_midi_input = +static const struct snd_rawmidi_ops snd_ensoniq_midi_input = { .open = snd_ensoniq_midi_input_open, .close = snd_ensoniq_midi_input_close, diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index e5c52ed9b674..842744e7a139 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -367,7 +367,7 @@ static void vt1724_midi_output_drain(struct snd_rawmidi_substream *s) } while (time_after(timeout, jiffies)); } -static struct snd_rawmidi_ops vt1724_midi_output_ops = { +static const struct snd_rawmidi_ops vt1724_midi_output_ops = { .open = vt1724_midi_output_open, .close = vt1724_midi_output_close, .trigger = vt1724_midi_output_trigger, @@ -402,7 +402,7 @@ static void vt1724_midi_input_trigger(struct snd_rawmidi_substream *s, int up) spin_unlock_irqrestore(&ice->reg_lock, flags); } -static struct snd_rawmidi_ops vt1724_midi_input_ops = { +static const struct snd_rawmidi_ops vt1724_midi_input_ops = { .open = vt1724_midi_input_open, .close = vt1724_midi_input_close, .trigger = vt1724_midi_input_trigger, diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index b94fc6357139..fc0face6cdc6 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -1510,14 +1510,14 @@ static int snd_hdsp_midi_output_close(struct snd_rawmidi_substream *substream) return 0; } -static struct snd_rawmidi_ops snd_hdsp_midi_output = +static const struct snd_rawmidi_ops snd_hdsp_midi_output = { .open = snd_hdsp_midi_output_open, .close = snd_hdsp_midi_output_close, .trigger = snd_hdsp_midi_output_trigger, }; -static struct snd_rawmidi_ops snd_hdsp_midi_input = +static const struct snd_rawmidi_ops snd_hdsp_midi_input = { .open = snd_hdsp_midi_input_open, .close = snd_hdsp_midi_input_close, diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 14bbf55c1ef9..c48acdb0e186 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -2043,14 +2043,14 @@ static int snd_hdspm_midi_output_close(struct snd_rawmidi_substream *substream) return 0; } -static struct snd_rawmidi_ops snd_hdspm_midi_output = +static const struct snd_rawmidi_ops snd_hdspm_midi_output = { .open = snd_hdspm_midi_output_open, .close = snd_hdspm_midi_output_close, .trigger = snd_hdspm_midi_output_trigger, }; -static struct snd_rawmidi_ops snd_hdspm_midi_input = +static const struct snd_rawmidi_ops snd_hdspm_midi_input = { .open = snd_hdspm_midi_input_open, .close = snd_hdspm_midi_input_close, -- cgit v1.2.3 From 57eb67994a9d117ea81d1580a9163733e26a1fc3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 5 Jan 2017 17:29:54 +0100 Subject: ALSA: firewire: Constify snd_rawmidi_ops Now snd_rawmidi_ops is maintained as a const pointer in snd_rawmidi, we can constify the definitions. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob_midi.c | 4 ++-- sound/firewire/dice/dice-midi.c | 4 ++-- sound/firewire/digi00x/digi00x-midi.c | 8 ++++---- sound/firewire/fireworks/fireworks_midi.c | 4 ++-- sound/firewire/oxfw/oxfw-midi.c | 4 ++-- sound/firewire/oxfw/oxfw-scs1x.c | 4 ++-- sound/firewire/tascam/tascam-midi.c | 4 ++-- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/sound/firewire/bebob/bebob_midi.c b/sound/firewire/bebob/bebob_midi.c index 7e5fb4b990bd..3befa3eca6ef 100644 --- a/sound/firewire/bebob/bebob_midi.c +++ b/sound/firewire/bebob/bebob_midi.c @@ -120,12 +120,12 @@ static void set_midi_substream_names(struct snd_bebob *bebob, int snd_bebob_create_midi_devices(struct snd_bebob *bebob) { - static struct snd_rawmidi_ops capture_ops = { + static const struct snd_rawmidi_ops capture_ops = { .open = midi_capture_open, .close = midi_capture_close, .trigger = midi_capture_trigger, }; - static struct snd_rawmidi_ops playback_ops = { + static const struct snd_rawmidi_ops playback_ops = { .open = midi_playback_open, .close = midi_playback_close, .trigger = midi_playback_trigger, diff --git a/sound/firewire/dice/dice-midi.c b/sound/firewire/dice/dice-midi.c index cdf71c211342..8ff6da3c51f7 100644 --- a/sound/firewire/dice/dice-midi.c +++ b/sound/firewire/dice/dice-midi.c @@ -91,12 +91,12 @@ static void set_midi_substream_names(struct snd_dice *dice, int snd_dice_create_midi(struct snd_dice *dice) { - static struct snd_rawmidi_ops capture_ops = { + static const struct snd_rawmidi_ops capture_ops = { .open = midi_open, .close = midi_close, .trigger = midi_capture_trigger, }; - static struct snd_rawmidi_ops playback_ops = { + static const struct snd_rawmidi_ops playback_ops = { .open = midi_open, .close = midi_close, .trigger = midi_playback_trigger, diff --git a/sound/firewire/digi00x/digi00x-midi.c b/sound/firewire/digi00x/digi00x-midi.c index 8689c3bb4c6a..915d2a21223e 100644 --- a/sound/firewire/digi00x/digi00x-midi.c +++ b/sound/firewire/digi00x/digi00x-midi.c @@ -148,22 +148,22 @@ static void set_midi_substream_names(struct snd_dg00x *dg00x, int snd_dg00x_create_midi_devices(struct snd_dg00x *dg00x) { - static struct snd_rawmidi_ops phys_capture_ops = { + static const struct snd_rawmidi_ops phys_capture_ops = { .open = midi_phys_open, .close = midi_phys_close, .trigger = midi_phys_capture_trigger, }; - static struct snd_rawmidi_ops phys_playback_ops = { + static const struct snd_rawmidi_ops phys_playback_ops = { .open = midi_phys_open, .close = midi_phys_close, .trigger = midi_phys_playback_trigger, }; - static struct snd_rawmidi_ops ctl_capture_ops = { + static const struct snd_rawmidi_ops ctl_capture_ops = { .open = midi_ctl_open, .close = midi_ctl_capture_close, .trigger = midi_ctl_capture_trigger, }; - static struct snd_rawmidi_ops ctl_playback_ops = { + static const struct snd_rawmidi_ops ctl_playback_ops = { .open = midi_ctl_open, .close = midi_ctl_playback_close, .trigger = midi_ctl_playback_trigger, diff --git a/sound/firewire/fireworks/fireworks_midi.c b/sound/firewire/fireworks/fireworks_midi.c index 2873eca22bfc..f5da2cd4ce42 100644 --- a/sound/firewire/fireworks/fireworks_midi.c +++ b/sound/firewire/fireworks/fireworks_midi.c @@ -120,12 +120,12 @@ static void set_midi_substream_names(struct snd_efw *efw, int snd_efw_create_midi_devices(struct snd_efw *efw) { - static struct snd_rawmidi_ops capture_ops = { + static const struct snd_rawmidi_ops capture_ops = { .open = midi_capture_open, .close = midi_capture_close, .trigger = midi_capture_trigger, }; - static struct snd_rawmidi_ops playback_ops = { + static const struct snd_rawmidi_ops playback_ops = { .open = midi_playback_open, .close = midi_playback_close, .trigger = midi_playback_trigger, diff --git a/sound/firewire/oxfw/oxfw-midi.c b/sound/firewire/oxfw/oxfw-midi.c index 076a1a977275..b7bbd77dfff1 100644 --- a/sound/firewire/oxfw/oxfw-midi.c +++ b/sound/firewire/oxfw/oxfw-midi.c @@ -130,12 +130,12 @@ static void set_midi_substream_names(struct snd_oxfw *oxfw, int snd_oxfw_create_midi(struct snd_oxfw *oxfw) { - static struct snd_rawmidi_ops capture_ops = { + static const struct snd_rawmidi_ops capture_ops = { .open = midi_capture_open, .close = midi_capture_close, .trigger = midi_capture_trigger, }; - static struct snd_rawmidi_ops playback_ops = { + static const struct snd_rawmidi_ops playback_ops = { .open = midi_playback_open, .close = midi_playback_close, .trigger = midi_playback_trigger, diff --git a/sound/firewire/oxfw/oxfw-scs1x.c b/sound/firewire/oxfw/oxfw-scs1x.c index f897c9831077..79400586b7ac 100644 --- a/sound/firewire/oxfw/oxfw-scs1x.c +++ b/sound/firewire/oxfw/oxfw-scs1x.c @@ -297,7 +297,7 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *stream, int up) } } -static struct snd_rawmidi_ops midi_capture_ops = { +static const struct snd_rawmidi_ops midi_capture_ops = { .open = midi_capture_open, .close = midi_capture_close, .trigger = midi_capture_trigger, @@ -338,7 +338,7 @@ static void midi_playback_drain(struct snd_rawmidi_substream *stream) wait_event(scs->idle_wait, scs->output_idle); } -static struct snd_rawmidi_ops midi_playback_ops = { +static const struct snd_rawmidi_ops midi_playback_ops = { .open = midi_playback_open, .close = midi_playback_close, .trigger = midi_playback_trigger, diff --git a/sound/firewire/tascam/tascam-midi.c b/sound/firewire/tascam/tascam-midi.c index 7fdc71e4763e..df4f95d65925 100644 --- a/sound/firewire/tascam/tascam-midi.c +++ b/sound/firewire/tascam/tascam-midi.c @@ -70,12 +70,12 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up) int snd_tscm_create_midi_devices(struct snd_tscm *tscm) { - static struct snd_rawmidi_ops capture_ops = { + static const struct snd_rawmidi_ops capture_ops = { .open = midi_capture_open, .close = midi_capture_close, .trigger = midi_capture_trigger, }; - static struct snd_rawmidi_ops playback_ops = { + static const struct snd_rawmidi_ops playback_ops = { .open = midi_playback_open, .close = midi_playback_close, .trigger = midi_playback_trigger, -- cgit v1.2.3 From f43e5407e4184ef0e5a31272f80ca893cb5ee24c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 5 Jan 2017 17:30:12 +0100 Subject: ALSA: usb: Constify snd_rawmidi_ops Now snd_rawmidi_ops is maintained as a const pointer in snd_rawmidi, we can constify the definitions. Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/usb/6fire/midi.c | 4 ++-- sound/usb/bcd2000/bcd2000.c | 4 ++-- sound/usb/caiaq/midi.c | 4 ++-- sound/usb/line6/midi.c | 4 ++-- sound/usb/midi.c | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/sound/usb/6fire/midi.c b/sound/usb/6fire/midi.c index 3d410969553e..aa5adbb6eb5d 100644 --- a/sound/usb/6fire/midi.c +++ b/sound/usb/6fire/midi.c @@ -139,14 +139,14 @@ static void usb6fire_midi_in_trigger( spin_unlock_irqrestore(&rt->in_lock, flags); } -static struct snd_rawmidi_ops out_ops = { +static const struct snd_rawmidi_ops out_ops = { .open = usb6fire_midi_out_open, .close = usb6fire_midi_out_close, .trigger = usb6fire_midi_out_trigger, .drain = usb6fire_midi_out_drain }; -static struct snd_rawmidi_ops in_ops = { +static const struct snd_rawmidi_ops in_ops = { .open = usb6fire_midi_in_open, .close = usb6fire_midi_in_close, .trigger = usb6fire_midi_in_trigger diff --git a/sound/usb/bcd2000/bcd2000.c b/sound/usb/bcd2000/bcd2000.c index d060dddcc52d..2ff9d578753a 100644 --- a/sound/usb/bcd2000/bcd2000.c +++ b/sound/usb/bcd2000/bcd2000.c @@ -252,13 +252,13 @@ static void bcd2000_input_complete(struct urb *urb) __func__, ret); } -static struct snd_rawmidi_ops bcd2000_midi_output = { +static const struct snd_rawmidi_ops bcd2000_midi_output = { .open = bcd2000_midi_output_open, .close = bcd2000_midi_output_close, .trigger = bcd2000_midi_output_trigger, }; -static struct snd_rawmidi_ops bcd2000_midi_input = { +static const struct snd_rawmidi_ops bcd2000_midi_input = { .open = bcd2000_midi_input_open, .close = bcd2000_midi_input_close, .trigger = bcd2000_midi_input_trigger, diff --git a/sound/usb/caiaq/midi.c b/sound/usb/caiaq/midi.c index 2d7588461b33..f8e5b1b57c4f 100644 --- a/sound/usb/caiaq/midi.c +++ b/sound/usb/caiaq/midi.c @@ -102,14 +102,14 @@ static void snd_usb_caiaq_midi_output_trigger(struct snd_rawmidi_substream *subs } -static struct snd_rawmidi_ops snd_usb_caiaq_midi_output = +static const struct snd_rawmidi_ops snd_usb_caiaq_midi_output = { .open = snd_usb_caiaq_midi_output_open, .close = snd_usb_caiaq_midi_output_close, .trigger = snd_usb_caiaq_midi_output_trigger, }; -static struct snd_rawmidi_ops snd_usb_caiaq_midi_input = +static const struct snd_rawmidi_ops snd_usb_caiaq_midi_input = { .open = snd_usb_caiaq_midi_input_open, .close = snd_usb_caiaq_midi_input_close, diff --git a/sound/usb/line6/midi.c b/sound/usb/line6/midi.c index d0fb2f205bd9..1d3a23b02d68 100644 --- a/sound/usb/line6/midi.c +++ b/sound/usb/line6/midi.c @@ -200,14 +200,14 @@ static void line6_midi_input_trigger(struct snd_rawmidi_substream *substream, line6->line6midi->substream_receive = NULL; } -static struct snd_rawmidi_ops line6_midi_output_ops = { +static const struct snd_rawmidi_ops line6_midi_output_ops = { .open = line6_midi_output_open, .close = line6_midi_output_close, .trigger = line6_midi_output_trigger, .drain = line6_midi_output_drain, }; -static struct snd_rawmidi_ops line6_midi_input_ops = { +static const struct snd_rawmidi_ops line6_midi_input_ops = { .open = line6_midi_input_open, .close = line6_midi_input_close, .trigger = line6_midi_input_trigger, diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 7ba92921bf28..6e763bc8d7db 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -1234,14 +1234,14 @@ static void snd_usbmidi_input_trigger(struct snd_rawmidi_substream *substream, clear_bit(substream->number, &umidi->input_triggered); } -static struct snd_rawmidi_ops snd_usbmidi_output_ops = { +static const struct snd_rawmidi_ops snd_usbmidi_output_ops = { .open = snd_usbmidi_output_open, .close = snd_usbmidi_output_close, .trigger = snd_usbmidi_output_trigger, .drain = snd_usbmidi_output_drain, }; -static struct snd_rawmidi_ops snd_usbmidi_input_ops = { +static const struct snd_rawmidi_ops snd_usbmidi_input_ops = { .open = snd_usbmidi_input_open, .close = snd_usbmidi_input_close, .trigger = snd_usbmidi_input_trigger -- cgit v1.2.3 From 1753187e288aacabfa8d61e4465f234fd80599fe Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 13 Jan 2017 20:30:22 +0900 Subject: ALSA: oxfw: enclose identifiers referred by single function for scs1x feature Some identifiers are referred just by one functions. In this case, they can be put into the function definition. This brings two merits; readers can easily follow codes related to the identifiers, developers are free from name conflict. This commit moves such identifiers to each function definition. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/oxfw/oxfw-scs1x.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/firewire/oxfw/oxfw-scs1x.c b/sound/firewire/oxfw/oxfw-scs1x.c index 79400586b7ac..93209ebd9121 100644 --- a/sound/firewire/oxfw/oxfw-scs1x.c +++ b/sound/firewire/oxfw/oxfw-scs1x.c @@ -338,12 +338,6 @@ static void midi_playback_drain(struct snd_rawmidi_substream *stream) wait_event(scs->idle_wait, scs->output_idle); } -static const struct snd_rawmidi_ops midi_playback_ops = { - .open = midi_playback_open, - .close = midi_playback_close, - .trigger = midi_playback_trigger, - .drain = midi_playback_drain, -}; static int register_address(struct snd_oxfw *oxfw) { struct fw_scs1x *scs = oxfw->spec; @@ -369,6 +363,12 @@ void snd_oxfw_scs1x_update(struct snd_oxfw *oxfw) int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw) { + static const struct snd_rawmidi_ops midi_playback_ops = { + .open = midi_playback_open, + .close = midi_playback_close, + .trigger = midi_playback_trigger, + .drain = midi_playback_drain, + }; struct snd_rawmidi *rmidi; struct fw_scs1x *scs; int err; -- cgit v1.2.3 From 41438f1314b0f6f4d94edc56bb5bc77138445bb3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 12 Jan 2017 17:13:21 +0100 Subject: ALSA: hda - Make single_cmd option to stop the fallback mechanism HD-audio driver has a mechanism to fall back to the single cmd mode as a last resort if the CORB/RIRB communication goes wrong even after switching to the polling mode. The switching has worked in the past well, but Enrico Mioso reported that his system crashes when this happens. Although the actual cause of the crash isn't still fully analyzed yet, it'd be in anyway good to provide an option to turn off the fallback mode. Now this patch extends the behavior of the existing single_cmd option for that. Namely, - The option is changed from bool to bint. - As default, it is the mode allowing the fallback to single cmd. - Once when either true/false value is given to the option, the driver explicitly turns on/off the single cmd mode, but without the fallback. That is, if you want to disable the fallback, just pass single_cmd=0 option. Passing single_cmd=1 will keep working like before. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_controller.c | 4 ++++ sound/pci/hda/hda_controller.h | 1 + sound/pci/hda/hda_intel.c | 10 +++++++--- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 500878556578..3715a5725613 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -861,6 +861,10 @@ static int azx_rirb_get_response(struct hdac_bus *bus, unsigned int addr, return -EIO; } + /* no fallback mechanism? */ + if (!chip->fallback_to_single_cmd) + return -EIO; + /* a fatal communication error; need either to reset or to fallback * to the single_cmd mode */ diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index a50e0532622a..35a9ab2cac46 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -150,6 +150,7 @@ struct azx { int bdl_pos_adj; int poll_count; unsigned int running:1; + unsigned int fallback_to_single_cmd:1; unsigned int single_cmd:1; unsigned int polling_mode:1; unsigned int msi:1; diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 2587c197e353..faf99cc71277 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -128,7 +128,7 @@ static int bdl_pos_adj[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; static int probe_only[SNDRV_CARDS]; static int jackpoll_ms[SNDRV_CARDS]; -static bool single_cmd; +static int single_cmd = -1; static int enable_msi = -1; #ifdef CONFIG_SND_HDA_PATCH_LOADER static char *patch[SNDRV_CARDS]; @@ -157,7 +157,7 @@ module_param_array(probe_only, int, NULL, 0444); MODULE_PARM_DESC(probe_only, "Only probing and no codec initialization."); module_param_array(jackpoll_ms, int, NULL, 0444); MODULE_PARM_DESC(jackpoll_ms, "Ms between polling for jack events (default = 0, using unsol events only)"); -module_param(single_cmd, bool, 0444); +module_param(single_cmd, bint, 0444); MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs " "(for debugging only)."); module_param(enable_msi, bint, 0444); @@ -1596,7 +1596,11 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci, check_probe_mask(chip, dev); - chip->single_cmd = single_cmd; + if (single_cmd < 0) /* allow fallback to single_cmd at errors */ + chip->fallback_to_single_cmd = 1; + else /* explicitly set to single_cmd or not */ + chip->single_cmd = single_cmd; + azx_check_snoop_available(chip); if (bdl_pos_adj[dev] < 0) -- cgit v1.2.3 From a535ad57d0e6b959cd79914a1127caade36a9459 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Mon, 16 Jan 2017 16:59:26 +0800 Subject: ALSA: hda/realtek - New codec support of ALC1220 Add support for new codec of ALC1220. It's compatible with ALC882 & co. Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 3c6964793206..1c88da8a5cf4 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -380,6 +380,7 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) break; case 0x10ec0899: case 0x10ec0900: + case 0x10ec1220: alc_update_coef_idx(codec, 0x7, 1<<1, 0); break; } @@ -2310,6 +2311,7 @@ static int patch_alc882(struct hda_codec *codec) case 0x10ec0882: case 0x10ec0885: case 0x10ec0900: + case 0x10ec1220: break; default: /* ALC883 and variants */ @@ -7297,6 +7299,7 @@ static const struct hda_device_id snd_hda_id_realtek[] = { HDA_CODEC_ENTRY(0x10ec0892, "ALC892", patch_alc662), HDA_CODEC_ENTRY(0x10ec0899, "ALC898", patch_alc882), HDA_CODEC_ENTRY(0x10ec0900, "ALC1150", patch_alc882), + HDA_CODEC_ENTRY(0x10ec1220, "ALC1220", patch_alc882), {} /* terminator */ }; MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_realtek); -- cgit v1.2.3 From 8b169cb27c8267cd344fd71c2067ea864dd4c2e7 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 16 Jan 2017 14:27:57 +0100 Subject: ALSA: mips: avoid potential uninitialized variable use MIPS allmodconfig results in this warning: sound/mips/hal2.c: In function 'hal2_gain_get': sound/mips/hal2.c:224:35: error: 'r' may be used uninitialized in this function [-Werror=maybe-uninitialized] sound/mips/hal2.c:223:35: error: 'l' may be used uninitialized in this function [-Werror=maybe-uninitialized] sound/mips/hal2.c: In function 'hal2_gain_put': sound/mips/hal2.c:260:13: error: 'new' may be used uninitialized in this function [-Werror=maybe-uninitialized] sound/mips/hal2.c:260:13: error: 'old' may be used uninitialized in this function [-Werror=maybe-uninitialized] Returning an error for all unexpected cases shuts up the warning Signed-off-by: Arnd Bergmann Signed-off-by: Takashi Iwai --- sound/mips/hal2.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/mips/hal2.c b/sound/mips/hal2.c index ede449f0b50d..00fc9241d266 100644 --- a/sound/mips/hal2.c +++ b/sound/mips/hal2.c @@ -219,6 +219,8 @@ static int hal2_gain_get(struct snd_kcontrol *kcontrol, l = (tmp >> H2I_C2_L_GAIN_SHIFT) & 15; r = (tmp >> H2I_C2_R_GAIN_SHIFT) & 15; break; + default: + return -EINVAL; } ucontrol->value.integer.value[0] = l; ucontrol->value.integer.value[1] = r; @@ -256,6 +258,8 @@ static int hal2_gain_put(struct snd_kcontrol *kcontrol, new |= (r << H2I_C2_R_GAIN_SHIFT); hal2_i_write32(hal2, H2I_ADC_C2, new); break; + default: + return -EINVAL; } return old != new; } -- cgit v1.2.3 From 9eb5d0e635ebe2f227d591e531d48c6f01c0dd78 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Tue, 17 Jan 2017 15:40:25 +0800 Subject: ALSA: hda/realtek - Add support headphone Mic for ALC221 of HP platform ALC221 HP platform need to support Headphone Mic. This patch will turn on headphone Mic supported. Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 1c88da8a5cf4..06b5a480db8d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3816,6 +3816,7 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, case 0x10ec0867: alc_update_coefex_idx(codec, 0x57, 0x5, 0, 1<<14); /* fallthru */ + case 0x10ec0221: case 0x10ec0662: snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); @@ -4867,6 +4868,7 @@ enum { ALC298_FIXUP_SPK_VOLUME, ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER, ALC269_FIXUP_ATIV_BOOK_8, + ALC221_FIXUP_HP_MIC_NO_PRESENCE, }; static const struct hda_fixup alc269_fixups[] = { @@ -5545,6 +5547,16 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC269_FIXUP_NO_SHUTUP }, + [ALC221_FIXUP_HP_MIC_NO_PRESENCE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x18, 0x01a1913c }, /* use as headset mic, without its own jack detect */ + { 0x1a, 0x01a1913d }, /* use as headphone mic, without its own jack detect */ + { } + }, + .chained = true, + .chain_id = ALC269_FIXUP_HEADSET_MODE + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -5655,6 +5667,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { 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, 0x8256, "HP", ALC221_FIXUP_HP_FRONT_MIC), + SND_PCI_QUIRK(0x103c, 0x82bf, "HP", ALC221_FIXUP_HP_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x103c, 0x82c0, "HP", ALC221_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300), SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), -- cgit v1.2.3 From eef57324d926f0d8c7a40069e7d26e0cb0651b47 Mon Sep 17 00:00:00 2001 From: Jerome Anand Date: Wed, 25 Jan 2017 04:27:49 +0530 Subject: drm/i915: setup bridge for HDMI LPE audio driver Enable support for HDMI LPE audio mode on Baytrail and Cherrytrail when HDaudio controller is not detected Setup minimum required resources during i915_driver_load: 1. Create a platform device to share MMIO/IRQ resources 2. Make the platform device child of i915 device for runtime PM. 3. Create IRQ chip to forward HDMI LPE audio irqs. HDMI LPE audio driver (a standalone sound driver) probes the LPE audio device and creates a new sound card. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Jerome Anand Acked-by: Jani Nikula Signed-off-by: Takashi Iwai --- Documentation/gpu/i915.rst | 9 + drivers/gpu/drm/i915/Makefile | 3 + drivers/gpu/drm/i915/i915_drv.c | 4 +- drivers/gpu/drm/i915/i915_drv.h | 11 ++ drivers/gpu/drm/i915/i915_irq.c | 16 ++ drivers/gpu/drm/i915/i915_reg.h | 3 + drivers/gpu/drm/i915/intel_audio.c | 25 +++ drivers/gpu/drm/i915/intel_drv.h | 2 + drivers/gpu/drm/i915/intel_lpe_audio.c | 321 +++++++++++++++++++++++++++++++++ include/drm/intel_lpe_audio.h | 46 +++++ 10 files changed, 438 insertions(+), 2 deletions(-) create mode 100644 drivers/gpu/drm/i915/intel_lpe_audio.c create mode 100644 include/drm/intel_lpe_audio.h diff --git a/Documentation/gpu/i915.rst b/Documentation/gpu/i915.rst index 117d2ab7a5f7..a671eee78945 100644 --- a/Documentation/gpu/i915.rst +++ b/Documentation/gpu/i915.rst @@ -213,6 +213,15 @@ Video BIOS Table (VBT) .. kernel-doc:: drivers/gpu/drm/i915/intel_vbt_defs.h :internal: +intel hdmi lpe audio support +---------------------------- + +.. kernel-doc:: drivers/gpu/drm/i915/intel_lpe_audio.c + :doc: LPE Audio integration for HDMI or DP playback + +.. kernel-doc:: drivers/gpu/drm/i915/intel_lpe_audio.c + :internal: + Memory Management and Command Submission ======================================== diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 3dea46af9fe6..78711dddd937 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -122,6 +122,9 @@ i915-y += intel_gvt.o include $(src)/gvt/Makefile endif +# LPE Audio for VLV and CHT +i915-y += intel_lpe_audio.o + obj-$(CONFIG_DRM_I915) += i915.o CFLAGS_i915_trace_points.o := -I$(src) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 445fec9c2841..9b8d81fa0441 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1138,7 +1138,7 @@ static void i915_driver_register(struct drm_i915_private *dev_priv) if (IS_GEN5(dev_priv)) intel_gpu_ips_init(dev_priv); - i915_audio_component_init(dev_priv); + intel_audio_init(dev_priv); /* * Some ports require correctly set-up hpd registers for detection to @@ -1156,7 +1156,7 @@ static void i915_driver_register(struct drm_i915_private *dev_priv) */ static void i915_driver_unregister(struct drm_i915_private *dev_priv) { - i915_audio_component_cleanup(dev_priv); + intel_audio_deinit(dev_priv); intel_gpu_ips_teardown(); acpi_video_unregister(); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 243224aeabf8..c55bf144c4e2 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2136,6 +2136,12 @@ struct drm_i915_private { /* Used to save the pipe-to-encoder mapping for audio */ struct intel_encoder *av_enc_map[I915_MAX_PIPES]; + /* necessary resource sharing with HDMI LPE audio driver. */ + struct { + struct platform_device *platdev; + int irq; + } lpe_audio; + /* * NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch * will be rejected. Instead look for a better place. @@ -3390,6 +3396,11 @@ extern int i915_restore_state(struct drm_device *dev); void i915_setup_sysfs(struct drm_i915_private *dev_priv); void i915_teardown_sysfs(struct drm_i915_private *dev_priv); +/* intel_lpe_audio.c */ +int intel_lpe_audio_init(struct drm_i915_private *dev_priv); +void intel_lpe_audio_teardown(struct drm_i915_private *dev_priv); +void intel_lpe_audio_irq_handler(struct drm_i915_private *dev_priv); + /* intel_i2c.c */ extern int intel_setup_gmbus(struct drm_device *dev); extern void intel_teardown_gmbus(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 07ca71cabb2b..f0880afbb878 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1893,6 +1893,10 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg) * signalled in iir */ valleyview_pipestat_irq_ack(dev_priv, iir, pipe_stats); + if (iir & (I915_LPE_PIPE_A_INTERRUPT | + I915_LPE_PIPE_B_INTERRUPT)) + intel_lpe_audio_irq_handler(dev_priv); + /* * VLV_IIR is single buffered, and reflects the level * from PIPESTAT/PORT_HOTPLUG_STAT, hence clear it last. @@ -1973,6 +1977,11 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg) * signalled in iir */ valleyview_pipestat_irq_ack(dev_priv, iir, pipe_stats); + if (iir & (I915_LPE_PIPE_A_INTERRUPT | + I915_LPE_PIPE_B_INTERRUPT | + I915_LPE_PIPE_C_INTERRUPT)) + intel_lpe_audio_irq_handler(dev_priv); + /* * VLV_IIR is single buffered, and reflects the level * from PIPESTAT/PORT_HOTPLUG_STAT, hence clear it last. @@ -2914,6 +2923,7 @@ static void vlv_display_irq_postinstall(struct drm_i915_private *dev_priv) u32 pipestat_mask; u32 enable_mask; enum pipe pipe; + u32 val; pipestat_mask = PLANE_FLIP_DONE_INT_STATUS_VLV | PIPE_CRC_DONE_INTERRUPT_STATUS; @@ -2930,6 +2940,12 @@ static void vlv_display_irq_postinstall(struct drm_i915_private *dev_priv) WARN_ON(dev_priv->irq_mask != ~0); + val = (I915_LPE_PIPE_A_INTERRUPT | + I915_LPE_PIPE_B_INTERRUPT | + I915_LPE_PIPE_C_INTERRUPT); + + enable_mask |= val; + dev_priv->irq_mask = ~enable_mask; GEN5_IRQ_INIT(VLV_, dev_priv->irq_mask, enable_mask); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index c70c07a7b586..a9ffc8df241b 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2058,6 +2058,9 @@ enum skl_disp_power_wells { #define I915_ASLE_INTERRUPT (1<<0) #define I915_BSD_USER_INTERRUPT (1<<25) +#define I915_HDMI_LPE_AUDIO_BASE (VLV_DISPLAY_BASE + 0x65000) +#define I915_HDMI_LPE_AUDIO_SIZE 0x1000 + #define GEN6_BSD_RNCID _MMIO(0x12198) #define GEN7_FF_THREAD_MODE _MMIO(0x20a0) diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 49f10538d4aa..1e93263b4c87 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -931,3 +931,28 @@ void i915_audio_component_cleanup(struct drm_i915_private *dev_priv) component_del(dev_priv->drm.dev, &i915_audio_component_bind_ops); dev_priv->audio_component_registered = false; } + +/** + * intel_audio_init() - Initialize the audio driver either using + * component framework or using lpe audio bridge + * @dev_priv: the i915 drm device private data + * + */ +void intel_audio_init(struct drm_i915_private *dev_priv) +{ + if (intel_lpe_audio_init(dev_priv) < 0) + i915_audio_component_init(dev_priv); +} + +/** + * intel_audio_deinit() - deinitialize the audio driver + * @dev_priv: the i915 drm device private data + * + */ +void intel_audio_deinit(struct drm_i915_private *dev_priv) +{ + if ((dev_priv)->lpe_audio.platdev != NULL) + intel_lpe_audio_teardown(dev_priv); + else + i915_audio_component_cleanup(dev_priv); +} diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index cd132c216a67..301c4be0544b 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1192,6 +1192,8 @@ void intel_audio_codec_enable(struct intel_encoder *encoder, void intel_audio_codec_disable(struct intel_encoder *encoder); void i915_audio_component_init(struct drm_i915_private *dev_priv); void i915_audio_component_cleanup(struct drm_i915_private *dev_priv); +void intel_audio_init(struct drm_i915_private *dev_priv); +void intel_audio_deinit(struct drm_i915_private *dev_priv); /* intel_display.c */ enum transcoder intel_crtc_pch_transcoder(struct intel_crtc *crtc); diff --git a/drivers/gpu/drm/i915/intel_lpe_audio.c b/drivers/gpu/drm/i915/intel_lpe_audio.c new file mode 100644 index 000000000000..7ce1b5b99275 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_lpe_audio.c @@ -0,0 +1,321 @@ +/* + * Copyright © 2016 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Pierre-Louis Bossart + * Jerome Anand + * based on VED patches + * + */ + +/** + * DOC: LPE Audio integration for HDMI or DP playback + * + * Motivation: + * Atom platforms (e.g. valleyview and cherryTrail) integrates a DMA-based + * interface as an alternative to the traditional HDaudio path. While this + * mode is unrelated to the LPE aka SST audio engine, the documentation refers + * to this mode as LPE so we keep this notation for the sake of consistency. + * + * The interface is handled by a separate standalone driver maintained in the + * ALSA subsystem for simplicity. To minimize the interaction between the two + * subsystems, a bridge is setup between the hdmi-lpe-audio and i915: + * 1. Create a platform device to share MMIO/IRQ resources + * 2. Make the platform device child of i915 device for runtime PM. + * 3. Create IRQ chip to forward the LPE audio irqs. + * the hdmi-lpe-audio driver probes the lpe audio device and creates a new + * sound card + * + * Threats: + * Due to the restriction in Linux platform device model, user need manually + * uninstall the hdmi-lpe-audio driver before uninstalling i915 module, + * otherwise we might run into use-after-free issues after i915 removes the + * platform device: even though hdmi-lpe-audio driver is released, the modules + * is still in "installed" status. + * + * Implementation: + * The MMIO/REG platform resources are created according to the registers + * specification. + * When forwarding LPE audio irqs, the flow control handler selection depends + * on the platform, for example on valleyview handle_simple_irq is enough. + * + */ + +#include +#include +#include + +#include "i915_drv.h" +#include +#include + +#define HAS_LPE_AUDIO(dev_priv) ((dev_priv)->lpe_audio.platdev != NULL) + +static struct platform_device * +lpe_audio_platdev_create(struct drm_i915_private *dev_priv) +{ + int ret; + struct drm_device *dev = &dev_priv->drm; + struct platform_device_info pinfo = {}; + struct resource *rsc; + struct platform_device *platdev; + struct intel_hdmi_lpe_audio_pdata *pdata; + + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + + rsc = kcalloc(2, sizeof(*rsc), GFP_KERNEL); + if (!rsc) { + kfree(pdata); + return ERR_PTR(-ENOMEM); + } + + rsc[0].start = rsc[0].end = dev_priv->lpe_audio.irq; + rsc[0].flags = IORESOURCE_IRQ; + rsc[0].name = "hdmi-lpe-audio-irq"; + + rsc[1].start = pci_resource_start(dev->pdev, 0) + + I915_HDMI_LPE_AUDIO_BASE; + rsc[1].end = pci_resource_start(dev->pdev, 0) + + I915_HDMI_LPE_AUDIO_BASE + I915_HDMI_LPE_AUDIO_SIZE - 1; + rsc[1].flags = IORESOURCE_MEM; + rsc[1].name = "hdmi-lpe-audio-mmio"; + + pinfo.parent = dev->dev; + pinfo.name = "hdmi-lpe-audio"; + pinfo.id = -1; + pinfo.res = rsc; + pinfo.num_res = 2; + pinfo.data = pdata; + pinfo.size_data = sizeof(*pdata); + pinfo.dma_mask = DMA_BIT_MASK(32); + + spin_lock_init(&pdata->lpe_audio_slock); + + platdev = platform_device_register_full(&pinfo); + if (IS_ERR(platdev)) { + ret = PTR_ERR(platdev); + DRM_ERROR("Failed to allocate LPE audio platform device\n"); + goto err; + } + + kfree(rsc); + + return platdev; + +err: + kfree(rsc); + kfree(pdata); + return ERR_PTR(ret); +} + +static void lpe_audio_platdev_destroy(struct drm_i915_private *dev_priv) +{ + platform_device_unregister(dev_priv->lpe_audio.platdev); + kfree(dev_priv->lpe_audio.platdev->dev.dma_mask); +} + +static void lpe_audio_irq_unmask(struct irq_data *d) +{ + struct drm_i915_private *dev_priv = d->chip_data; + unsigned long irqflags; + u32 val = (I915_LPE_PIPE_A_INTERRUPT | + I915_LPE_PIPE_B_INTERRUPT); + + if (IS_CHERRYVIEW(dev_priv)) + val |= I915_LPE_PIPE_C_INTERRUPT; + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + + dev_priv->irq_mask &= ~val; + I915_WRITE(VLV_IIR, val); + I915_WRITE(VLV_IIR, val); + I915_WRITE(VLV_IMR, dev_priv->irq_mask); + POSTING_READ(VLV_IMR); + + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); +} + +static void lpe_audio_irq_mask(struct irq_data *d) +{ + struct drm_i915_private *dev_priv = d->chip_data; + unsigned long irqflags; + u32 val = (I915_LPE_PIPE_A_INTERRUPT | + I915_LPE_PIPE_B_INTERRUPT); + + if (IS_CHERRYVIEW(dev_priv)) + val |= I915_LPE_PIPE_C_INTERRUPT; + + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + + dev_priv->irq_mask |= val; + I915_WRITE(VLV_IMR, dev_priv->irq_mask); + I915_WRITE(VLV_IIR, val); + I915_WRITE(VLV_IIR, val); + POSTING_READ(VLV_IIR); + + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); +} + +static struct irq_chip lpe_audio_irqchip = { + .name = "hdmi_lpe_audio_irqchip", + .irq_mask = lpe_audio_irq_mask, + .irq_unmask = lpe_audio_irq_unmask, +}; + +static int lpe_audio_irq_init(struct drm_i915_private *dev_priv) +{ + int irq = dev_priv->lpe_audio.irq; + + WARN_ON(!intel_irqs_enabled(dev_priv)); + irq_set_chip_and_handler_name(irq, + &lpe_audio_irqchip, + handle_simple_irq, + "hdmi_lpe_audio_irq_handler"); + + return irq_set_chip_data(irq, dev_priv); +} + +static bool lpe_audio_detect(struct drm_i915_private *dev_priv) +{ + int lpe_present = false; + + if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) { + static const struct pci_device_id atom_hdaudio_ids[] = { + /* Baytrail */ + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0f04)}, + /* Braswell */ + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2284)}, + {} + }; + + if (!pci_dev_present(atom_hdaudio_ids)) { + DRM_INFO("%s\n", "HDaudio controller not detected, using LPE audio instead\n"); + lpe_present = true; + } + } + return lpe_present; +} + +static int lpe_audio_setup(struct drm_i915_private *dev_priv) +{ + int ret; + + dev_priv->lpe_audio.irq = irq_alloc_desc(0); + if (dev_priv->lpe_audio.irq < 0) { + DRM_ERROR("Failed to allocate IRQ desc: %d\n", + dev_priv->lpe_audio.irq); + ret = dev_priv->lpe_audio.irq; + goto err; + } + + DRM_DEBUG("irq = %d\n", dev_priv->lpe_audio.irq); + + ret = lpe_audio_irq_init(dev_priv); + + if (ret) { + DRM_ERROR("Failed to initialize irqchip for lpe audio: %d\n", + ret); + goto err_free_irq; + } + + dev_priv->lpe_audio.platdev = lpe_audio_platdev_create(dev_priv); + + if (IS_ERR(dev_priv->lpe_audio.platdev)) { + ret = PTR_ERR(dev_priv->lpe_audio.platdev); + DRM_ERROR("Failed to create lpe audio platform device: %d\n", + ret); + goto err_free_irq; + } + + return 0; +err_free_irq: + irq_free_desc(dev_priv->lpe_audio.irq); +err: + dev_priv->lpe_audio.irq = -1; + dev_priv->lpe_audio.platdev = NULL; + return ret; +} + +/** + * intel_lpe_audio_irq_handler() - forwards the LPE audio irq + * @dev_priv: the i915 drm device private data + * + * the LPE Audio irq is forwarded to the irq handler registered by LPE audio + * driver. + */ +void intel_lpe_audio_irq_handler(struct drm_i915_private *dev_priv) +{ + int ret; + + if (!HAS_LPE_AUDIO(dev_priv)) + return; + + ret = generic_handle_irq(dev_priv->lpe_audio.irq); + if (ret) + DRM_ERROR_RATELIMITED("error handling LPE audio irq: %d\n", + ret); +} + +/** + * intel_lpe_audio_init() - detect and setup the bridge between HDMI LPE Audio + * driver and i915 + * @dev_priv: the i915 drm device private data + * + * Return: 0 if successful. non-zero if detection or + * llocation/initialization fails + */ +int intel_lpe_audio_init(struct drm_i915_private *dev_priv) +{ + int ret = -ENODEV; + + if (lpe_audio_detect(dev_priv)) { + ret = lpe_audio_setup(dev_priv); + if (ret < 0) + DRM_ERROR("failed to setup LPE Audio bridge\n"); + } + return ret; +} + +/** + * intel_lpe_audio_teardown() - destroy the bridge between HDMI LPE + * audio driver and i915 + * @dev_priv: the i915 drm device private data + * + * release all the resources for LPE audio <-> i915 bridge. + */ +void intel_lpe_audio_teardown(struct drm_i915_private *dev_priv) +{ + struct irq_desc *desc; + + if (!HAS_LPE_AUDIO(dev_priv)) + return; + + desc = irq_to_desc(dev_priv->lpe_audio.irq); + + lpe_audio_irq_mask(&desc->irq_data); + + lpe_audio_platdev_destroy(dev_priv); + + irq_free_desc(dev_priv->lpe_audio.irq); +} diff --git a/include/drm/intel_lpe_audio.h b/include/drm/intel_lpe_audio.h new file mode 100644 index 000000000000..952de05a9d76 --- /dev/null +++ b/include/drm/intel_lpe_audio.h @@ -0,0 +1,46 @@ +/* + * Copyright © 2016 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef _INTEL_LPE_AUDIO_H_ +#define _INTEL_LPE_AUDIO_H_ + +#include +#include + +#define HDMI_MAX_ELD_BYTES 128 + +struct intel_hdmi_lpe_audio_eld { + int port_id; + unsigned char eld_data[HDMI_MAX_ELD_BYTES]; +}; + +struct intel_hdmi_lpe_audio_pdata { + bool notify_pending; + int tmds_clock_speed; + bool hdmi_connected; + struct intel_hdmi_lpe_audio_eld eld; + void (*notify_audio_lpe)(void *audio_ptr); + spinlock_t lpe_audio_slock; +}; + +#endif /* _I915_LPE_AUDIO_H_ */ -- cgit v1.2.3 From 46d196ec460b9c45ca225f815c0b05f9de67290d Mon Sep 17 00:00:00 2001 From: Jerome Anand Date: Wed, 25 Jan 2017 04:27:50 +0530 Subject: drm/i915: Add support for audio driver notifications Notifiations like mode change, hot plug and edid to the audio driver are added. This is inturn used by the audio driver for its functionality. A new interface file capturing the notifications needed by the audio driver is added Signed-off-by: Pierre-Louis Bossart Signed-off-by: Jerome Anand Acked-by: Jani Nikula Signed-off-by: Takashi Iwai --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/intel_audio.c | 6 +++++ drivers/gpu/drm/i915/intel_hdmi.c | 1 + drivers/gpu/drm/i915/intel_lpe_audio.c | 49 ++++++++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c55bf144c4e2..3e3102cedc82 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3400,6 +3400,8 @@ void i915_teardown_sysfs(struct drm_i915_private *dev_priv); int intel_lpe_audio_init(struct drm_i915_private *dev_priv); void intel_lpe_audio_teardown(struct drm_i915_private *dev_priv); void intel_lpe_audio_irq_handler(struct drm_i915_private *dev_priv); +void intel_lpe_audio_notify(struct drm_i915_private *dev_priv, + void *eld, int port, int tmds_clk_speed); /* intel_i2c.c */ extern int intel_setup_gmbus(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 1e93263b4c87..364f96207c40 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "intel_drv.h" #include @@ -630,6 +631,9 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder, if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, (int) port, (int) pipe); + + intel_lpe_audio_notify(dev_priv, connector->eld, port, + crtc_state->port_clock); } /** @@ -663,6 +667,8 @@ void intel_audio_codec_disable(struct intel_encoder *intel_encoder) if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, (int) port, (int) pipe); + + intel_lpe_audio_notify(dev_priv, NULL, port, 0); } /** diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index fb88e32e25a3..02d50e334ac6 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -36,6 +36,7 @@ #include #include "intel_drv.h" #include +#include #include "i915_drv.h" static struct drm_device *intel_hdmi_to_dev(struct intel_hdmi *intel_hdmi) diff --git a/drivers/gpu/drm/i915/intel_lpe_audio.c b/drivers/gpu/drm/i915/intel_lpe_audio.c index 7ce1b5b99275..27d94255872d 100644 --- a/drivers/gpu/drm/i915/intel_lpe_audio.c +++ b/drivers/gpu/drm/i915/intel_lpe_audio.c @@ -319,3 +319,52 @@ void intel_lpe_audio_teardown(struct drm_i915_private *dev_priv) irq_free_desc(dev_priv->lpe_audio.irq); } + + +/** + * intel_lpe_audio_notify() - notify lpe audio event + * audio driver and i915 + * @dev_priv: the i915 drm device private data + * @eld : ELD data + * @port: port id + * @tmds_clk_speed: tmds clock frequency in Hz + * + * Notify lpe audio driver of eld change. + */ +void intel_lpe_audio_notify(struct drm_i915_private *dev_priv, + void *eld, int port, int tmds_clk_speed) +{ + unsigned long irq_flags; + struct intel_hdmi_lpe_audio_pdata *pdata = NULL; + + if (!HAS_LPE_AUDIO(dev_priv)) + return; + + pdata = dev_get_platdata( + &(dev_priv->lpe_audio.platdev->dev)); + + spin_lock_irqsave(&pdata->lpe_audio_slock, irq_flags); + + if (eld != NULL) { + memcpy(pdata->eld.eld_data, eld, + HDMI_MAX_ELD_BYTES); + pdata->eld.port_id = port; + pdata->hdmi_connected = true; + + if (tmds_clk_speed) + pdata->tmds_clock_speed = tmds_clk_speed; + } else { + memset(pdata->eld.eld_data, 0, + HDMI_MAX_ELD_BYTES); + pdata->hdmi_connected = false; + } + + if (pdata->notify_audio_lpe) + pdata->notify_audio_lpe( + (eld != NULL) ? &pdata->eld : NULL); + else + pdata->notify_pending = true; + + spin_unlock_irqrestore(&pdata->lpe_audio_slock, + irq_flags); +} -- cgit v1.2.3 From 287599cf2d7719c812774ff49db9ae8ca4fa844a Mon Sep 17 00:00:00 2001 From: Jerome Anand Date: Wed, 25 Jan 2017 04:27:51 +0530 Subject: ALSA: add Intel HDMI LPE audio driver for BYT/CHT-T On Baytrail and Cherrytrail, HDaudio may be fused out or disabled by the BIOS. This driver enables an alternate path to the i915 display registers and DMA. Although there is no hardware path between i915 display and LPE/SST audio clusters, this HDMI capability is referred to in the documentation as "HDMI LPE Audio" so we keep the name for consistency. There is no hardware path or control dependencies with the LPE/SST DSP functionality. The hdmi-lpe-audio driver will be probed when the i915 driver creates a child platform device. Since this driver is neither SoC nor PCI, a new x86 folder is added Additional indirections in the code will be cleaned up in the next series to aid smoother DP integration Signed-off-by: Pierre-Louis Bossart Signed-off-by: Jerome Anand Signed-off-by: Takashi Iwai --- sound/Kconfig | 2 + sound/Makefile | 2 +- sound/x86/Kconfig | 15 + sound/x86/Makefile | 4 + sound/x86/intel_hdmi_lpe_audio.c | 614 +++++++++++++++++++++++++++++++++++ sound/x86/intel_hdmi_lpe_audio.h | 683 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 1319 insertions(+), 1 deletion(-) create mode 100644 sound/x86/Kconfig create mode 100644 sound/x86/Makefile create mode 100644 sound/x86/intel_hdmi_lpe_audio.c create mode 100644 sound/x86/intel_hdmi_lpe_audio.h diff --git a/sound/Kconfig b/sound/Kconfig index 5a240e050ae6..ee2e69a9ecd1 100644 --- a/sound/Kconfig +++ b/sound/Kconfig @@ -108,6 +108,8 @@ source "sound/parisc/Kconfig" source "sound/soc/Kconfig" +source "sound/x86/Kconfig" + endif # SND menuconfig SOUND_PRIME diff --git a/sound/Makefile b/sound/Makefile index c41bdf5fdf24..6de45d2c32f7 100644 --- a/sound/Makefile +++ b/sound/Makefile @@ -5,7 +5,7 @@ obj-$(CONFIG_SOUND) += soundcore.o obj-$(CONFIG_SOUND_PRIME) += oss/ obj-$(CONFIG_DMASOUND) += oss/ obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \ - firewire/ sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/ hda/ + firewire/ sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/ hda/ x86/ obj-$(CONFIG_SND_AOA) += aoa/ # This one must be compilable even if sound is configured out diff --git a/sound/x86/Kconfig b/sound/x86/Kconfig new file mode 100644 index 000000000000..30d066e4885e --- /dev/null +++ b/sound/x86/Kconfig @@ -0,0 +1,15 @@ +menuconfig SND_X86 + tristate "X86 sound devices" + depends on X86 + ---help--- + X86 sound devices that don't fall under SoC or PCI categories + +if SND_X86 + +config HDMI_LPE_AUDIO + tristate "HDMI audio without HDaudio on Intel Atom platforms" + depends on DRM_I915 + help + Choose this option to support HDMI LPE Audio mode + +endif # SND_X86 diff --git a/sound/x86/Makefile b/sound/x86/Makefile new file mode 100644 index 000000000000..9b87384c17c5 --- /dev/null +++ b/sound/x86/Makefile @@ -0,0 +1,4 @@ +snd-hdmi-lpe-audio-objs += \ + intel_hdmi_lpe_audio.o + +obj-$(CONFIG_HDMI_LPE_AUDIO) += snd-hdmi-lpe-audio.o diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c new file mode 100644 index 000000000000..a9fd2d34a921 --- /dev/null +++ b/sound/x86/intel_hdmi_lpe_audio.c @@ -0,0 +1,614 @@ +/* + * intel_hdmi_lpe_audio.c - Intel HDMI LPE audio driver for Atom platforms + * + * Copyright (C) 2016 Intel Corp + * Authors: + * Jerome Anand + * Aravind Siddappaji + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "intel_hdmi_lpe_audio.h" + +/* globals*/ +static struct platform_device *hlpe_pdev; +static int hlpe_state; +static union otm_hdmi_eld_t hlpe_eld; + +struct hdmi_lpe_audio_ctx { + int irq; + void __iomem *mmio_start; + had_event_call_back had_event_callbacks; + struct snd_intel_had_interface *had_interface; + void *had_pvt_data; + int tmds_clock_speed; + unsigned int had_config_offset; + int hdmi_audio_interrupt_mask; + struct work_struct hdmi_audio_wq; +}; + +static void hdmi_set_eld(void *eld) +{ + int size; + + BUILD_BUG_ON(sizeof(hlpe_eld) > HDMI_MAX_ELD_BYTES); + + size = sizeof(hlpe_eld); + memcpy((void *)&hlpe_eld, eld, size); +} + +static int hdmi_get_eld(void *eld) +{ + u8 *eld_data = (u8 *)&hlpe_eld; + + memcpy(eld, (void *)&hlpe_eld, sizeof(hlpe_eld)); + + print_hex_dump_bytes("eld: ", DUMP_PREFIX_NONE, eld_data, + sizeof(hlpe_eld)); + return 0; +} + + +static struct hdmi_lpe_audio_ctx *get_hdmi_context(void) +{ + struct hdmi_lpe_audio_ctx *ctx; + + ctx = platform_get_drvdata(hlpe_pdev); + return ctx; +} + +/* + * return whether HDMI audio device is busy. + */ +bool mid_hdmi_audio_is_busy(void *ddev) +{ + struct hdmi_lpe_audio_ctx *ctx; + int hdmi_audio_busy = 0; + struct hdmi_audio_event hdmi_audio_event; + + dev_dbg(&hlpe_pdev->dev, "%s: Enter", __func__); + + ctx = platform_get_drvdata(hlpe_pdev); + + if (hlpe_state == hdmi_connector_status_disconnected) { + /* HDMI is not connected, assuming audio device is idle. */ + return false; + } + + if (ctx->had_interface) { + hdmi_audio_event.type = HAD_EVENT_QUERY_IS_AUDIO_BUSY; + hdmi_audio_busy = ctx->had_interface->query( + ctx->had_pvt_data, + hdmi_audio_event); + return hdmi_audio_busy != 0; + } + return false; +} + +/* + * return true if HDMI audio device is suspended/ disconnected + */ +bool mid_hdmi_audio_suspend(void *ddev) +{ + struct hdmi_lpe_audio_ctx *ctx; + struct hdmi_audio_event hdmi_audio_event; + int ret = 0; + + ctx = platform_get_drvdata(hlpe_pdev); + + if (hlpe_state == hdmi_connector_status_disconnected) { + /* HDMI is not connected, assuming audio device + * is suspended already. + */ + return true; + } + + dev_dbg(&hlpe_pdev->dev, "%s: hlpe_state %d", __func__, + hlpe_state); + + if (ctx->had_interface) { + hdmi_audio_event.type = 0; + ret = ctx->had_interface->suspend(ctx->had_pvt_data, + hdmi_audio_event); + return (ret == 0) ? true : false; + } + return true; +} + +void mid_hdmi_audio_resume(void *ddev) +{ + struct hdmi_lpe_audio_ctx *ctx; + + ctx = platform_get_drvdata(hlpe_pdev); + + if (hlpe_state == hdmi_connector_status_disconnected) { + /* HDMI is not connected, there is no need + * to resume audio device. + */ + return; + } + + dev_dbg(&hlpe_pdev->dev, "%s: hlpe_state %d", __func__, hlpe_state); + + if (ctx->had_interface) + ctx->had_interface->resume(ctx->had_pvt_data); +} + +void mid_hdmi_audio_signal_event(enum had_event_type event) +{ + struct hdmi_lpe_audio_ctx *ctx; + + dev_dbg(&hlpe_pdev->dev, "%s: Enter\n", __func__); + + ctx = platform_get_drvdata(hlpe_pdev); + + /* The handler is protected in the respective + * event handlers to avoid races + */ + if (ctx->had_event_callbacks) + (*ctx->had_event_callbacks)(event, + ctx->had_pvt_data); +} + +/** + * used to write into display controller HDMI audio registers. + */ +static int hdmi_audio_write(u32 reg, u32 val) +{ + struct hdmi_lpe_audio_ctx *ctx; + + ctx = platform_get_drvdata(hlpe_pdev); + + dev_dbg(&hlpe_pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, reg, val); + + iowrite32(val, (ctx->mmio_start+reg)); + + return 0; +} + +/** + * used to get the register value read from + * display controller HDMI audio registers. + */ +static int hdmi_audio_read(u32 reg, u32 *val) +{ + struct hdmi_lpe_audio_ctx *ctx; + + ctx = platform_get_drvdata(hlpe_pdev); + *val = ioread32(ctx->mmio_start+reg); + dev_dbg(&hlpe_pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, reg, *val); + return 0; +} + +/** + * used to update the masked bits in display controller HDMI + * audio registers. + */ +static int hdmi_audio_rmw(u32 reg, u32 val, u32 mask) +{ + struct hdmi_lpe_audio_ctx *ctx; + u32 val_tmp = 0; + + ctx = platform_get_drvdata(hlpe_pdev); + + val_tmp = (val & mask) | + ((ioread32(ctx->mmio_start + reg)) & ~mask); + + iowrite32(val_tmp, (ctx->mmio_start+reg)); + dev_dbg(&hlpe_pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, + reg, val_tmp); + + return 0; +} + +/** + * used to return the HDMI audio capabilities. + * e.g. resolution, frame rate. + */ +static int hdmi_audio_get_caps(enum had_caps_list get_element, + void *capabilities) +{ + struct hdmi_lpe_audio_ctx *ctx; + int ret = 0; + + ctx = get_hdmi_context(); + + dev_dbg(&hlpe_pdev->dev, "%s: Enter\n", __func__); + + switch (get_element) { + case HAD_GET_ELD: + ret = hdmi_get_eld(capabilities); + break; + case HAD_GET_DISPLAY_RATE: + /* ToDo: Verify if sampling freq logic is correct */ + *(u32 *)capabilities = ctx->tmds_clock_speed; + dev_dbg(&hlpe_pdev->dev, "%s: tmds_clock_speed = 0x%x\n", + __func__, ctx->tmds_clock_speed); + break; + default: + break; + } + + return ret; +} + +/** + * used to get the current hdmi base address + */ +int hdmi_audio_get_register_base(u32 **reg_base, + u32 *config_offset) +{ + struct hdmi_lpe_audio_ctx *ctx; + + ctx = platform_get_drvdata(hlpe_pdev); + *reg_base = (u32 *)(ctx->mmio_start); + *config_offset = ctx->had_config_offset; + dev_dbg(&hlpe_pdev->dev, "%s: reg_base = 0x%p, cfg_off = 0x%x\n", + __func__, *reg_base, *config_offset); + return 0; +} + +/** + * used to set the HDMI audio capabilities. + * e.g. Audio INT. + */ +int hdmi_audio_set_caps(enum had_caps_list set_element, + void *capabilties) +{ + struct hdmi_lpe_audio_ctx *ctx; + + ctx = platform_get_drvdata(hlpe_pdev); + + dev_dbg(&hlpe_pdev->dev, "%s: cap_id = 0x%x\n", __func__, set_element); + + switch (set_element) { + case HAD_SET_ENABLE_AUDIO_INT: + { + u32 status_reg; + + hdmi_audio_read(AUD_HDMI_STATUS_v2 + + ctx->had_config_offset, &status_reg); + status_reg |= + HDMI_AUDIO_BUFFER_DONE | HDMI_AUDIO_UNDERRUN; + hdmi_audio_write(AUD_HDMI_STATUS_v2 + + ctx->had_config_offset, status_reg); + hdmi_audio_read(AUD_HDMI_STATUS_v2 + + ctx->had_config_offset, &status_reg); + + } + break; + default: + break; + } + + return 0; +} + +static struct hdmi_audio_registers_ops hdmi_audio_reg_ops = { + .hdmi_audio_get_register_base = hdmi_audio_get_register_base, + .hdmi_audio_read_register = hdmi_audio_read, + .hdmi_audio_write_register = hdmi_audio_write, + .hdmi_audio_read_modify = hdmi_audio_rmw, +}; + +static struct hdmi_audio_query_set_ops hdmi_audio_get_set_ops = { + .hdmi_audio_get_caps = hdmi_audio_get_caps, + .hdmi_audio_set_caps = hdmi_audio_set_caps, +}; + +int mid_hdmi_audio_setup( + had_event_call_back audio_callbacks, + struct hdmi_audio_registers_ops *reg_ops, + struct hdmi_audio_query_set_ops *query_ops) +{ + struct hdmi_lpe_audio_ctx *ctx; + + ctx = platform_get_drvdata(hlpe_pdev); + + dev_dbg(&hlpe_pdev->dev, "%s: called\n", __func__); + + reg_ops->hdmi_audio_get_register_base = + (hdmi_audio_reg_ops.hdmi_audio_get_register_base); + reg_ops->hdmi_audio_read_register = + (hdmi_audio_reg_ops.hdmi_audio_read_register); + reg_ops->hdmi_audio_write_register = + (hdmi_audio_reg_ops.hdmi_audio_write_register); + reg_ops->hdmi_audio_read_modify = + (hdmi_audio_reg_ops.hdmi_audio_read_modify); + query_ops->hdmi_audio_get_caps = + hdmi_audio_get_set_ops.hdmi_audio_get_caps; + query_ops->hdmi_audio_set_caps = + hdmi_audio_get_set_ops.hdmi_audio_set_caps; + + ctx->had_event_callbacks = audio_callbacks; + + return 0; +} + +static void _had_wq(struct work_struct *work) +{ + mid_hdmi_audio_signal_event(HAD_EVENT_HOT_PLUG); +} + +int mid_hdmi_audio_register(struct snd_intel_had_interface *driver, + void *had_data) +{ + struct hdmi_lpe_audio_ctx *ctx; + + ctx = platform_get_drvdata(hlpe_pdev); + + dev_dbg(&hlpe_pdev->dev, "%s: called\n", __func__); + + ctx->had_pvt_data = had_data; + ctx->had_interface = driver; + + /* The Audio driver is loading now and we need to notify + * it if there is an HDMI device attached + */ + INIT_WORK(&ctx->hdmi_audio_wq, _had_wq); + dev_dbg(&hlpe_pdev->dev, "%s: Scheduling HDMI audio work queue\n", + __func__); + schedule_work(&ctx->hdmi_audio_wq); + + return 0; +} + +static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id) +{ + u32 audio_stat, audio_reg; + + struct hdmi_lpe_audio_ctx *ctx; + + dev_dbg(&hlpe_pdev->dev, "%s: Enter\n", __func__); + + ctx = platform_get_drvdata(hlpe_pdev); + + audio_reg = ctx->had_config_offset + AUD_HDMI_STATUS_v2; + hdmi_audio_read(audio_reg, &audio_stat); + + if (audio_stat & HDMI_AUDIO_UNDERRUN) { + hdmi_audio_write(audio_reg, HDMI_AUDIO_UNDERRUN); + mid_hdmi_audio_signal_event( + HAD_EVENT_AUDIO_BUFFER_UNDERRUN); + } + + if (audio_stat & HDMI_AUDIO_BUFFER_DONE) { + hdmi_audio_write(audio_reg, HDMI_AUDIO_BUFFER_DONE); + mid_hdmi_audio_signal_event( + HAD_EVENT_AUDIO_BUFFER_DONE); + } + + return IRQ_HANDLED; +} + +static void notify_audio_lpe(void *audio_ptr) +{ + struct hdmi_lpe_audio_ctx *ctx = get_hdmi_context(); + struct intel_hdmi_lpe_audio_pdata *pdata = hlpe_pdev->dev.platform_data; + struct intel_hdmi_lpe_audio_eld *eld = audio_ptr; + + if (pdata->hdmi_connected != true) { + + dev_dbg(&hlpe_pdev->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG\n", + __func__); + + if (hlpe_state == hdmi_connector_status_connected) { + + hlpe_state = + hdmi_connector_status_disconnected; + + mid_hdmi_audio_signal_event( + HAD_EVENT_HOT_UNPLUG); + } else + dev_dbg(&hlpe_pdev->dev, "%s: Already Unplugged!\n", + __func__); + + } else if (eld != NULL) { + + hdmi_set_eld(eld->eld_data); + + mid_hdmi_audio_signal_event(HAD_EVENT_HOT_PLUG); + + hlpe_state = hdmi_connector_status_connected; + + dev_dbg(&hlpe_pdev->dev, "%s: HAD_NOTIFY_ELD : port = %d, tmds = %d\n", + __func__, eld->port_id, pdata->tmds_clock_speed); + + if (pdata->tmds_clock_speed) { + ctx->tmds_clock_speed = pdata->tmds_clock_speed; + mid_hdmi_audio_signal_event(HAD_EVENT_MODE_CHANGING); + } + } else + dev_dbg(&hlpe_pdev->dev, "%s: Event: NULL EDID!!\n", __func__); +} + +/** + * hdmi_lpe_audio_probe - start bridge with i915 + * + * This function is called when the i915 driver creates the hdmi-lpe-audio + * platform device. Card creation is deferred until a hot plug event is + * received + */ +static int hdmi_lpe_audio_probe(struct platform_device *pdev) +{ + struct hdmi_lpe_audio_ctx *ctx; + struct intel_hdmi_lpe_audio_pdata *pdata; + int irq; + struct resource *res_mmio; + void __iomem *mmio_start; + int ret = 0; + unsigned long flag_irq; + static const struct pci_device_id cherryview_ids[] = { + {PCI_DEVICE(0x8086, 0x22b0)}, + {PCI_DEVICE(0x8086, 0x22b1)}, + {PCI_DEVICE(0x8086, 0x22b2)}, + {PCI_DEVICE(0x8086, 0x22b3)}, + {} + }; + + dev_dbg(&hlpe_pdev->dev, "Enter %s\n", __func__); + + /*TBD:remove globals*/ + hlpe_pdev = pdev; + hlpe_state = hdmi_connector_status_disconnected; + + /* get resources */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&hlpe_pdev->dev, "Could not get irq resource\n"); + return -ENODEV; + } + + res_mmio = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res_mmio) { + dev_err(&hlpe_pdev->dev, "Could not get IO_MEM resources\n"); + return -ENXIO; + } + + dev_dbg(&hlpe_pdev->dev, "%s: mmio_start = 0x%x, mmio_end = 0x%x\n", + __func__, (unsigned int)res_mmio->start, + (unsigned int)res_mmio->end); + + mmio_start = ioremap_nocache(res_mmio->start, + (size_t)((res_mmio->end - res_mmio->start) + + 1)); + if (!mmio_start) { + dev_err(&hlpe_pdev->dev, "Could not get ioremap\n"); + return -EACCES; + } + + /* setup interrupt handler */ + ret = request_irq(irq, display_pipe_interrupt_handler, + 0, + pdev->name, + NULL); + if (ret < 0) { + dev_err(&hlpe_pdev->dev, "request_irq failed\n"); + iounmap(mmio_start); + return -ENODEV; + } + + /* alloc and save context */ + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (ctx == NULL) { + free_irq(irq, NULL); + iounmap(mmio_start); + return -ENOMEM; + } + + ctx->irq = irq; + dev_dbg(&hlpe_pdev->dev, "hdmi lpe audio: irq num = %d\n", irq); + ctx->mmio_start = mmio_start; + ctx->tmds_clock_speed = DIS_SAMPLE_RATE_148_5; + + if (pci_dev_present(cherryview_ids)) { + dev_dbg(&hlpe_pdev->dev, "%s: Cherrytrail LPE - Detected\n", + __func__); + ctx->had_config_offset = AUDIO_HDMI_CONFIG_C; + } else { + dev_dbg(&hlpe_pdev->dev, "%s: Baytrail LPE - Assume\n", + __func__); + ctx->had_config_offset = AUDIO_HDMI_CONFIG_A; + } + + pdata = pdev->dev.platform_data; + + if (pdata == NULL) { + dev_err(&hlpe_pdev->dev, "%s: quit: pdata not allocated by i915!!\n", __func__); + kfree(ctx); + free_irq(irq, NULL); + iounmap(mmio_start); + return -ENOMEM; + } + + platform_set_drvdata(pdev, ctx); + + dev_dbg(&hlpe_pdev->dev, "hdmi lpe audio: setting pin eld notify callback\n"); + + spin_lock_irqsave(&pdata->lpe_audio_slock, flag_irq); + pdata->notify_audio_lpe = notify_audio_lpe; + + if (pdata->notify_pending) { + + dev_dbg(&hlpe_pdev->dev, "%s: handle pending notification\n", __func__); + notify_audio_lpe(&pdata->eld); + pdata->notify_pending = false; + } + spin_unlock_irqrestore(&pdata->lpe_audio_slock, flag_irq); + + return ret; +} + +/** + * hdmi_lpe_audio_remove - stop bridge with i915 + * + * This function is called when the platform device is destroyed. The sound + * card should have been removed on hot plug event. + */ +static int hdmi_lpe_audio_remove(struct platform_device *pdev) +{ + struct hdmi_lpe_audio_ctx *ctx; + + dev_dbg(&hlpe_pdev->dev, "Enter %s\n", __func__); + + /* get context, release resources */ + ctx = platform_get_drvdata(pdev); + iounmap(ctx->mmio_start); + free_irq(ctx->irq, NULL); + kfree(ctx); + return 0; +} + +static int hdmi_lpe_audio_suspend(struct platform_device *pt_dev, + pm_message_t state) +{ + dev_dbg(&hlpe_pdev->dev, "Enter %s\n", __func__); + mid_hdmi_audio_suspend(NULL); + return 0; +} + +static int hdmi_lpe_audio_resume(struct platform_device *pt_dev) +{ + dev_dbg(&hlpe_pdev->dev, "Enter %s\n", __func__); + mid_hdmi_audio_resume(NULL); + return 0; +} + +static struct platform_driver hdmi_lpe_audio_driver = { + .driver = { + .name = "hdmi-lpe-audio", + }, + .probe = hdmi_lpe_audio_probe, + .remove = hdmi_lpe_audio_remove, + .suspend = hdmi_lpe_audio_suspend, + .resume = hdmi_lpe_audio_resume +}; + +module_platform_driver(hdmi_lpe_audio_driver); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:hdmi_lpe_audio"); diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h new file mode 100644 index 000000000000..ec4bde50dba7 --- /dev/null +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -0,0 +1,683 @@ +/* + * intel_hdmi_lpe_audio.h - Intel HDMI LPE audio driver + * + * Copyright (C) 2016 Intel Corp + * Authors: Sailaja Bandarupalli + * Ramesh Babu K V + * Vaibhav Agarwal + * Jerome Anand + * Aravind Siddappaji + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +#ifndef __INTEL_HDMI_LPE_AUDIO_H +#define __INTEL_HDMI_LPE_AUDIO_H + +#include +#include +#include +#include +#include +#include +#include + +#define HMDI_LPE_AUDIO_DRIVER_NAME "intel-hdmi-lpe-audio" +#define HAD_MAX_DEVICES 1 +#define HAD_MIN_CHANNEL 2 +#define HAD_MAX_CHANNEL 8 +#define HAD_NUM_OF_RING_BUFS 4 + +/* Assume 192KHz, 8channel, 25msec period */ +#define HAD_MAX_BUFFER (600*1024) +#define HAD_MIN_BUFFER (32*1024) +#define HAD_MAX_PERIODS 4 +#define HAD_MIN_PERIODS 4 +#define HAD_MAX_PERIOD_BYTES (HAD_MAX_BUFFER/HAD_MIN_PERIODS) +#define HAD_MIN_PERIOD_BYTES 256 +#define HAD_FIFO_SIZE 0 /* fifo not being used */ +#define MAX_SPEAKERS 8 + +#define AUD_SAMPLE_RATE_32 32000 +#define AUD_SAMPLE_RATE_44_1 44100 +#define AUD_SAMPLE_RATE_48 48000 +#define AUD_SAMPLE_RATE_88_2 88200 +#define AUD_SAMPLE_RATE_96 96000 +#define AUD_SAMPLE_RATE_176_4 176400 +#define AUD_SAMPLE_RATE_192 192000 + +#define HAD_MIN_RATE AUD_SAMPLE_RATE_32 +#define HAD_MAX_RATE AUD_SAMPLE_RATE_192 + +#define DIS_SAMPLE_RATE_25_2 25200 +#define DIS_SAMPLE_RATE_27 27000 +#define DIS_SAMPLE_RATE_54 54000 +#define DIS_SAMPLE_RATE_74_25 74250 +#define DIS_SAMPLE_RATE_148_5 148500 +#define HAD_REG_WIDTH 0x08 +#define HAD_MAX_HW_BUFS 0x04 +#define HAD_MAX_DIP_WORDS 16 +#define INTEL_HAD "IntelHdmiLpeAudio" + +/* _AUD_CONFIG register MASK */ +#define AUD_CONFIG_MASK_UNDERRUN 0xC0000000 +#define AUD_CONFIG_MASK_SRDBG 0x00000002 +#define AUD_CONFIG_MASK_FUNCRST 0x00000001 + +#define MAX_CNT 0xFF +#define HAD_SUSPEND_DELAY 1000 + +#define OTM_HDMI_ELD_SIZE 128 + +union otm_hdmi_eld_t { + unsigned char eld_data[OTM_HDMI_ELD_SIZE]; + struct { + /* Byte[0] = ELD Version Number */ + union { + unsigned char byte0; + struct { + unsigned char reserved:3; /* Reserf */ + unsigned char eld_ver:5; /* ELD Version Number */ + /* 00000b - reserved + * 00001b - first rev, obsoleted + * 00010b - version 2, supporting CEA version + * 861D or below + * 00011b:11111b - reserved + * for future + */ + }; + }; + + /* Byte[1] = Vendor Version Field */ + union { + unsigned char vendor_version; + struct { + unsigned char reserved1:3; + unsigned char veld_ver:5; /* Version number of the ELD + * extension. This value is + * provisioned and unique to + * each vendor. + */ + }; + }; + + /* Byte[2] = Baseline Length field */ + unsigned char baseline_eld_length; /* Length of the Baseline structure + * divided by Four. + */ + + /* Byte [3] = Reserved for future use */ + unsigned char byte3; + + /* Starting of the BaseLine EELD structure + * Byte[4] = Monitor Name Length + */ + union { + unsigned char byte4; + struct { + unsigned char mnl:5; + unsigned char cea_edid_rev_id:3; + }; + }; + + /* Byte[5] = Capabilities */ + union { + unsigned char capabilities; + struct { + unsigned char hdcp:1; /* HDCP support */ + unsigned char ai_support:1; /* AI support */ + unsigned char connection_type:2; /* Connection type + * 00 - HDMI + * 01 - DP + * 10 -11 Reserved + * for future + * connection types + */ + unsigned char sadc:4; /* Indicates number of 3 bytes + * Short Audio Descriptors. + */ + }; + }; + + /* Byte[6] = Audio Synch Delay */ + unsigned char audio_synch_delay; /* Amount of time reported by the + * sink that the video trails audio + * in milliseconds. + */ + + /* Byte[7] = Speaker Allocation Block */ + union { + unsigned char speaker_allocation_block; + struct { + unsigned char flr:1; /*Front Left and Right channels*/ + unsigned char lfe:1; /*Low Frequency Effect channel*/ + unsigned char fc:1; /*Center transmission channel*/ + unsigned char rlr:1; /*Rear Left and Right channels*/ + unsigned char rc:1; /*Rear Center channel*/ + unsigned char flrc:1; /*Front left and Right of Center + *transmission channels + */ + unsigned char rlrc:1; /*Rear left and Right of Center + *transmission channels + */ + unsigned char reserved3:1; /* Reserved */ + }; + }; + + /* Byte[8 - 15] - 8 Byte port identification value */ + unsigned char port_id_value[8]; + + /* Byte[16 - 17] - 2 Byte Manufacturer ID */ + unsigned char manufacturer_id[2]; + + /* Byte[18 - 19] - 2 Byte Product ID */ + unsigned char product_id[2]; + + /* Byte [20-83] - 64 Bytes of BaseLine Data */ + unsigned char mn_sand_sads[64]; /* This will include + * - ASCII string of Monitor name + * - List of 3 byte SADs + * - Zero padding + */ + + /* Vendor ELD Block should continue here! + * No Vendor ELD block defined as of now. + */ + } __packed; +}; + +/** + * enum had_status - Audio stream states + * + * @STREAM_INIT: Stream initialized + * @STREAM_RUNNING: Stream running + * @STREAM_PAUSED: Stream paused + * @STREAM_DROPPED: Stream dropped + */ +enum had_stream_status { + STREAM_INIT = 0, + STREAM_RUNNING = 1, + STREAM_PAUSED = 2, + STREAM_DROPPED = 3 +}; + +/** + * enum had_status_stream - HAD stream states + */ +enum had_status_stream { + HAD_INIT = 0, + HAD_RUNNING_STREAM, +}; + +enum had_drv_status { + HAD_DRV_CONNECTED, + HAD_DRV_RUNNING, + HAD_DRV_DISCONNECTED, + HAD_DRV_SUSPENDED, + HAD_DRV_ERR, +}; + +/* enum intel_had_aud_buf_type - HDMI controller ring buffer types */ +enum intel_had_aud_buf_type { + HAD_BUF_TYPE_A = 0, + HAD_BUF_TYPE_B = 1, + HAD_BUF_TYPE_C = 2, + HAD_BUF_TYPE_D = 3, +}; + +enum num_aud_ch { + CH_STEREO = 0, + CH_THREE_FOUR = 1, + CH_FIVE_SIX = 2, + CH_SEVEN_EIGHT = 3 +}; + +/* HDMI Controller register offsets - audio domain common */ +/* Base address for below regs = 0x65000 */ +enum hdmi_ctrl_reg_offset_common { + AUDIO_HDMI_CONFIG_A = 0x000, + AUDIO_HDMI_CONFIG_B = 0x800, + AUDIO_HDMI_CONFIG_C = 0x900, +}; +/* HDMI controller register offsets */ +enum hdmi_ctrl_reg_offset_v1 { + AUD_CONFIG = 0x0, + AUD_CH_STATUS_0 = 0x08, + AUD_CH_STATUS_1 = 0x0C, + AUD_HDMI_CTS = 0x10, + AUD_N_ENABLE = 0x14, + AUD_SAMPLE_RATE = 0x18, + AUD_BUF_CONFIG = 0x20, + AUD_BUF_CH_SWAP = 0x24, + AUD_BUF_A_ADDR = 0x40, + AUD_BUF_A_LENGTH = 0x44, + AUD_BUF_B_ADDR = 0x48, + AUD_BUF_B_LENGTH = 0x4c, + AUD_BUF_C_ADDR = 0x50, + AUD_BUF_C_LENGTH = 0x54, + AUD_BUF_D_ADDR = 0x58, + AUD_BUF_D_LENGTH = 0x5c, + AUD_CNTL_ST = 0x60, + AUD_HDMI_STATUS = 0x68, + AUD_HDMIW_INFOFR = 0x114, +}; + +/* + * Delta changes in HDMI controller register offsets + * compare to v1 version + */ + +enum hdmi_ctrl_reg_offset_v2 { + AUD_HDMI_STATUS_v2 = 0x64, + AUD_HDMIW_INFOFR_v2 = 0x68, +}; + +/* + * CEA speaker placement: + * + * FL FLC FC FRC FR + * + * LFE + * + * RL RLC RC RRC RR + * + * The Left/Right Surround channel _notions_ LS/RS in SMPTE 320M + * corresponds to CEA RL/RR; The SMPTE channel _assignment_ C/LFE is + * swapped to CEA LFE/FC. + */ +enum cea_speaker_placement { + FL = (1 << 0), /* Front Left */ + FC = (1 << 1), /* Front Center */ + FR = (1 << 2), /* Front Right */ + FLC = (1 << 3), /* Front Left Center */ + FRC = (1 << 4), /* Front Right Center */ + RL = (1 << 5), /* Rear Left */ + RC = (1 << 6), /* Rear Center */ + RR = (1 << 7), /* Rear Right */ + RLC = (1 << 8), /* Rear Left Center */ + RRC = (1 << 9), /* Rear Right Center */ + LFE = (1 << 10), /* Low Frequency Effect */ +}; + +struct cea_channel_speaker_allocation { + int ca_index; + int speakers[8]; + + /* derived values, just for convenience */ + int channels; + int spk_mask; +}; + +struct channel_map_table { + unsigned char map; /* ALSA API channel map position */ + unsigned char cea_slot; /* CEA slot value */ + int spk_mask; /* speaker position bit mask */ +}; + +/** + * union aud_cfg - Audio configuration + * + * @cfg_regx: individual register bits + * @cfg_regval: full register value + * + */ +union aud_cfg { + struct { + u32 aud_en:1; + u32 layout:1; + u32 fmt:2; + u32 num_ch:2; + u32 rsvd0:1; + u32 set:1; + u32 flat:1; + u32 val_bit:1; + u32 user_bit:1; + u32 underrun:1; + u32 rsvd1:20; + } cfg_regx; + struct { + u32 aud_en:1; + u32 layout:1; + u32 fmt:2; + u32 num_ch:3; + u32 set:1; + u32 flat:1; + u32 val_bit:1; + u32 user_bit:1; + u32 underrun:1; + u32 packet_mode:1; + u32 left_align:1; + u32 bogus_sample:1; + u32 dp_modei:1; + u32 rsvd:16; + } cfg_regx_v2; + u32 cfg_regval; +}; + +/** + * union aud_ch_status_0 - Audio Channel Status 0 Attributes + * + * @status_0_regx:individual register bits + * @status_0_regval:full register value + * + */ +union aud_ch_status_0 { + struct { + u32 ch_status:1; + u32 lpcm_id:1; + u32 cp_info:1; + u32 format:3; + u32 mode:2; + u32 ctg_code:8; + u32 src_num:4; + u32 ch_num:4; + u32 samp_freq:4; + u32 clk_acc:2; + u32 rsvd:2; + } status_0_regx; + u32 status_0_regval; +}; + +/** + * union aud_ch_status_1 - Audio Channel Status 1 Attributes + * + * @status_1_regx: individual register bits + * @status_1_regval: full register value + * + */ +union aud_ch_status_1 { + struct { + u32 max_wrd_len:1; + u32 wrd_len:3; + u32 rsvd:28; + } status_1_regx; + u32 status_1_regval; +}; + +/** + * union aud_hdmi_cts - CTS register + * + * @cts_regx: individual register bits + * @cts_regval: full register value + * + */ +union aud_hdmi_cts { + struct { + u32 cts_val:20; + u32 en_cts_prog:1; + u32 rsvd:11; + } cts_regx; + struct { + u32 cts_val:24; + u32 en_cts_prog:1; + u32 rsvd:7; + } cts_regx_v2; + u32 cts_regval; +}; + +/** + * union aud_hdmi_n_enable - N register + * + * @n_regx: individual register bits + * @n_regval: full register value + * + */ +union aud_hdmi_n_enable { + struct { + u32 n_val:20; + u32 en_n_prog:1; + u32 rsvd:11; + } n_regx; + struct { + u32 n_val:24; + u32 en_n_prog:1; + u32 rsvd:7; + } n_regx_v2; + u32 n_regval; +}; + +/** + * union aud_buf_config - Audio Buffer configurations + * + * @buf_cfg_regx: individual register bits + * @buf_cfgval: full register value + * + */ +union aud_buf_config { + struct { + u32 fifo_width:8; + u32 rsvd0:8; + u32 aud_delay:8; + u32 rsvd1:8; + } buf_cfg_regx; + struct { + u32 audio_fifo_watermark:8; + u32 dma_fifo_watermark:3; + u32 rsvd0:5; + u32 aud_delay:8; + u32 rsvd1:8; + } buf_cfg_regx_v2; + u32 buf_cfgval; +}; + +/** + * union aud_buf_ch_swap - Audio Sample Swapping offset + * + * @buf_ch_swap_regx: individual register bits + * @buf_ch_swap_val: full register value + * + */ +union aud_buf_ch_swap { + struct { + u32 first_0:3; + u32 second_0:3; + u32 first_1:3; + u32 second_1:3; + u32 first_2:3; + u32 second_2:3; + u32 first_3:3; + u32 second_3:3; + u32 rsvd:8; + } buf_ch_swap_regx; + u32 buf_ch_swap_val; +}; + +/** + * union aud_buf_addr - Address for Audio Buffer + * + * @buf_addr_regx: individual register bits + * @buf_addr_val: full register value + * + */ +union aud_buf_addr { + struct { + u32 valid:1; + u32 intr_en:1; + u32 rsvd:4; + u32 addr:26; + } buf_addr_regx; + u32 buf_addr_val; +}; + +/** + * union aud_buf_len - Length of Audio Buffer + * + * @buf_len_regx: individual register bits + * @buf_len_val: full register value + * + */ +union aud_buf_len { + struct { + u32 buf_len:20; + u32 rsvd:12; + } buf_len_regx; + u32 buf_len_val; +}; + +/** + * union aud_ctrl_st - Audio Control State Register offset + * + * @ctrl_regx: individual register bits + * @ctrl_val: full register value + * + */ +union aud_ctrl_st { + struct { + u32 ram_addr:4; + u32 eld_ack:1; + u32 eld_addr:4; + u32 eld_buf_size:5; + u32 eld_valid:1; + u32 cp_ready:1; + u32 dip_freq:2; + u32 dip_idx:3; + u32 dip_en_sta:4; + u32 rsvd:7; + } ctrl_regx; + u32 ctrl_val; +}; + +/** + * union aud_info_frame1 - Audio HDMI Widget Data Island Packet offset + * + * @fr1_regx: individual register bits + * @fr1_val: full register value + * + */ +union aud_info_frame1 { + struct { + u32 pkt_type:8; + u32 ver_num:8; + u32 len:5; + u32 rsvd:11; + } fr1_regx; + u32 fr1_val; +}; + +/** + * union aud_info_frame2 - DIP frame 2 + * + * @fr2_regx: individual register bits + * @fr2_val: full register value + * + */ +union aud_info_frame2 { + struct { + u32 chksum:8; + u32 chnl_cnt:3; + u32 rsvd0:1; + u32 coding_type:4; + u32 smpl_size:2; + u32 smpl_freq:3; + u32 rsvd1:3; + u32 format:8; + } fr2_regx; + u32 fr2_val; +}; + +/** + * union aud_info_frame3 - DIP frame 3 + * + * @fr3_regx: individual register bits + * @fr3_val: full register value + * + */ +union aud_info_frame3 { + struct { + u32 chnl_alloc:8; + u32 rsvd0:3; + u32 lsv:4; + u32 dm_inh:1; + u32 rsvd1:16; + } fr3_regx; + u32 fr3_val; +}; + +enum hdmi_connector_status { + hdmi_connector_status_connected = 1, + hdmi_connector_status_disconnected = 2, + hdmi_connector_status_unknown = 3, +}; + +#define HDMI_AUDIO_UNDERRUN (1UL<<31) +#define HDMI_AUDIO_BUFFER_DONE (1UL<<29) + + +#define PORT_ENABLE (1 << 31) +#define SDVO_AUDIO_ENABLE (1 << 6) + +enum had_caps_list { + HAD_GET_ELD = 1, + HAD_GET_DISPLAY_RATE, + HAD_SET_ENABLE_AUDIO, + HAD_SET_DISABLE_AUDIO, + HAD_SET_ENABLE_AUDIO_INT, + HAD_SET_DISABLE_AUDIO_INT, +}; + +enum had_event_type { + HAD_EVENT_HOT_PLUG = 1, + HAD_EVENT_HOT_UNPLUG, + HAD_EVENT_MODE_CHANGING, + HAD_EVENT_AUDIO_BUFFER_DONE, + HAD_EVENT_AUDIO_BUFFER_UNDERRUN, + HAD_EVENT_QUERY_IS_AUDIO_BUSY, + HAD_EVENT_QUERY_IS_AUDIO_SUSPENDED, +}; + +/* + * HDMI Display Controller Audio Interface + * + */ +typedef int (*had_event_call_back) (enum had_event_type event_type, + void *ctxt_info); + +struct hdmi_audio_registers_ops { + int (*hdmi_audio_get_register_base)(u32 **reg_base, + u32 *config_offset); + int (*hdmi_audio_read_register)(u32 reg_addr, u32 *data); + int (*hdmi_audio_write_register)(u32 reg_addr, u32 data); + int (*hdmi_audio_read_modify)(u32 reg_addr, u32 data, + u32 mask); +}; + +struct hdmi_audio_query_set_ops { + int (*hdmi_audio_get_caps)(enum had_caps_list query_element, + void *capabilties); + int (*hdmi_audio_set_caps)(enum had_caps_list set_element, + void *capabilties); +}; + +struct hdmi_audio_event { + int type; +}; + +struct snd_intel_had_interface { + const char *name; + int (*query)(void *had_data, struct hdmi_audio_event event); + int (*suspend)(void *had_data, struct hdmi_audio_event event); + int (*resume)(void *had_data); +}; + +bool mid_hdmi_audio_is_busy(void *dev); +bool mid_hdmi_audio_suspend(void *dev); +void mid_hdmi_audio_resume(void *dev); +void mid_hdmi_audio_signal_event(enum had_event_type event); +int mid_hdmi_audio_setup( + had_event_call_back audio_callbacks, + struct hdmi_audio_registers_ops *reg_ops, + struct hdmi_audio_query_set_ops *query_ops); +int mid_hdmi_audio_register( + struct snd_intel_had_interface *driver, + void *had_data); + +#endif -- cgit v1.2.3 From 5dab11d89777230b3ff38f19ee1b6fbba9688b23 Mon Sep 17 00:00:00 2001 From: Jerome Anand Date: Wed, 25 Jan 2017 04:27:52 +0530 Subject: ALSA: x86: hdmi: Add audio support for BYT and CHT Hdmi audio driver based on the child platform device created by gfx driver is implemented. This audio driver is derived from legacy intel hdmi audio driver. The interfaces for interaction between gfx and audio are updated and the driver implementation updated to derive interrupts in its own address space based on irq chip framework The changes to calculate sub-period positions was triggered by David Henningsson and is accomodated in this patch Signed-off-by: Pierre-Louis Bossart Signed-off-by: Jerome Anand Signed-off-by: Takashi Iwai --- sound/x86/Makefile | 2 + sound/x86/intel_hdmi_audio.c | 1855 ++++++++++++++++++++++++++++++++++++++ sound/x86/intel_hdmi_audio.h | 197 ++++ sound/x86/intel_hdmi_audio_if.c | 551 +++++++++++ sound/x86/intel_hdmi_lpe_audio.c | 15 +- 5 files changed, 2614 insertions(+), 6 deletions(-) create mode 100644 sound/x86/intel_hdmi_audio.c create mode 100644 sound/x86/intel_hdmi_audio.h create mode 100644 sound/x86/intel_hdmi_audio_if.c diff --git a/sound/x86/Makefile b/sound/x86/Makefile index 9b87384c17c5..85ea22a2cf28 100644 --- a/sound/x86/Makefile +++ b/sound/x86/Makefile @@ -1,4 +1,6 @@ snd-hdmi-lpe-audio-objs += \ + intel_hdmi_audio.o \ + intel_hdmi_audio_if.o \ intel_hdmi_lpe_audio.o obj-$(CONFIG_HDMI_LPE_AUDIO) += snd-hdmi-lpe-audio.o diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c new file mode 100644 index 000000000000..b69521aa2ed1 --- /dev/null +++ b/sound/x86/intel_hdmi_audio.c @@ -0,0 +1,1855 @@ +/* + * intel_hdmi_audio.c - Intel HDMI audio driver + * + * Copyright (C) 2016 Intel Corp + * Authors: Sailaja Bandarupalli + * Ramesh Babu K V + * Vaibhav Agarwal + * Jerome Anand + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * ALSA driver for Intel HDMI audio + */ + +#define pr_fmt(fmt) "had: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "intel_hdmi_audio.h" + +static DEFINE_MUTEX(had_mutex); + +/*standard module options for ALSA. This module supports only one card*/ +static int hdmi_card_index = SNDRV_DEFAULT_IDX1; +static char *hdmi_card_id = SNDRV_DEFAULT_STR1; +static struct snd_intelhad *had_data; + +module_param_named(index, hdmi_card_index, int, 0444); +MODULE_PARM_DESC(index, + "Index value for INTEL Intel HDMI Audio controller."); +module_param_named(id, hdmi_card_id, charp, 0444); +MODULE_PARM_DESC(id, + "ID string for INTEL Intel HDMI Audio controller."); + +/* + * ELD SA bits in the CEA Speaker Allocation data block + */ +static int eld_speaker_allocation_bits[] = { + [0] = FL | FR, + [1] = LFE, + [2] = FC, + [3] = RL | RR, + [4] = RC, + [5] = FLC | FRC, + [6] = RLC | RRC, + /* the following are not defined in ELD yet */ + [7] = 0, +}; + +/* + * This is an ordered list! + * + * The preceding ones have better chances to be selected by + * hdmi_channel_allocation(). + */ +static struct cea_channel_speaker_allocation channel_allocations[] = { +/* channel: 7 6 5 4 3 2 1 0 */ +{ .ca_index = 0x00, .speakers = { 0, 0, 0, 0, 0, 0, FR, FL } }, + /* 2.1 */ +{ .ca_index = 0x01, .speakers = { 0, 0, 0, 0, 0, LFE, FR, FL } }, + /* Dolby Surround */ +{ .ca_index = 0x02, .speakers = { 0, 0, 0, 0, FC, 0, FR, FL } }, + /* surround40 */ +{ .ca_index = 0x08, .speakers = { 0, 0, RR, RL, 0, 0, FR, FL } }, + /* surround41 */ +{ .ca_index = 0x09, .speakers = { 0, 0, RR, RL, 0, LFE, FR, FL } }, + /* surround50 */ +{ .ca_index = 0x0a, .speakers = { 0, 0, RR, RL, FC, 0, FR, FL } }, + /* surround51 */ +{ .ca_index = 0x0b, .speakers = { 0, 0, RR, RL, FC, LFE, FR, FL } }, + /* 6.1 */ +{ .ca_index = 0x0f, .speakers = { 0, RC, RR, RL, FC, LFE, FR, FL } }, + /* surround71 */ +{ .ca_index = 0x13, .speakers = { RRC, RLC, RR, RL, FC, LFE, FR, FL } }, + +{ .ca_index = 0x03, .speakers = { 0, 0, 0, 0, FC, LFE, FR, FL } }, +{ .ca_index = 0x04, .speakers = { 0, 0, 0, RC, 0, 0, FR, FL } }, +{ .ca_index = 0x05, .speakers = { 0, 0, 0, RC, 0, LFE, FR, FL } }, +{ .ca_index = 0x06, .speakers = { 0, 0, 0, RC, FC, 0, FR, FL } }, +{ .ca_index = 0x07, .speakers = { 0, 0, 0, RC, FC, LFE, FR, FL } }, +{ .ca_index = 0x0c, .speakers = { 0, RC, RR, RL, 0, 0, FR, FL } }, +{ .ca_index = 0x0d, .speakers = { 0, RC, RR, RL, 0, LFE, FR, FL } }, +{ .ca_index = 0x0e, .speakers = { 0, RC, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x10, .speakers = { RRC, RLC, RR, RL, 0, 0, FR, FL } }, +{ .ca_index = 0x11, .speakers = { RRC, RLC, RR, RL, 0, LFE, FR, FL } }, +{ .ca_index = 0x12, .speakers = { RRC, RLC, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x14, .speakers = { FRC, FLC, 0, 0, 0, 0, FR, FL } }, +{ .ca_index = 0x15, .speakers = { FRC, FLC, 0, 0, 0, LFE, FR, FL } }, +{ .ca_index = 0x16, .speakers = { FRC, FLC, 0, 0, FC, 0, FR, FL } }, +{ .ca_index = 0x17, .speakers = { FRC, FLC, 0, 0, FC, LFE, FR, FL } }, +{ .ca_index = 0x18, .speakers = { FRC, FLC, 0, RC, 0, 0, FR, FL } }, +{ .ca_index = 0x19, .speakers = { FRC, FLC, 0, RC, 0, LFE, FR, FL } }, +{ .ca_index = 0x1a, .speakers = { FRC, FLC, 0, RC, FC, 0, FR, FL } }, +{ .ca_index = 0x1b, .speakers = { FRC, FLC, 0, RC, FC, LFE, FR, FL } }, +{ .ca_index = 0x1c, .speakers = { FRC, FLC, RR, RL, 0, 0, FR, FL } }, +{ .ca_index = 0x1d, .speakers = { FRC, FLC, RR, RL, 0, LFE, FR, FL } }, +{ .ca_index = 0x1e, .speakers = { FRC, FLC, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x1f, .speakers = { FRC, FLC, RR, RL, FC, LFE, FR, FL } }, +}; + +static struct channel_map_table map_tables[] = { + { SNDRV_CHMAP_FL, 0x00, FL }, + { SNDRV_CHMAP_FR, 0x01, FR }, + { SNDRV_CHMAP_RL, 0x04, RL }, + { SNDRV_CHMAP_RR, 0x05, RR }, + { SNDRV_CHMAP_LFE, 0x02, LFE }, + { SNDRV_CHMAP_FC, 0x03, FC }, + { SNDRV_CHMAP_RLC, 0x06, RLC }, + { SNDRV_CHMAP_RRC, 0x07, RRC }, + {} /* terminator */ +}; + +/* hardware capability structure */ +static const struct snd_pcm_hardware snd_intel_hadstream = { + .info = (SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_DOUBLE | + SNDRV_PCM_INFO_MMAP| + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_BATCH), + .formats = (SNDRV_PCM_FMTBIT_S24 | + SNDRV_PCM_FMTBIT_U24), + .rates = SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_176400 | + SNDRV_PCM_RATE_192000, + .rate_min = HAD_MIN_RATE, + .rate_max = HAD_MAX_RATE, + .channels_min = HAD_MIN_CHANNEL, + .channels_max = HAD_MAX_CHANNEL, + .buffer_bytes_max = HAD_MAX_BUFFER, + .period_bytes_min = HAD_MIN_PERIOD_BYTES, + .period_bytes_max = HAD_MAX_PERIOD_BYTES, + .periods_min = HAD_MIN_PERIODS, + .periods_max = HAD_MAX_PERIODS, + .fifo_size = HAD_FIFO_SIZE, +}; + +/* Register access functions */ + +int had_get_hwstate(struct snd_intelhad *intelhaddata) +{ + /* Check for device presence -SW state */ + if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { + pr_debug("%s:Device not connected:%d\n", __func__, + intelhaddata->drv_status); + return -ENODEV; + } + + return 0; +} + +int had_get_caps(enum had_caps_list query, void *caps) +{ + int retval; + struct snd_intelhad *intelhaddata = had_data; + + retval = had_get_hwstate(intelhaddata); + if (!retval) + retval = intelhaddata->query_ops.hdmi_audio_get_caps(query, + caps); + + return retval; +} + +int had_set_caps(enum had_caps_list set_element, void *caps) +{ + int retval; + struct snd_intelhad *intelhaddata = had_data; + + retval = had_get_hwstate(intelhaddata); + if (!retval) + retval = intelhaddata->query_ops.hdmi_audio_set_caps( + set_element, caps); + + return retval; +} + +int had_read_register(u32 offset, u32 *data) +{ + int retval; + struct snd_intelhad *intelhaddata = had_data; + + retval = had_get_hwstate(intelhaddata); + if (!retval) + retval = intelhaddata->reg_ops.hdmi_audio_read_register( + offset + intelhaddata->audio_cfg_offset, data); + + return retval; +} + +int had_write_register(u32 offset, u32 data) +{ + int retval; + struct snd_intelhad *intelhaddata = had_data; + + retval = had_get_hwstate(intelhaddata); + if (!retval) + retval = intelhaddata->reg_ops.hdmi_audio_write_register( + offset + intelhaddata->audio_cfg_offset, data); + + return retval; +} + +int had_read_modify(u32 offset, u32 data, u32 mask) +{ + int retval; + struct snd_intelhad *intelhaddata = had_data; + + retval = had_get_hwstate(intelhaddata); + if (!retval) + retval = intelhaddata->reg_ops.hdmi_audio_read_modify( + offset + intelhaddata->audio_cfg_offset, + data, mask); + + return retval; +} +/** + * function to read-modify + * AUD_CONFIG register on VLV2.The had_read_modify() function should not + * directly be used on VLV2 for updating AUD_CONFIG register. + * This is because: + * Bit6 of AUD_CONFIG register is writeonly due to a silicon bug on VLV2 + * HDMI IP. As a result a read-modify of AUD_CONFIG regiter will always + * clear bit6. AUD_CONFIG[6:4] represents the "channels" field of the + * register. This field should be 1xy binary for configuration with 6 or + * more channels. Read-modify of AUD_CONFIG (Eg. for enabling audio) + * causes the "channels" field to be updated as 0xy binary resulting in + * bad audio. The fix is to always write the AUD_CONFIG[6:4] with + * appropriate value when doing read-modify of AUD_CONFIG register. + * + * @substream: the current substream or NULL if no active substream + * @data : data to be written + * @mask : mask + * + */ +static int had_read_modify_aud_config_v2(struct snd_pcm_substream *substream, + u32 data, u32 mask) +{ + union aud_cfg cfg_val = {.cfg_regval = 0}; + u8 channels; + + /* + * If substream is NULL, there is no active stream. + * In this case just set channels to 2 + */ + if (substream) + channels = substream->runtime->channels; + else + channels = 2; + cfg_val.cfg_regx_v2.num_ch = channels - 2; + + data = data | cfg_val.cfg_regval; + mask = mask | AUD_CONFIG_CH_MASK_V2; + + pr_debug("%s : data = %x, mask =%x\n", __func__, data, mask); + + return had_read_modify(AUD_CONFIG, data, mask); +} + +static void snd_intelhad_enable_audio_v1(struct snd_pcm_substream *substream, + u8 enable) +{ + had_read_modify(AUD_CONFIG, enable, BIT(0)); +} + +static void snd_intelhad_enable_audio_v2(struct snd_pcm_substream *substream, + u8 enable) +{ + had_read_modify_aud_config_v2(substream, enable, BIT(0)); +} + +static void snd_intelhad_reset_audio_v1(u8 reset) +{ + had_write_register(AUD_HDMI_STATUS, reset); +} + +static void snd_intelhad_reset_audio_v2(u8 reset) +{ + had_write_register(AUD_HDMI_STATUS_v2, reset); +} + +/** + * initialize audio channel status registers + * This function is called in the prepare callback + */ +static int had_prog_status_reg(struct snd_pcm_substream *substream, + struct snd_intelhad *intelhaddata) +{ + union aud_cfg cfg_val = {.cfg_regval = 0}; + union aud_ch_status_0 ch_stat0 = {.status_0_regval = 0}; + union aud_ch_status_1 ch_stat1 = {.status_1_regval = 0}; + int format; + + pr_debug("Entry %s\n", __func__); + + ch_stat0.status_0_regx.lpcm_id = (intelhaddata->aes_bits & + IEC958_AES0_NONAUDIO)>>1; + ch_stat0.status_0_regx.clk_acc = (intelhaddata->aes_bits & + IEC958_AES3_CON_CLOCK)>>4; + cfg_val.cfg_regx.val_bit = ch_stat0.status_0_regx.lpcm_id; + + switch (substream->runtime->rate) { + case AUD_SAMPLE_RATE_32: + ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_32KHZ; + break; + + case AUD_SAMPLE_RATE_44_1: + ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_44KHZ; + break; + case AUD_SAMPLE_RATE_48: + ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_48KHZ; + break; + case AUD_SAMPLE_RATE_88_2: + ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_88KHZ; + break; + case AUD_SAMPLE_RATE_96: + ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_96KHZ; + break; + case AUD_SAMPLE_RATE_176_4: + ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_176KHZ; + break; + case AUD_SAMPLE_RATE_192: + ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_192KHZ; + break; + + default: + /* control should never come here */ + return -EINVAL; + break; + + } + had_write_register(AUD_CH_STATUS_0, ch_stat0.status_0_regval); + + format = substream->runtime->format; + + if (format == SNDRV_PCM_FORMAT_S16_LE) { + ch_stat1.status_1_regx.max_wrd_len = MAX_SMPL_WIDTH_20; + ch_stat1.status_1_regx.wrd_len = SMPL_WIDTH_16BITS; + } else if (format == SNDRV_PCM_FORMAT_S24_LE) { + ch_stat1.status_1_regx.max_wrd_len = MAX_SMPL_WIDTH_24; + ch_stat1.status_1_regx.wrd_len = SMPL_WIDTH_24BITS; + } else { + ch_stat1.status_1_regx.max_wrd_len = 0; + ch_stat1.status_1_regx.wrd_len = 0; + } + had_write_register(AUD_CH_STATUS_1, ch_stat1.status_1_regval); + return 0; +} + +/** + * function to initialize audio + * registers and buffer confgiuration registers + * This function is called in the prepare callback + */ +static int snd_intelhad_prog_audio_ctrl_v2(struct snd_pcm_substream *substream, + struct snd_intelhad *intelhaddata) +{ + union aud_cfg cfg_val = {.cfg_regval = 0}; + union aud_buf_config buf_cfg = {.buf_cfgval = 0}; + u8 channels; + + had_prog_status_reg(substream, intelhaddata); + + buf_cfg.buf_cfg_regx_v2.audio_fifo_watermark = FIFO_THRESHOLD; + buf_cfg.buf_cfg_regx_v2.dma_fifo_watermark = DMA_FIFO_THRESHOLD; + buf_cfg.buf_cfg_regx_v2.aud_delay = 0; + had_write_register(AUD_BUF_CONFIG, buf_cfg.buf_cfgval); + + channels = substream->runtime->channels; + cfg_val.cfg_regx_v2.num_ch = channels - 2; + if (channels <= 2) + cfg_val.cfg_regx_v2.layout = LAYOUT0; + else + cfg_val.cfg_regx_v2.layout = LAYOUT1; + + had_write_register(AUD_CONFIG, cfg_val.cfg_regval); + return 0; +} + +/** + * function to initialize audio + * registers and buffer confgiuration registers + * This function is called in the prepare callback + */ +static int snd_intelhad_prog_audio_ctrl_v1(struct snd_pcm_substream *substream, + struct snd_intelhad *intelhaddata) +{ + union aud_cfg cfg_val = {.cfg_regval = 0}; + union aud_buf_config buf_cfg = {.buf_cfgval = 0}; + u8 channels; + + had_prog_status_reg(substream, intelhaddata); + + buf_cfg.buf_cfg_regx.fifo_width = FIFO_THRESHOLD; + buf_cfg.buf_cfg_regx.aud_delay = 0; + had_write_register(AUD_BUF_CONFIG, buf_cfg.buf_cfgval); + + channels = substream->runtime->channels; + + switch (channels) { + case 1: + case 2: + cfg_val.cfg_regx.num_ch = CH_STEREO; + cfg_val.cfg_regx.layout = LAYOUT0; + break; + + case 3: + case 4: + cfg_val.cfg_regx.num_ch = CH_THREE_FOUR; + cfg_val.cfg_regx.layout = LAYOUT1; + break; + + case 5: + case 6: + cfg_val.cfg_regx.num_ch = CH_FIVE_SIX; + cfg_val.cfg_regx.layout = LAYOUT1; + break; + + case 7: + case 8: + cfg_val.cfg_regx.num_ch = CH_SEVEN_EIGHT; + cfg_val.cfg_regx.layout = LAYOUT1; + break; + + } + + had_write_register(AUD_CONFIG, cfg_val.cfg_regval); + return 0; +} + +/* + * Compute derived values in channel_allocations[]. + */ +static void init_channel_allocations(void) +{ + int i, j; + struct cea_channel_speaker_allocation *p; + + pr_debug("%s: Enter\n", __func__); + + for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { + p = channel_allocations + i; + p->channels = 0; + p->spk_mask = 0; + for (j = 0; j < ARRAY_SIZE(p->speakers); j++) + if (p->speakers[j]) { + p->channels++; + p->spk_mask |= p->speakers[j]; + } + } +} + +/* + * The transformation takes two steps: + * + * eld->spk_alloc => (eld_speaker_allocation_bits[]) => spk_mask + * spk_mask => (channel_allocations[]) => ai->CA + * + * TODO: it could select the wrong CA from multiple candidates. + */ +static int snd_intelhad_channel_allocation(struct snd_intelhad *intelhaddata, + int channels) +{ + int i; + int ca = 0; + int spk_mask = 0; + + /* + * CA defaults to 0 for basic stereo audio + */ + if (channels <= 2) + return 0; + + /* + * expand ELD's speaker allocation mask + * + * ELD tells the speaker mask in a compact(paired) form, + * expand ELD's notions to match the ones used by Audio InfoFrame. + */ + + for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) { + if (intelhaddata->eeld.speaker_allocation_block & (1 << i)) + spk_mask |= eld_speaker_allocation_bits[i]; + } + + /* search for the first working match in the CA table */ + for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { + if (channels == channel_allocations[i].channels && + (spk_mask & channel_allocations[i].spk_mask) == + channel_allocations[i].spk_mask) { + ca = channel_allocations[i].ca_index; + break; + } + } + + pr_debug("HDMI: select CA 0x%x for %d\n", ca, channels); + + return ca; +} + +/* from speaker bit mask to ALSA API channel position */ +static int spk_to_chmap(int spk) +{ + struct channel_map_table *t = map_tables; + + for (; t->map; t++) { + if (t->spk_mask == spk) + return t->map; + } + return 0; +} + +void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata) +{ + int i = 0, c = 0; + int spk_mask = 0; + struct snd_pcm_chmap_elem *chmap; + u8 eld_high, eld_high_mask = 0xF0; + u8 high_msb; + + chmap = kzalloc(sizeof(*chmap), GFP_KERNEL); + if (chmap == NULL) { + intelhaddata->chmap->chmap = NULL; + return; + } + + had_get_caps(HAD_GET_ELD, &intelhaddata->eeld); + + pr_debug("eeld.speaker_allocation_block = %x\n", + intelhaddata->eeld.speaker_allocation_block); + + /* WA: Fix the max channel supported to 8 */ + + /* + * Sink may support more than 8 channels, if eld_high has more than + * one bit set. SOC supports max 8 channels. + * Refer eld_speaker_allocation_bits, for sink speaker allocation + */ + + /* if 0x2F < eld < 0x4F fall back to 0x2f, else fall back to 0x4F */ + eld_high = intelhaddata->eeld.speaker_allocation_block & eld_high_mask; + if ((eld_high & (eld_high-1)) && (eld_high > 0x1F)) { + /* eld_high & (eld_high-1): if more than 1 bit set */ + /* 0x1F: 7 channels */ + for (i = 1; i < 4; i++) { + high_msb = eld_high & (0x80 >> i); + if (high_msb) { + intelhaddata->eeld.speaker_allocation_block &= + high_msb | 0xF; + break; + } + } + } + + for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) { + if (intelhaddata->eeld.speaker_allocation_block & (1 << i)) + spk_mask |= eld_speaker_allocation_bits[i]; + } + + for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { + if (spk_mask == channel_allocations[i].spk_mask) { + for (c = 0; c < channel_allocations[i].channels; c++) { + chmap->map[c] = spk_to_chmap( + channel_allocations[i].speakers[ + (MAX_SPEAKERS - 1)-c]); + } + chmap->channels = channel_allocations[i].channels; + intelhaddata->chmap->chmap = chmap; + break; + } + } + if (i >= ARRAY_SIZE(channel_allocations)) { + intelhaddata->chmap->chmap = NULL; + kfree(chmap); + } +} + +/* + * ALSA API channel-map control callbacks + */ +static int had_chmap_ctl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); + struct snd_intelhad *intelhaddata = info->private_data; + + if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) + return -ENODEV; + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = HAD_MAX_CHANNEL; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = SNDRV_CHMAP_LAST; + return 0; +} + +static int had_chmap_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); + struct snd_intelhad *intelhaddata = info->private_data; + int i = 0; + const struct snd_pcm_chmap_elem *chmap; + + if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) + return -ENODEV; + if (intelhaddata->chmap->chmap == NULL) + return -ENODATA; + chmap = intelhaddata->chmap->chmap; + for (i = 0; i < chmap->channels; i++) { + ucontrol->value.integer.value[i] = chmap->map[i]; + pr_debug("chmap->map[%d] = %d\n", i, chmap->map[i]); + } + + return 0; +} + +static int had_register_chmap_ctls(struct snd_intelhad *intelhaddata, + struct snd_pcm *pcm) +{ + int err = 0; + + err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, + NULL, 0, (unsigned long)intelhaddata, + &intelhaddata->chmap); + if (err < 0) + return err; + + intelhaddata->chmap->private_data = intelhaddata; + intelhaddata->kctl = intelhaddata->chmap->kctl; + intelhaddata->kctl->info = had_chmap_ctl_info; + intelhaddata->kctl->get = had_chmap_ctl_get; + intelhaddata->chmap->chmap = NULL; + return 0; +} + +/** + * snd_intelhad_prog_dip_v1 - to initialize Data Island Packets registers + * + * @substream:substream for which the prepare function is called + * @intelhaddata:substream private data + * + * This function is called in the prepare callback + */ +static void snd_intelhad_prog_dip_v1(struct snd_pcm_substream *substream, + struct snd_intelhad *intelhaddata) +{ + int i; + union aud_ctrl_st ctrl_state = {.ctrl_val = 0}; + union aud_info_frame2 frame2 = {.fr2_val = 0}; + union aud_info_frame3 frame3 = {.fr3_val = 0}; + u8 checksum = 0; + int channels; + + channels = substream->runtime->channels; + + had_write_register(AUD_CNTL_ST, ctrl_state.ctrl_val); + + frame2.fr2_regx.chnl_cnt = substream->runtime->channels - 1; + + frame3.fr3_regx.chnl_alloc = snd_intelhad_channel_allocation( + intelhaddata, channels); + + /*Calculte the byte wide checksum for all valid DIP words*/ + for (i = 0; i < BYTES_PER_WORD; i++) + checksum += (INFO_FRAME_WORD1 >> i*BITS_PER_BYTE) & MASK_BYTE0; + for (i = 0; i < BYTES_PER_WORD; i++) + checksum += (frame2.fr2_val >> i*BITS_PER_BYTE) & MASK_BYTE0; + for (i = 0; i < BYTES_PER_WORD; i++) + checksum += (frame3.fr3_val >> i*BITS_PER_BYTE) & MASK_BYTE0; + + frame2.fr2_regx.chksum = -(checksum); + + had_write_register(AUD_HDMIW_INFOFR, INFO_FRAME_WORD1); + had_write_register(AUD_HDMIW_INFOFR, frame2.fr2_val); + had_write_register(AUD_HDMIW_INFOFR, frame3.fr3_val); + + /* program remaining DIP words with zero */ + for (i = 0; i < HAD_MAX_DIP_WORDS-VALID_DIP_WORDS; i++) + had_write_register(AUD_HDMIW_INFOFR, 0x0); + + ctrl_state.ctrl_regx.dip_freq = 1; + ctrl_state.ctrl_regx.dip_en_sta = 1; + had_write_register(AUD_CNTL_ST, ctrl_state.ctrl_val); +} + +/** + * snd_intelhad_prog_dip_v2 - to initialize Data Island Packets registers + * + * @substream:substream for which the prepare function is called + * @intelhaddata:substream private data + * + * This function is called in the prepare callback + */ +static void snd_intelhad_prog_dip_v2(struct snd_pcm_substream *substream, + struct snd_intelhad *intelhaddata) +{ + int i; + union aud_ctrl_st ctrl_state = {.ctrl_val = 0}; + union aud_info_frame2 frame2 = {.fr2_val = 0}; + union aud_info_frame3 frame3 = {.fr3_val = 0}; + u8 checksum = 0; + int channels; + + channels = substream->runtime->channels; + + had_write_register(AUD_CNTL_ST, ctrl_state.ctrl_val); + + frame2.fr2_regx.chnl_cnt = substream->runtime->channels - 1; + + frame3.fr3_regx.chnl_alloc = snd_intelhad_channel_allocation( + intelhaddata, channels); + + /*Calculte the byte wide checksum for all valid DIP words*/ + for (i = 0; i < BYTES_PER_WORD; i++) + checksum += (INFO_FRAME_WORD1 >> i*BITS_PER_BYTE) & MASK_BYTE0; + for (i = 0; i < BYTES_PER_WORD; i++) + checksum += (frame2.fr2_val >> i*BITS_PER_BYTE) & MASK_BYTE0; + for (i = 0; i < BYTES_PER_WORD; i++) + checksum += (frame3.fr3_val >> i*BITS_PER_BYTE) & MASK_BYTE0; + + frame2.fr2_regx.chksum = -(checksum); + + had_write_register(AUD_HDMIW_INFOFR_v2, INFO_FRAME_WORD1); + had_write_register(AUD_HDMIW_INFOFR_v2, frame2.fr2_val); + had_write_register(AUD_HDMIW_INFOFR_v2, frame3.fr3_val); + + /* program remaining DIP words with zero */ + for (i = 0; i < HAD_MAX_DIP_WORDS-VALID_DIP_WORDS; i++) + had_write_register(AUD_HDMIW_INFOFR_v2, 0x0); + + ctrl_state.ctrl_regx.dip_freq = 1; + ctrl_state.ctrl_regx.dip_en_sta = 1; + had_write_register(AUD_CNTL_ST, ctrl_state.ctrl_val); +} + +/** + * snd_intelhad_prog_buffer - programs buffer + * address and length registers + * + * @substream:substream for which the prepare function is called + * @intelhaddata:substream private data + * + * This function programs ring buffer address and length into registers. + */ +int snd_intelhad_prog_buffer(struct snd_intelhad *intelhaddata, + int start, int end) +{ + u32 ring_buf_addr, ring_buf_size, period_bytes; + u8 i, num_periods; + struct snd_pcm_substream *substream; + + substream = intelhaddata->stream_info.had_substream; + if (!substream) { + pr_err("substream is NULL\n"); + dump_stack(); + return 0; + } + + ring_buf_addr = substream->runtime->dma_addr; + ring_buf_size = snd_pcm_lib_buffer_bytes(substream); + intelhaddata->stream_info.ring_buf_size = ring_buf_size; + period_bytes = frames_to_bytes(substream->runtime, + substream->runtime->period_size); + num_periods = substream->runtime->periods; + + /* + * buffer addr should be 64 byte aligned, period bytes + * will be used to calculate addr offset + */ + period_bytes &= ~0x3F; + + /* Hardware supports MAX_PERIODS buffers */ + if (end >= HAD_MAX_PERIODS) + return -EINVAL; + + for (i = start; i <= end; i++) { + /* Program the buf registers with addr and len */ + intelhaddata->buf_info[i].buf_addr = ring_buf_addr + + (i * period_bytes); + if (i < num_periods-1) + intelhaddata->buf_info[i].buf_size = period_bytes; + else + intelhaddata->buf_info[i].buf_size = ring_buf_size - + (period_bytes*i); + + had_write_register(AUD_BUF_A_ADDR + (i * HAD_REG_WIDTH), + intelhaddata->buf_info[i].buf_addr | + BIT(0) | BIT(1)); + had_write_register(AUD_BUF_A_LENGTH + (i * HAD_REG_WIDTH), + period_bytes); + intelhaddata->buf_info[i].is_valid = true; + } + pr_debug("%s:buf[%d-%d] addr=%#x and size=%d\n", __func__, start, end, + intelhaddata->buf_info[start].buf_addr, + intelhaddata->buf_info[start].buf_size); + intelhaddata->valid_buf_cnt = num_periods; + return 0; +} + +int snd_intelhad_read_len(struct snd_intelhad *intelhaddata) +{ + int i, retval = 0; + u32 len[4]; + + for (i = 0; i < 4 ; i++) { + had_read_register(AUD_BUF_A_LENGTH + (i * HAD_REG_WIDTH), + &len[i]); + if (!len[i]) + retval++; + } + if (retval != 1) { + for (i = 0; i < 4 ; i++) + pr_debug("buf[%d] size=%d\n", i, len[i]); + } + + return retval; +} + +/** + * snd_intelhad_prog_cts_v1 - Program HDMI audio CTS value + * + * @aud_samp_freq: sampling frequency of audio data + * @tmds: sampling frequency of the display data + * @n_param: N value, depends on aud_samp_freq + * @intelhaddata:substream private data + * + * Program CTS register based on the audio and display sampling frequency + */ +static void snd_intelhad_prog_cts_v1(u32 aud_samp_freq, u32 tmds, u32 n_param, + struct snd_intelhad *intelhaddata) +{ + u32 cts_val; + u64 dividend, divisor; + + /* Calculate CTS according to HDMI 1.3a spec*/ + dividend = (u64)tmds * n_param*1000; + divisor = 128 * aud_samp_freq; + cts_val = div64_u64(dividend, divisor); + pr_debug("TMDS value=%d, N value=%d, CTS Value=%d\n", + tmds, n_param, cts_val); + had_write_register(AUD_HDMI_CTS, (BIT(20) | cts_val)); +} + +/** + * snd_intelhad_prog_cts_v2 - Program HDMI audio CTS value + * + * @aud_samp_freq: sampling frequency of audio data + * @tmds: sampling frequency of the display data + * @n_param: N value, depends on aud_samp_freq + * @intelhaddata:substream private data + * + * Program CTS register based on the audio and display sampling frequency + */ +static void snd_intelhad_prog_cts_v2(u32 aud_samp_freq, u32 tmds, u32 n_param, + struct snd_intelhad *intelhaddata) +{ + u32 cts_val; + u64 dividend, divisor; + + /* Calculate CTS according to HDMI 1.3a spec*/ + dividend = (u64)tmds * n_param*1000; + divisor = 128 * aud_samp_freq; + cts_val = div64_u64(dividend, divisor); + pr_debug("TMDS value=%d, N value=%d, CTS Value=%d\n", + tmds, n_param, cts_val); + had_write_register(AUD_HDMI_CTS, (BIT(24) | cts_val)); +} + +static int had_calculate_n_value(u32 aud_samp_freq) +{ + s32 n_val; + + /* Select N according to HDMI 1.3a spec*/ + switch (aud_samp_freq) { + case AUD_SAMPLE_RATE_32: + n_val = 4096; + break; + + case AUD_SAMPLE_RATE_44_1: + n_val = 6272; + break; + + case AUD_SAMPLE_RATE_48: + n_val = 6144; + break; + + case AUD_SAMPLE_RATE_88_2: + n_val = 12544; + break; + + case AUD_SAMPLE_RATE_96: + n_val = 12288; + break; + + case AUD_SAMPLE_RATE_176_4: + n_val = 25088; + break; + + case HAD_MAX_RATE: + n_val = 24576; + break; + + default: + n_val = -EINVAL; + break; + } + return n_val; +} + +/** + * snd_intelhad_prog_n_v1 - Program HDMI audio N value + * + * @aud_samp_freq: sampling frequency of audio data + * @n_param: N value, depends on aud_samp_freq + * @intelhaddata:substream private data + * + * This function is called in the prepare callback. + * It programs based on the audio and display sampling frequency + */ +static int snd_intelhad_prog_n_v1(u32 aud_samp_freq, u32 *n_param, + struct snd_intelhad *intelhaddata) +{ + s32 n_val; + + n_val = had_calculate_n_value(aud_samp_freq); + + if (n_val < 0) + return n_val; + + had_write_register(AUD_N_ENABLE, (BIT(20) | n_val)); + *n_param = n_val; + return 0; +} + +/** + * snd_intelhad_prog_n_v2 - Program HDMI audio N value + * + * @aud_samp_freq: sampling frequency of audio data + * @n_param: N value, depends on aud_samp_freq + * @intelhaddata:substream private data + * + * This function is called in the prepare callback. + * It programs based on the audio and display sampling frequency + */ +static int snd_intelhad_prog_n_v2(u32 aud_samp_freq, u32 *n_param, + struct snd_intelhad *intelhaddata) +{ + s32 n_val; + + n_val = had_calculate_n_value(aud_samp_freq); + + if (n_val < 0) + return n_val; + + had_write_register(AUD_N_ENABLE, (BIT(24) | n_val)); + *n_param = n_val; + return 0; +} + +static void had_clear_underrun_intr_v1(struct snd_intelhad *intelhaddata) +{ + u32 hdmi_status, i = 0; + + /* Handle Underrun interrupt within Audio Unit */ + had_write_register(AUD_CONFIG, 0); + /* Reset buffer pointers */ + had_write_register(AUD_HDMI_STATUS, 1); + had_write_register(AUD_HDMI_STATUS, 0); + /** + * The interrupt status 'sticky' bits might not be cleared by + * setting '1' to that bit once... + */ + do { /* clear bit30, 31 AUD_HDMI_STATUS */ + had_read_register(AUD_HDMI_STATUS, &hdmi_status); + pr_debug("HDMI status =0x%x\n", hdmi_status); + if (hdmi_status & AUD_CONFIG_MASK_UNDERRUN) { + i++; + hdmi_status &= (AUD_CONFIG_MASK_SRDBG | + AUD_CONFIG_MASK_FUNCRST); + hdmi_status |= ~AUD_CONFIG_MASK_UNDERRUN; + had_write_register(AUD_HDMI_STATUS, hdmi_status); + } else + break; + } while (i < MAX_CNT); + if (i >= MAX_CNT) + pr_err("Unable to clear UNDERRUN bits\n"); +} + +static void had_clear_underrun_intr_v2(struct snd_intelhad *intelhaddata) +{ + u32 hdmi_status, i = 0; + + /* Handle Underrun interrupt within Audio Unit */ + had_write_register(AUD_CONFIG, 0); + /* Reset buffer pointers */ + had_write_register(AUD_HDMI_STATUS_v2, 1); + had_write_register(AUD_HDMI_STATUS_v2, 0); + /** + * The interrupt status 'sticky' bits might not be cleared by + * setting '1' to that bit once... + */ + do { /* clear bit30, 31 AUD_HDMI_STATUS */ + had_read_register(AUD_HDMI_STATUS_v2, &hdmi_status); + pr_debug("HDMI status =0x%x\n", hdmi_status); + if (hdmi_status & AUD_CONFIG_MASK_UNDERRUN) { + i++; + had_write_register(AUD_HDMI_STATUS_v2, hdmi_status); + } else + break; + } while (i < MAX_CNT); + if (i >= MAX_CNT) + pr_err("Unable to clear UNDERRUN bits\n"); +} + +/** + * snd_intelhad_open - stream initializations are done here + * @substream:substream for which the stream function is called + * + * This function is called whenever a PCM stream is opened + */ +static int snd_intelhad_open(struct snd_pcm_substream *substream) +{ + struct snd_intelhad *intelhaddata; + struct snd_pcm_runtime *runtime; + struct had_stream_pvt *stream; + struct had_pvt_data *had_stream; + int retval; + + pr_debug("snd_intelhad_open called\n"); + intelhaddata = snd_pcm_substream_chip(substream); + had_stream = intelhaddata->private_data; + runtime = substream->runtime; + + pm_runtime_get(intelhaddata->dev); + + if (had_get_hwstate(intelhaddata)) { + pr_err("%s: HDMI cable plugged-out\n", __func__); + retval = -ENODEV; + goto exit_put_handle; + } + + /* Check, if device already in use */ + if (runtime->private_data) { + pr_err("Device already in use\n"); + retval = -EBUSY; + goto exit_put_handle; + } + + /* set the runtime hw parameter with local snd_pcm_hardware struct */ + runtime->hw = snd_intel_hadstream; + + stream = kzalloc(sizeof(*stream), GFP_KERNEL); + if (!stream) { + retval = -ENOMEM; + goto exit_put_handle; + } + stream->stream_status = STREAM_INIT; + runtime->private_data = stream; + + retval = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (retval < 0) + goto exit_err; + + /* Make sure, that the period size is always aligned + * 64byte boundary + */ + retval = snd_pcm_hw_constraint_step(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64); + if (retval < 0) { + pr_err("%s:step_size=64 failed,err=%d\n", __func__, retval); + goto exit_err; + } + + return retval; +exit_err: + kfree(stream); +exit_put_handle: + pm_runtime_put(intelhaddata->dev); + runtime->private_data = NULL; + return retval; +} + +/** + * had_period_elapsed - updates the hardware pointer status + * @had_substream:substream for which the stream function is called + * + */ +static void had_period_elapsed(void *had_substream) +{ + struct snd_pcm_substream *substream = had_substream; + struct had_stream_pvt *stream; + + /* pr_debug("had_period_elapsed called\n"); */ + + if (!substream || !substream->runtime) + return; + stream = substream->runtime->private_data; + if (!stream) + return; + + if (stream->stream_status != STREAM_RUNNING) + return; + snd_pcm_period_elapsed(substream); +} + +/** + * snd_intelhad_init_stream - internal function to initialize stream info + * @substream:substream for which the stream function is called + * + */ +static int snd_intelhad_init_stream(struct snd_pcm_substream *substream) +{ + struct snd_intelhad *intelhaddata = snd_pcm_substream_chip(substream); + + pr_debug("snd_intelhad_init_stream called\n"); + + pr_debug("setting buffer ptr param\n"); + intelhaddata->stream_info.period_elapsed = had_period_elapsed; + intelhaddata->stream_info.had_substream = substream; + intelhaddata->stream_info.buffer_ptr = 0; + intelhaddata->stream_info.buffer_rendered = 0; + intelhaddata->stream_info.sfreq = substream->runtime->rate; + return 0; +} + +/** + * snd_intelhad_close- to free parameteres when stream is stopped + * + * @substream: substream for which the function is called + * + * This function is called by ALSA framework when stream is stopped + */ +static int snd_intelhad_close(struct snd_pcm_substream *substream) +{ + struct snd_intelhad *intelhaddata; + struct snd_pcm_runtime *runtime; + + pr_debug("snd_intelhad_close called\n"); + + intelhaddata = snd_pcm_substream_chip(substream); + runtime = substream->runtime; + + if (!runtime->private_data) { + pr_debug("close() might have called after failed open"); + return 0; + } + + intelhaddata->stream_info.buffer_rendered = 0; + intelhaddata->stream_info.buffer_ptr = 0; + intelhaddata->stream_info.str_id = 0; + intelhaddata->stream_info.had_substream = NULL; + + /* Check if following drv_status modification is required - VA */ + if (intelhaddata->drv_status != HAD_DRV_DISCONNECTED) { + intelhaddata->drv_status = HAD_DRV_CONNECTED; + pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_CONNECTED\n", + __func__, __LINE__); + } + kfree(runtime->private_data); + runtime->private_data = NULL; + pm_runtime_put(intelhaddata->dev); + return 0; +} + +/** + * snd_intelhad_hw_params- to setup the hardware parameters + * like allocating the buffers + * + * @substream: substream for which the function is called + * @hw_params: hardware parameters + * + * This function is called by ALSA framework when hardware params are set + */ +static int snd_intelhad_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + unsigned long addr; + int pages, buf_size, retval; + + pr_debug("snd_intelhad_hw_params called\n"); + + if (!hw_params) + return -EINVAL; + + buf_size = params_buffer_bytes(hw_params); + retval = snd_pcm_lib_malloc_pages(substream, buf_size); + if (retval < 0) + return retval; + pr_debug("%s:allocated memory = %d\n", __func__, buf_size); + /* mark the pages as uncached region */ + addr = (unsigned long) substream->runtime->dma_area; + pages = (substream->runtime->dma_bytes + PAGE_SIZE - 1) / PAGE_SIZE; + retval = set_memory_uc(addr, pages); + if (retval) { + pr_err("set_memory_uc failed.Error:%d\n", retval); + return retval; + } + memset(substream->runtime->dma_area, 0, buf_size); + + return retval; +} + +/** + * snd_intelhad_hw_free- to release the resources allocated during + * hardware params setup + * + * @substream: substream for which the function is called + * + * This function is called by ALSA framework before close callback. + * + */ +static int snd_intelhad_hw_free(struct snd_pcm_substream *substream) +{ + unsigned long addr; + u32 pages; + + pr_debug("snd_intelhad_hw_free called\n"); + + /* mark back the pages as cached/writeback region before the free */ + if (substream->runtime->dma_area != NULL) { + addr = (unsigned long) substream->runtime->dma_area; + pages = (substream->runtime->dma_bytes + PAGE_SIZE - 1) / + PAGE_SIZE; + set_memory_wb(addr, pages); + return snd_pcm_lib_free_pages(substream); + } + return 0; +} + +/** + * snd_intelhad_pcm_trigger - stream activities are handled here + * @substream:substream for which the stream function is called + * @cmd:the stream commamd thats requested from upper layer + * This function is called whenever an a stream activity is invoked + */ +static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, + int cmd) +{ + int caps, retval = 0; + unsigned long flag_irq; + struct snd_intelhad *intelhaddata; + struct had_stream_pvt *stream; + struct had_pvt_data *had_stream; + + pr_debug("snd_intelhad_pcm_trigger called\n"); + + intelhaddata = snd_pcm_substream_chip(substream); + stream = substream->runtime->private_data; + had_stream = intelhaddata->private_data; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + pr_debug("Trigger Start\n"); + + /* Disable local INTRs till register prgmng is done */ + if (had_get_hwstate(intelhaddata)) { + pr_err("_START: HDMI cable plugged-out\n"); + retval = -ENODEV; + break; + } + stream->stream_status = STREAM_RUNNING; + + had_stream->stream_type = HAD_RUNNING_STREAM; + + /* Enable Audio */ + /* + * ToDo: Need to enable UNDERRUN interrupts as well + * caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE; + */ + caps = HDMI_AUDIO_BUFFER_DONE; + retval = had_set_caps(HAD_SET_ENABLE_AUDIO_INT, &caps); + retval = had_set_caps(HAD_SET_ENABLE_AUDIO, NULL); + intelhaddata->ops->enable_audio(substream, 1); + + pr_debug("Processed _Start\n"); + + break; + + case SNDRV_PCM_TRIGGER_STOP: + pr_debug("Trigger Stop\n"); + spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irq); + intelhaddata->stream_info.str_id = 0; + intelhaddata->curr_buf = 0; + + /* Stop reporting BUFFER_DONE/UNDERRUN to above layers*/ + + had_stream->stream_type = HAD_INIT; + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irq); + /* Disable Audio */ + /* + * ToDo: Need to disable UNDERRUN interrupts as well + * caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE; + */ + caps = HDMI_AUDIO_BUFFER_DONE; + had_set_caps(HAD_SET_DISABLE_AUDIO_INT, &caps); + intelhaddata->ops->enable_audio(substream, 0); + /* Reset buffer pointers */ + intelhaddata->ops->reset_audio(1); + intelhaddata->ops->reset_audio(0); + stream->stream_status = STREAM_DROPPED; + had_set_caps(HAD_SET_DISABLE_AUDIO, NULL); + break; + + default: + retval = -EINVAL; + } + return retval; +} + +/** + * snd_intelhad_pcm_prepare- internal preparation before starting a stream + * + * @substream: substream for which the function is called + * + * This function is called when a stream is started for internal preparation. + */ +static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) +{ + int retval; + u32 disp_samp_freq, n_param; + struct snd_intelhad *intelhaddata; + struct snd_pcm_runtime *runtime; + struct had_pvt_data *had_stream; + + pr_debug("snd_intelhad_pcm_prepare called\n"); + + intelhaddata = snd_pcm_substream_chip(substream); + runtime = substream->runtime; + had_stream = intelhaddata->private_data; + + if (had_get_hwstate(intelhaddata)) { + pr_err("%s: HDMI cable plugged-out\n", __func__); + retval = -ENODEV; + goto prep_end; + } + + pr_debug("period_size=%d\n", + (int)frames_to_bytes(runtime, runtime->period_size)); + pr_debug("periods=%d\n", runtime->periods); + pr_debug("buffer_size=%d\n", (int)snd_pcm_lib_buffer_bytes(substream)); + pr_debug("rate=%d\n", runtime->rate); + pr_debug("channels=%d\n", runtime->channels); + + if (intelhaddata->stream_info.str_id) { + pr_debug("_prepare is called for existing str_id#%d\n", + intelhaddata->stream_info.str_id); + retval = snd_intelhad_pcm_trigger(substream, + SNDRV_PCM_TRIGGER_STOP); + return retval; + } + + retval = snd_intelhad_init_stream(substream); + if (retval) + goto prep_end; + + + /* Get N value in KHz */ + retval = had_get_caps(HAD_GET_DISPLAY_RATE, &disp_samp_freq); + if (retval) { + pr_err("querying display sampling freq failed %#x\n", retval); + goto prep_end; + } + + had_get_caps(HAD_GET_ELD, &intelhaddata->eeld); + + retval = intelhaddata->ops->prog_n(substream->runtime->rate, &n_param, + intelhaddata); + if (retval) { + pr_err("programming N value failed %#x\n", retval); + goto prep_end; + } + intelhaddata->ops->prog_cts(substream->runtime->rate, + disp_samp_freq, n_param, intelhaddata); + + intelhaddata->ops->prog_dip(substream, intelhaddata); + + retval = intelhaddata->ops->audio_ctrl(substream, intelhaddata); + + /* Prog buffer address */ + retval = snd_intelhad_prog_buffer(intelhaddata, + HAD_BUF_TYPE_A, HAD_BUF_TYPE_D); + + /* + * Program channel mapping in following order: + * FL, FR, C, LFE, RL, RR + */ + + had_write_register(AUD_BUF_CH_SWAP, SWAP_LFE_CENTER); + +prep_end: + return retval; +} + +/** + * snd_intelhad_pcm_pointer- to send the current buffer pointerprocessed by hw + * + * @substream: substream for which the function is called + * + * This function is called by ALSA framework to get the current hw buffer ptr + * when a period is elapsed + */ +static snd_pcm_uframes_t snd_intelhad_pcm_pointer( + struct snd_pcm_substream *substream) +{ + struct snd_intelhad *intelhaddata; + u32 bytes_rendered = 0; + u32 t; + int buf_id; + + /* pr_debug("snd_intelhad_pcm_pointer called\n"); */ + + intelhaddata = snd_pcm_substream_chip(substream); + + if (intelhaddata->flag_underrun) { + intelhaddata->flag_underrun = 0; + return SNDRV_PCM_POS_XRUN; + } + + /* Use a hw register to calculate sub-period position reports. + * This makes PulseAudio happier. + */ + + buf_id = intelhaddata->curr_buf % 4; + had_read_register(AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH), &t); + if (t == 0) { + pr_debug("discovered buffer done for buf %d\n", buf_id); + /* had_process_buffer_done(intelhaddata); */ + } + t = intelhaddata->buf_info[buf_id].buf_size - t; + + if (intelhaddata->stream_info.buffer_rendered) + div_u64_rem(intelhaddata->stream_info.buffer_rendered, + intelhaddata->stream_info.ring_buf_size, + &(bytes_rendered)); + + intelhaddata->stream_info.buffer_ptr = bytes_to_frames( + substream->runtime, + bytes_rendered + t); + return intelhaddata->stream_info.buffer_ptr; +} + +/** + * snd_intelhad_pcm_mmap- mmaps a kernel buffer to user space for copying data + * + * @substream: substream for which the function is called + * @vma: struct instance of memory VMM memory area + * + * This function is called by OS when a user space component + * tries to get mmap memory from driver + */ +static int snd_intelhad_pcm_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + + pr_debug("snd_intelhad_pcm_mmap called\n"); + + pr_debug("entry with prot:%s\n", __func__); + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + return remap_pfn_range(vma, vma->vm_start, + substream->dma_buffer.addr >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, vma->vm_page_prot); +} + +int hdmi_audio_mode_change(struct snd_pcm_substream *substream) +{ + int retval = 0; + u32 disp_samp_freq, n_param; + struct snd_intelhad *intelhaddata; + + intelhaddata = snd_pcm_substream_chip(substream); + + /* Disable Audio */ + intelhaddata->ops->enable_audio(substream, 0); + + /* Update CTS value */ + retval = had_get_caps(HAD_GET_DISPLAY_RATE, &disp_samp_freq); + if (retval) { + pr_err("querying display sampling freq failed %#x\n", retval); + goto out; + } + + retval = intelhaddata->ops->prog_n(substream->runtime->rate, &n_param, + intelhaddata); + if (retval) { + pr_err("programming N value failed %#x\n", retval); + goto out; + } + intelhaddata->ops->prog_cts(substream->runtime->rate, + disp_samp_freq, n_param, intelhaddata); + + /* Enable Audio */ + intelhaddata->ops->enable_audio(substream, 1); + +out: + return retval; +} + +/*PCM operations structure and the calls back for the same */ +struct snd_pcm_ops snd_intelhad_playback_ops = { + .open = snd_intelhad_open, + .close = snd_intelhad_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_intelhad_hw_params, + .hw_free = snd_intelhad_hw_free, + .prepare = snd_intelhad_pcm_prepare, + .trigger = snd_intelhad_pcm_trigger, + .pointer = snd_intelhad_pcm_pointer, + .mmap = snd_intelhad_pcm_mmap, +}; + +/** + * snd_intelhad_create - to crete alsa card instance + * + * @intelhaddata: pointer to internal context + * @card: pointer to card + * + * This function is called when the hdmi cable is plugged in + */ +static int snd_intelhad_create( + struct snd_intelhad *intelhaddata, + struct snd_card *card) +{ + int retval; + static struct snd_device_ops ops = { + }; + + pr_debug("snd_intelhad_create called\n"); + + if (!intelhaddata) + return -EINVAL; + + /* ALSA api to register the device */ + retval = snd_device_new(card, SNDRV_DEV_LOWLEVEL, intelhaddata, &ops); + return retval; +} +/** + * snd_intelhad_pcm_free - to free the memory allocated + * + * @pcm: pointer to pcm instance + * This function is called when the device is removed + */ +static void snd_intelhad_pcm_free(struct snd_pcm *pcm) +{ + pr_debug("Freeing PCM preallocated pages\n"); + snd_pcm_lib_preallocate_free_for_all(pcm); +} + +static int had_iec958_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; + uinfo->count = 1; + return 0; +} + +static int had_iec958_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_intelhad *intelhaddata = snd_kcontrol_chip(kcontrol); + + ucontrol->value.iec958.status[0] = (intelhaddata->aes_bits >> 0) & 0xff; + ucontrol->value.iec958.status[1] = (intelhaddata->aes_bits >> 8) & 0xff; + ucontrol->value.iec958.status[2] = + (intelhaddata->aes_bits >> 16) & 0xff; + ucontrol->value.iec958.status[3] = + (intelhaddata->aes_bits >> 24) & 0xff; + return 0; +} +static int had_iec958_mask_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.iec958.status[0] = 0xff; + ucontrol->value.iec958.status[1] = 0xff; + ucontrol->value.iec958.status[2] = 0xff; + ucontrol->value.iec958.status[3] = 0xff; + return 0; +} +static int had_iec958_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + unsigned int val; + struct snd_intelhad *intelhaddata = snd_kcontrol_chip(kcontrol); + + pr_debug("entered had_iec958_put\n"); + val = (ucontrol->value.iec958.status[0] << 0) | + (ucontrol->value.iec958.status[1] << 8) | + (ucontrol->value.iec958.status[2] << 16) | + (ucontrol->value.iec958.status[3] << 24); + if (intelhaddata->aes_bits != val) { + intelhaddata->aes_bits = val; + return 1; + } + return 1; +} + +static struct snd_kcontrol_new had_control_iec958_mask = { + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK), + .info = had_iec958_info, /* shared */ + .get = had_iec958_mask_get, +}; + +static struct snd_kcontrol_new had_control_iec958 = { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), + .info = had_iec958_info, + .get = had_iec958_get, + .put = had_iec958_put +}; + +static struct snd_intel_had_interface had_interface = { + .name = "hdmi-audio", + .query = hdmi_audio_query, + .suspend = hdmi_audio_suspend, + .resume = hdmi_audio_resume, +}; + +static struct had_ops had_ops_v1 = { + .enable_audio = snd_intelhad_enable_audio_v1, + .reset_audio = snd_intelhad_reset_audio_v1, + .prog_n = snd_intelhad_prog_n_v1, + .prog_cts = snd_intelhad_prog_cts_v1, + .audio_ctrl = snd_intelhad_prog_audio_ctrl_v1, + .prog_dip = snd_intelhad_prog_dip_v1, + .handle_underrun = had_clear_underrun_intr_v1, +}; + +static struct had_ops had_ops_v2 = { + .enable_audio = snd_intelhad_enable_audio_v2, + .reset_audio = snd_intelhad_reset_audio_v2, + .prog_n = snd_intelhad_prog_n_v2, + .prog_cts = snd_intelhad_prog_cts_v2, + .audio_ctrl = snd_intelhad_prog_audio_ctrl_v2, + .prog_dip = snd_intelhad_prog_dip_v2, + .handle_underrun = had_clear_underrun_intr_v2, +}; +/** + * hdmi_audio_probe - to create sound card instance for HDMI audio playabck + * + *@haddata: pointer to HAD private data + *@card_id: card for which probe is called + * + * This function is called when the hdmi cable is plugged in. This function + * creates and registers the sound card with ALSA + */ +int hdmi_audio_probe(void *deviceptr) +{ + int retval; + struct snd_pcm *pcm; + struct snd_card *card; + struct had_callback_ops ops_cb; + struct snd_intelhad *intelhaddata; + struct had_pvt_data *had_stream; + struct platform_device *devptr = deviceptr; + + pr_debug("Enter %s\n", __func__); + + pr_debug("hdmi_audio_probe dma_mask: %p\n", devptr->dev.dma_mask); + + /* allocate memory for saving internal context and working */ + intelhaddata = kzalloc(sizeof(*intelhaddata), GFP_KERNEL); + if (!intelhaddata) + return -ENOMEM; + + had_stream = kzalloc(sizeof(*had_stream), GFP_KERNEL); + if (!had_stream) { + retval = -ENOMEM; + goto free_haddata; + } + + had_data = intelhaddata; + ops_cb.intel_had_event_call_back = had_event_handler; + + /* registering with display driver to get access to display APIs */ + + retval = mid_hdmi_audio_setup( + ops_cb.intel_had_event_call_back, + &(intelhaddata->reg_ops), + &(intelhaddata->query_ops)); + if (retval) { + pr_err("querying display driver APIs failed %#x\n", retval); + goto free_hadstream; + } + mutex_lock(&had_mutex); + spin_lock_init(&intelhaddata->had_spinlock); + intelhaddata->drv_status = HAD_DRV_DISCONNECTED; + pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", + __func__, __LINE__); + + /* create a card instance with ALSA framework */ + retval = snd_card_new(&devptr->dev, hdmi_card_index, hdmi_card_id, + THIS_MODULE, 0, &card); + + if (retval) + goto unlock_mutex; + intelhaddata->card = card; + intelhaddata->card_id = hdmi_card_id; + intelhaddata->card_index = card->number; + intelhaddata->private_data = had_stream; + intelhaddata->flag_underrun = 0; + intelhaddata->aes_bits = SNDRV_PCM_DEFAULT_CON_SPDIF; + strncpy(card->driver, INTEL_HAD, strlen(INTEL_HAD)); + strncpy(card->shortname, INTEL_HAD, strlen(INTEL_HAD)); + + retval = snd_pcm_new(card, INTEL_HAD, PCM_INDEX, MAX_PB_STREAMS, + MAX_CAP_STREAMS, &pcm); + if (retval) + goto err; + + /* setup private data which can be retrieved when required */ + pcm->private_data = intelhaddata; + pcm->private_free = snd_intelhad_pcm_free; + pcm->info_flags = 0; + strncpy(pcm->name, card->shortname, strlen(card->shortname)); + /* setup the ops for palyabck */ + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, + &snd_intelhad_playback_ops); + /* allocate dma pages for ALSA stream operations + * memory allocated is based on size, not max value + * thus using same argument for max & size + */ + retval = snd_pcm_lib_preallocate_pages_for_all(pcm, + SNDRV_DMA_TYPE_DEV, NULL, + HAD_MAX_BUFFER, HAD_MAX_BUFFER); + + if (card->dev == NULL) + pr_debug("card->dev is NULL!!!!! Should not be this case\n"); + else if (card->dev->dma_mask == NULL) + pr_debug("hdmi_audio_probe dma_mask is NULL!!!!!\n"); + else + pr_debug("hdmi_audio_probe dma_mask is : %p\n", + card->dev->dma_mask); + + if (retval) + goto err; + + /* internal function call to register device with ALSA */ + retval = snd_intelhad_create(intelhaddata, card); + if (retval) + goto err; + + card->private_data = &intelhaddata; + retval = snd_card_register(card); + if (retval) + goto err; + + /* IEC958 controls */ + retval = snd_ctl_add(card, snd_ctl_new1(&had_control_iec958_mask, + intelhaddata)); + if (retval < 0) + goto err; + retval = snd_ctl_add(card, snd_ctl_new1(&had_control_iec958, + intelhaddata)); + if (retval < 0) + goto err; + + init_channel_allocations(); + + /* Register channel map controls */ + retval = had_register_chmap_ctls(intelhaddata, pcm); + if (retval < 0) + goto err; + + intelhaddata->dev = &devptr->dev; + pm_runtime_set_active(intelhaddata->dev); + pm_runtime_enable(intelhaddata->dev); + + mutex_unlock(&had_mutex); + retval = mid_hdmi_audio_register(&had_interface, intelhaddata); + if (retval) { + pr_err("registering with display driver failed %#x\n", retval); + snd_card_free(card); + goto free_hadstream; + } + + intelhaddata->hw_silence = 1; + had_ops_v1 = had_ops_v1; /* unused */ + intelhaddata->ops = &had_ops_v2; + + return retval; +err: + snd_card_free(card); +unlock_mutex: + mutex_unlock(&had_mutex); +free_hadstream: + kfree(had_stream); + pm_runtime_disable(intelhaddata->dev); + intelhaddata->dev = NULL; +free_haddata: + kfree(intelhaddata); + intelhaddata = NULL; + pr_err("Error returned from %s api %#x\n", __func__, retval); + return retval; +} + +/** + * hdmi_audio_remove - removes the alsa card + * + *@haddata: pointer to HAD private data + * + * This function is called when the hdmi cable is un-plugged. This function + * free the sound card. + */ +int hdmi_audio_remove(void *pdevptr) +{ + struct snd_intelhad *intelhaddata = had_data; + int caps; + + pr_debug("Enter %s\n", __func__); + + if (!intelhaddata) + return 0; + + if (intelhaddata->drv_status != HAD_DRV_DISCONNECTED) { + caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE; + had_set_caps(HAD_SET_DISABLE_AUDIO_INT, &caps); + had_set_caps(HAD_SET_DISABLE_AUDIO, NULL); + } + snd_card_free(intelhaddata->card); + kfree(intelhaddata->private_data); + kfree(intelhaddata); + return 0; +} + +MODULE_AUTHOR("Sailaja Bandarupalli "); +MODULE_AUTHOR("Ramesh Babu K V "); +MODULE_AUTHOR("Vaibhav Agarwal "); +MODULE_AUTHOR("Jerome Anand "); +MODULE_DESCRIPTION("Intel HDMI Audio driver"); +MODULE_LICENSE("GPL v2"); +MODULE_SUPPORTED_DEVICE("{Intel,Intel_HAD}"); diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h new file mode 100644 index 000000000000..d2015ec84843 --- /dev/null +++ b/sound/x86/intel_hdmi_audio.h @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2016 Intel Corporation + * Authors: Sailaja Bandarupalli + * Ramesh Babu K V + * Vaibhav Agarwal + * Jerome Anand + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _INTEL_HDMI_AUDIO_H_ +#define _INTEL_HDMI_AUDIO_H_ + +#include +#include +#include +#include +#include +#include +#include +#include "intel_hdmi_lpe_audio.h" + +#define PCM_INDEX 0 +#define MAX_PB_STREAMS 1 +#define MAX_CAP_STREAMS 0 +#define HDMI_AUDIO_DRIVER "hdmi-audio" + +#define INFO_FRAME_WORD1 0x000a0184 +#define FIFO_THRESHOLD 0xFE +#define DMA_FIFO_THRESHOLD 0x7 +#define BYTES_PER_WORD 0x4 + +/* Sampling rate as per IEC60958 Ver 3 */ +#define CH_STATUS_MAP_32KHZ 0x3 +#define CH_STATUS_MAP_44KHZ 0x0 +#define CH_STATUS_MAP_48KHZ 0x2 +#define CH_STATUS_MAP_88KHZ 0x8 +#define CH_STATUS_MAP_96KHZ 0xA +#define CH_STATUS_MAP_176KHZ 0xC +#define CH_STATUS_MAP_192KHZ 0xE + +#define MAX_SMPL_WIDTH_20 0x0 +#define MAX_SMPL_WIDTH_24 0x1 +#define SMPL_WIDTH_16BITS 0x1 +#define SMPL_WIDTH_24BITS 0x5 +#define CHANNEL_ALLOCATION 0x1F +#define MASK_BYTE0 0x000000FF +#define VALID_DIP_WORDS 3 +#define LAYOUT0 0 +#define LAYOUT1 1 +#define SWAP_LFE_CENTER 0x00fac4c8 +#define AUD_CONFIG_CH_MASK_V2 0x70 + +struct pcm_stream_info { + int str_id; + void *had_substream; + void (*period_elapsed)(void *had_substream); + u32 buffer_ptr; + u64 buffer_rendered; + u32 ring_buf_size; + int sfreq; +}; + +struct ring_buf_info { + u32 buf_addr; + u32 buf_size; + u8 is_valid; +}; + +struct had_stream_pvt { + enum had_stream_status stream_status; + int stream_ops; + ssize_t dbg_cum_bytes; +}; + +struct had_pvt_data { + enum had_status_stream stream_type; +}; + +struct had_callback_ops { + had_event_call_back intel_had_event_call_back; +}; + +/** + * struct snd_intelhad - intelhad driver structure + * + * @card: ptr to hold card details + * @card_index: sound card index + * @card_id: detected sound card id + * @reg_ops: register operations to program registers + * @query_ops: caps call backs for get/set operations + * @drv_status: driver status + * @buf_info: ring buffer info + * @stream_info: stream information + * @eeld: holds EELD info + * @curr_buf: pointer to hold current active ring buf + * @valid_buf_cnt: ring buffer count for stream + * @had_spinlock: driver lock + * @aes_bits: IEC958 status bits + * @buff_done: id of current buffer done intr + * @dev: platoform device handle + * @kctl: holds kctl ptrs used for channel map + * @chmap: holds channel map info + * @audio_reg_base: hdmi audio register base offset + * @hw_silence: flag indicates SoC support for HW silence/Keep alive + * @ops: holds ops functions based on platform + */ +struct snd_intelhad { + struct snd_card *card; + int card_index; + char *card_id; + struct hdmi_audio_registers_ops reg_ops; + struct hdmi_audio_query_set_ops query_ops; + enum had_drv_status drv_status; + struct ring_buf_info buf_info[HAD_NUM_OF_RING_BUFS]; + struct pcm_stream_info stream_info; + union otm_hdmi_eld_t eeld; + enum intel_had_aud_buf_type curr_buf; + int valid_buf_cnt; + unsigned int aes_bits; + int flag_underrun; + struct had_pvt_data *private_data; + spinlock_t had_spinlock; + enum intel_had_aud_buf_type buff_done; + struct device *dev; + struct snd_kcontrol *kctl; + struct snd_pcm_chmap *chmap; + unsigned int *audio_reg_base; + unsigned int audio_cfg_offset; + bool hw_silence; + struct had_ops *ops; +}; + +struct had_ops { + void (*enable_audio)(struct snd_pcm_substream *substream, + u8 enable); + void (*reset_audio)(u8 reset); + int (*prog_n)(u32 aud_samp_freq, u32 *n_param, + struct snd_intelhad *intelhaddata); + void (*prog_cts)(u32 aud_samp_freq, u32 tmds, u32 n_param, + struct snd_intelhad *intelhaddata); + int (*audio_ctrl)(struct snd_pcm_substream *substream, + struct snd_intelhad *intelhaddata); + void (*prog_dip)(struct snd_pcm_substream *substream, + struct snd_intelhad *intelhaddata); + void (*handle_underrun)(struct snd_intelhad *intelhaddata); +}; + + +int had_event_handler(enum had_event_type event_type, void *data); + +int hdmi_audio_query(void *drv_data, struct hdmi_audio_event event); +int hdmi_audio_suspend(void *drv_data, struct hdmi_audio_event event); +int hdmi_audio_resume(void *drv_data); +int hdmi_audio_mode_change(struct snd_pcm_substream *substream); +extern struct snd_pcm_ops snd_intelhad_playback_ops; + +int snd_intelhad_init_audio_ctrl(struct snd_pcm_substream *substream, + struct snd_intelhad *intelhaddata, + int flag_silence); +int snd_intelhad_prog_buffer(struct snd_intelhad *intelhaddata, + int start, int end); +int snd_intelhad_invd_buffer(int start, int end); +int snd_intelhad_read_len(struct snd_intelhad *intelhaddata); +void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata); + +/* Register access functions */ +int had_get_hwstate(struct snd_intelhad *intelhaddata); +int had_get_caps(enum had_caps_list query_element, void *capabilties); +int had_set_caps(enum had_caps_list set_element, void *capabilties); +int had_read_register(u32 reg_addr, u32 *data); +int had_write_register(u32 reg_addr, u32 data); +int had_read_modify(u32 reg_addr, u32 data, u32 mask); + +int hdmi_audio_probe(void *devptr); +int hdmi_audio_remove(void *pdev); + +#endif /* _INTEL_HDMI_AUDIO_ */ diff --git a/sound/x86/intel_hdmi_audio_if.c b/sound/x86/intel_hdmi_audio_if.c new file mode 100644 index 000000000000..c650ba46d8b9 --- /dev/null +++ b/sound/x86/intel_hdmi_audio_if.c @@ -0,0 +1,551 @@ +/* + * intel_hdmi_audio_if.c - Intel HDMI audio driver for MID + * + * Copyright (C) 2016 Intel Corp + * Authors: Sailaja Bandarupalli + * Ramesh Babu K V + * Vaibhav Agarwal + * Jerome Anand + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * ALSA driver for Intel MID HDMI audio controller. This file contains + * interface functions exposed to HDMI Display driver and code to register + * with ALSA framework.. + */ + +#define pr_fmt(fmt) "had: " fmt + +#include +#include +#include +#include +#include +#include "intel_hdmi_audio.h" +#include "intel_hdmi_lpe_audio.h" + +/** + * hdmi_audio_query - hdmi audio query function + * + *@haddata: pointer to HAD private data + *@event: audio event for which this method is invoked + * + * This function is called by client driver to query the + * hdmi audio. + */ +int hdmi_audio_query(void *haddata, struct hdmi_audio_event event) +{ + struct snd_pcm_substream *substream = NULL; + struct had_pvt_data *had_stream; + unsigned long flag_irqs; + struct snd_intelhad *intelhaddata = (struct snd_intelhad *)haddata; + + if (intelhaddata->stream_info.had_substream) + substream = intelhaddata->stream_info.had_substream; + had_stream = intelhaddata->private_data; + switch (event.type) { + case HAD_EVENT_QUERY_IS_AUDIO_BUSY: + spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + + if ((had_stream->stream_type == HAD_RUNNING_STREAM) || + substream) { + spin_unlock_irqrestore(&intelhaddata->had_spinlock, + flag_irqs); + pr_debug("Audio stream active\n"); + return -EBUSY; + } + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + break; + + case HAD_EVENT_QUERY_IS_AUDIO_SUSPENDED: + spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + if (intelhaddata->drv_status == HAD_DRV_SUSPENDED) { + spin_unlock_irqrestore(&intelhaddata->had_spinlock, + flag_irqs); + pr_debug("Audio is suspended\n"); + return 1; + } + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + break; + + default: + pr_debug("error un-handled event !!\n"); + return -EINVAL; + break; + + } + + return 0; +} + +/** + * hdmi_audio_suspend - power management suspend function + * + *@haddata: pointer to HAD private data + *@event: pm event for which this method is invoked + * + * This function is called by client driver to suspend the + * hdmi audio. + */ +int hdmi_audio_suspend(void *haddata, struct hdmi_audio_event event) +{ + int caps, retval = 0; + struct had_pvt_data *had_stream; + unsigned long flag_irqs; + struct snd_pcm_substream *substream; + struct snd_intelhad *intelhaddata = (struct snd_intelhad *)haddata; + + pr_debug("Enter:%s\n", __func__); + + had_stream = intelhaddata->private_data; + substream = intelhaddata->stream_info.had_substream; + + if (intelhaddata->dev->power.runtime_status != RPM_SUSPENDED) { + pr_err("audio stream is active\n"); + return -EAGAIN; + } + + + spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + pr_debug("had not connected\n"); + return retval; + } + + if (intelhaddata->drv_status == HAD_DRV_SUSPENDED) { + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + pr_debug("had already suspended\n"); + return retval; + } + + intelhaddata->drv_status = HAD_DRV_SUSPENDED; + pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_SUSPENDED\n", + __func__, __LINE__); + + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + /* + * ToDo: Need to disable UNDERRUN interrupts as well + * caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE; + */ + caps = HDMI_AUDIO_BUFFER_DONE; + had_set_caps(HAD_SET_DISABLE_AUDIO_INT, &caps); + had_set_caps(HAD_SET_DISABLE_AUDIO, NULL); + pr_debug("Exit:%s", __func__); + return retval; +} + +/** + * hdmi_audio_resume - power management resume function + * + *@haddata: pointer to HAD private data + * + * This function is called by client driver to resume the + * hdmi audio. + */ +int hdmi_audio_resume(void *haddata) +{ + int caps, retval = 0; + struct snd_intelhad *intelhaddata = (struct snd_intelhad *)haddata; + unsigned long flag_irqs; + + pr_debug("Enter:%s\n", __func__); + + spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + pr_debug("had not connected\n"); + return 0; + } + + if (intelhaddata->drv_status != HAD_DRV_SUSPENDED) { + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + pr_err("had is not in suspended state\n"); + return 0; + } + + if (had_get_hwstate(intelhaddata)) { + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + pr_err("Failed to resume. Device not accessible\n"); + return -ENODEV; + } + + intelhaddata->drv_status = HAD_DRV_CONNECTED; + pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", + __func__, __LINE__); + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + /* + * ToDo: Need to enable UNDERRUN interrupts as well + * caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE; + */ + caps = HDMI_AUDIO_BUFFER_DONE; + retval = had_set_caps(HAD_SET_ENABLE_AUDIO_INT, &caps); + retval = had_set_caps(HAD_SET_ENABLE_AUDIO, NULL); + pr_debug("Exit:%s", __func__); + return retval; +} + +static inline int had_chk_intrmiss(struct snd_intelhad *intelhaddata, + enum intel_had_aud_buf_type buf_id) +{ + int i, intr_count = 0; + enum intel_had_aud_buf_type buff_done; + u32 buf_size, buf_addr; + struct had_pvt_data *had_stream; + unsigned long flag_irqs; + + had_stream = intelhaddata->private_data; + + buff_done = buf_id; + + intr_count = snd_intelhad_read_len(intelhaddata); + if (intr_count > 1) { + /* In case of active playback */ + pr_err("Driver detected %d missed buffer done interrupt(s)!!!!\n", + (intr_count - 1)); + if (intr_count > 3) + return intr_count; + + buf_id += (intr_count - 1); + /* Reprogram registers*/ + for (i = buff_done; i < buf_id; i++) { + int j = i % 4; + + buf_size = intelhaddata->buf_info[j].buf_size; + buf_addr = intelhaddata->buf_info[j].buf_addr; + had_write_register(AUD_BUF_A_LENGTH + + (j * HAD_REG_WIDTH), buf_size); + had_write_register( + AUD_BUF_A_ADDR+(j * HAD_REG_WIDTH), + (buf_addr | BIT(0) | BIT(1))); + } + buf_id = buf_id % 4; + spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + intelhaddata->buff_done = buf_id; + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + } + + return intr_count; +} + +int had_process_buffer_done(struct snd_intelhad *intelhaddata) +{ + int retval = 0; + u32 len = 1; + enum intel_had_aud_buf_type buf_id; + enum intel_had_aud_buf_type buff_done; + struct pcm_stream_info *stream; + u32 buf_size; + struct had_pvt_data *had_stream; + int intr_count; + enum had_status_stream stream_type; + unsigned long flag_irqs; + + had_stream = intelhaddata->private_data; + stream = &intelhaddata->stream_info; + intr_count = 1; + + spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + pr_err("%s:Device already disconnected\n", __func__); + return retval; + } + buf_id = intelhaddata->curr_buf; + intelhaddata->buff_done = buf_id; + buff_done = intelhaddata->buff_done; + buf_size = intelhaddata->buf_info[buf_id].buf_size; + stream_type = had_stream->stream_type; + + pr_debug("Enter:%s buf_id=%d\n", __func__, buf_id); + + /* Every debug statement has an implication + * of ~5msec. Thus, avoid having >3 debug statements + * for each buffer_done handling. + */ + + /* Check for any intr_miss in case of active playback */ + if (had_stream->stream_type == HAD_RUNNING_STREAM) { + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + intr_count = had_chk_intrmiss(intelhaddata, buf_id); + if (!intr_count || (intr_count > 3)) { + pr_err("HAD SW state in non-recoverable!!! mode\n"); + pr_err("Already played stale data\n"); + return retval; + } + buf_id += (intr_count - 1); + buf_id = buf_id % 4; + spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + } + + intelhaddata->buf_info[buf_id].is_valid = true; + if (intelhaddata->valid_buf_cnt-1 == buf_id) { + if (had_stream->stream_type >= HAD_RUNNING_STREAM) + intelhaddata->curr_buf = HAD_BUF_TYPE_A; + } else + intelhaddata->curr_buf = buf_id + 1; + + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + + if (had_get_hwstate(intelhaddata)) { + pr_err("HDMI cable plugged-out\n"); + return retval; + } + + /*Reprogram the registers with addr and length*/ + had_write_register(AUD_BUF_A_LENGTH + + (buf_id * HAD_REG_WIDTH), buf_size); + had_write_register(AUD_BUF_A_ADDR+(buf_id * HAD_REG_WIDTH), + intelhaddata->buf_info[buf_id].buf_addr| + BIT(0) | BIT(1)); + + had_read_register(AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH), + &len); + pr_debug("%s:Enabled buf[%d]\n", __func__, buf_id); + + /* In case of actual data, + * report buffer_done to above ALSA layer + */ + buf_size = intelhaddata->buf_info[buf_id].buf_size; + if (stream_type >= HAD_RUNNING_STREAM) { + intelhaddata->stream_info.buffer_rendered += + (intr_count * buf_size); + stream->period_elapsed(stream->had_substream); + } + + return retval; +} + +int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) +{ + int retval = 0; + enum intel_had_aud_buf_type buf_id; + struct pcm_stream_info *stream; + struct had_pvt_data *had_stream; + enum had_status_stream stream_type; + unsigned long flag_irqs; + int drv_status; + + had_stream = intelhaddata->private_data; + stream = &intelhaddata->stream_info; + + spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + buf_id = intelhaddata->curr_buf; + stream_type = had_stream->stream_type; + intelhaddata->buff_done = buf_id; + drv_status = intelhaddata->drv_status; + if (stream_type == HAD_RUNNING_STREAM) + intelhaddata->curr_buf = HAD_BUF_TYPE_A; + + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + + pr_debug("Enter:%s buf_id=%d, stream_type=%d\n", + __func__, buf_id, stream_type); + + intelhaddata->ops->handle_underrun(intelhaddata); + + if (drv_status == HAD_DRV_DISCONNECTED) { + pr_err("%s:Device already disconnected\n", __func__); + return retval; + } + + if (stream_type == HAD_RUNNING_STREAM) { + /* Report UNDERRUN error to above layers */ + intelhaddata->flag_underrun = 1; + stream->period_elapsed(stream->had_substream); + } + + return retval; +} + +int had_process_hot_plug(struct snd_intelhad *intelhaddata) +{ + int retval = 0; + enum intel_had_aud_buf_type buf_id; + struct snd_pcm_substream *substream; + struct had_pvt_data *had_stream; + unsigned long flag_irqs; + + pr_debug("Enter:%s\n", __func__); + + substream = intelhaddata->stream_info.had_substream; + had_stream = intelhaddata->private_data; + + spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + if (intelhaddata->drv_status == HAD_DRV_CONNECTED) { + pr_debug("Device already connected\n"); + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + return retval; + } + buf_id = intelhaddata->curr_buf; + intelhaddata->buff_done = buf_id; + intelhaddata->drv_status = HAD_DRV_CONNECTED; + pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_CONNECTED\n", + __func__, __LINE__); + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + + pr_debug("Processing HOT_PLUG, buf_id = %d\n", buf_id); + + /* Query display driver for audio register base */ + if (intelhaddata->reg_ops.hdmi_audio_get_register_base( + &intelhaddata->audio_reg_base, + &intelhaddata->audio_cfg_offset)) { + pr_err("Unable to get audio reg base from Display driver\n"); + goto err; + } + + if (intelhaddata->audio_reg_base == NULL) { + pr_err("audio reg base value is NULL\n"); + goto err; + } + + pr_debug("%s audio_reg_base = 0x%p\n", __func__, + intelhaddata->audio_reg_base); + + /* Safety check */ + if (substream) { + pr_debug("There should not be active PB from ALSA\n"); + pr_debug("Signifies, cable is plugged-in even before\n"); + pr_debug("processing snd_pcm_disconnect\n"); + /* Set runtime->state to hw_params done */ + snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); + } + + had_build_channel_allocation_map(intelhaddata); + + return retval; + +err: + pm_runtime_disable(intelhaddata->dev); + intelhaddata->dev = NULL; + return retval; +} + +int had_process_hot_unplug(struct snd_intelhad *intelhaddata) +{ + int caps, retval = 0; + enum intel_had_aud_buf_type buf_id; + struct had_pvt_data *had_stream; + unsigned long flag_irqs; + + pr_debug("Enter:%s\n", __func__); + + had_stream = intelhaddata->private_data; + buf_id = intelhaddata->curr_buf; + + spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + + if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { + pr_debug("Device already disconnected\n"); + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + return retval; + + } else { + /* Disable Audio */ + caps = HDMI_AUDIO_BUFFER_DONE; + retval = had_set_caps(HAD_SET_DISABLE_AUDIO_INT, &caps); + retval = had_set_caps(HAD_SET_DISABLE_AUDIO, NULL); + intelhaddata->ops->enable_audio( + intelhaddata->stream_info.had_substream, 0); + } + + intelhaddata->drv_status = HAD_DRV_DISCONNECTED; + pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", + __func__, __LINE__); + + /* Report to above ALSA layer */ + if (intelhaddata->stream_info.had_substream != NULL) { + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + pr_debug("%s: unlock -> sending pcm_stop -> lock\n", __func__); + snd_pcm_stop(intelhaddata->stream_info.had_substream, + SNDRV_PCM_STATE_DISCONNECTED); + spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + } + + had_stream->stream_type = HAD_INIT; + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + kfree(intelhaddata->chmap->chmap); + intelhaddata->chmap->chmap = NULL; + intelhaddata->audio_reg_base = NULL; + pr_debug("%s: unlocked -> returned\n", __func__); + + return retval; +} + +/** + * had_event_handler - Call back function to handle events + * + * @event_type: Event type to handle + * @data: data related to the event_type + * + * This function is invoked to handle HDMI events from client driver. + */ +int had_event_handler(enum had_event_type event_type, void *data) +{ + int retval = 0; + struct snd_intelhad *intelhaddata = data; + enum intel_had_aud_buf_type buf_id; + struct snd_pcm_substream *substream; + struct had_pvt_data *had_stream; + unsigned long flag_irqs; + + buf_id = intelhaddata->curr_buf; + had_stream = intelhaddata->private_data; + + /* Switching to a function can drop atomicity even in INTR context. + * Thus, a big lock is acquired to maintain atomicity. + * This can be optimized later. + * Currently, only buffer_done/_underrun executes in INTR context. + * Also, locking is implemented separately to avoid real contention + * of data(struct intelhaddata) between IRQ/SOFT_IRQ/PROCESS context. + */ + substream = intelhaddata->stream_info.had_substream; + switch (event_type) { + case HAD_EVENT_AUDIO_BUFFER_DONE: + retval = had_process_buffer_done(intelhaddata); + break; + + case HAD_EVENT_AUDIO_BUFFER_UNDERRUN: + retval = had_process_buffer_underrun(intelhaddata); + break; + + case HAD_EVENT_HOT_PLUG: + retval = had_process_hot_plug(intelhaddata); + break; + + case HAD_EVENT_HOT_UNPLUG: + retval = had_process_hot_unplug(intelhaddata); + break; + + case HAD_EVENT_MODE_CHANGING: + pr_debug(" called _event_handler with _MODE_CHANGE event\n"); + /* Process only if stream is active & cable Plugged-in */ + spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + if (intelhaddata->drv_status >= HAD_DRV_DISCONNECTED) { + spin_unlock_irqrestore(&intelhaddata->had_spinlock, + flag_irqs); + break; + } + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + if ((had_stream->stream_type == HAD_RUNNING_STREAM) + && substream) + retval = hdmi_audio_mode_change(substream); + break; + + default: + pr_debug("error un-handled event !!\n"); + retval = -EINVAL; + break; + + } + return retval; +} diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c index a9fd2d34a921..ce24ef1dd491 100644 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ b/sound/x86/intel_hdmi_lpe_audio.c @@ -34,6 +34,7 @@ #include #include #include "intel_hdmi_lpe_audio.h" +#include "intel_hdmi_audio.h" /* globals*/ static struct platform_device *hlpe_pdev; @@ -450,9 +451,9 @@ static void notify_audio_lpe(void *audio_ptr) /** * hdmi_lpe_audio_probe - start bridge with i915 * - * This function is called when the i915 driver creates the hdmi-lpe-audio - * platform device. Card creation is deferred until a hot plug event is - * received + * This function is called when the i915 driver creates the + * hdmi-lpe-audio platform device. Card creation is deferred until a + * hot plug event is received */ static int hdmi_lpe_audio_probe(struct platform_device *pdev) { @@ -495,8 +496,8 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) (unsigned int)res_mmio->end); mmio_start = ioremap_nocache(res_mmio->start, - (size_t)((res_mmio->end - res_mmio->start) - + 1)); + (size_t)((res_mmio->end - + res_mmio->start) + 1)); if (!mmio_start) { dev_err(&hlpe_pdev->dev, "Could not get ioremap\n"); return -EACCES; @@ -548,11 +549,11 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ctx); + ret = hdmi_audio_probe((void *)pdev); dev_dbg(&hlpe_pdev->dev, "hdmi lpe audio: setting pin eld notify callback\n"); spin_lock_irqsave(&pdata->lpe_audio_slock, flag_irq); pdata->notify_audio_lpe = notify_audio_lpe; - if (pdata->notify_pending) { dev_dbg(&hlpe_pdev->dev, "%s: handle pending notification\n", __func__); @@ -576,6 +577,8 @@ static int hdmi_lpe_audio_remove(struct platform_device *pdev) dev_dbg(&hlpe_pdev->dev, "Enter %s\n", __func__); + hdmi_audio_remove(pdev); + /* get context, release resources */ ctx = platform_get_drvdata(pdev); iounmap(ctx->mmio_start); -- cgit v1.2.3 From 232892fb14265b07b7a50061f36aaa5a6b81fb9d Mon Sep 17 00:00:00 2001 From: Jerome Anand Date: Wed, 25 Jan 2017 04:27:53 +0530 Subject: ALSA: x86: hdmi: continue playback even when display resolution changes When the display resolution changes, the drm disables the display pipes due to which audio rendering stops. At this time, we need to ensure the existing audio pointers and buffers are cleared out so that the playback can restarted once the display pipe is enabled with a different N/CTS values Signed-off-by: Pierre-Louis Bossart Signed-off-by: Jerome Anand Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index b69521aa2ed1..f30155446117 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -43,6 +43,7 @@ static DEFINE_MUTEX(had_mutex); static int hdmi_card_index = SNDRV_DEFAULT_IDX1; static char *hdmi_card_id = SNDRV_DEFAULT_STR1; static struct snd_intelhad *had_data; +static int underrun_count; module_param_named(index, hdmi_card_index, int, 0444); MODULE_PARM_DESC(index, @@ -1052,6 +1053,7 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) intelhaddata = snd_pcm_substream_chip(substream); had_stream = intelhaddata->private_data; runtime = substream->runtime; + underrun_count = 0; pm_runtime_get(intelhaddata->dev); @@ -1445,10 +1447,23 @@ static snd_pcm_uframes_t snd_intelhad_pcm_pointer( buf_id = intelhaddata->curr_buf % 4; had_read_register(AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH), &t); - if (t == 0) { - pr_debug("discovered buffer done for buf %d\n", buf_id); - /* had_process_buffer_done(intelhaddata); */ + + if ((t == 0) || (t == ((u32)-1L))) { + underrun_count++; + pr_debug("discovered buffer done for buf %d, count = %d\n", + buf_id, underrun_count); + + if (underrun_count > (HAD_MIN_PERIODS/2)) { + pr_debug("assume audio_codec_reset, underrun = %d - do xrun\n", + underrun_count); + underrun_count = 0; + return SNDRV_PCM_POS_XRUN; + } + } else { + /* Reset Counter */ + underrun_count = 0; } + t = intelhaddata->buf_info[buf_id].buf_size - t; if (intelhaddata->stream_info.buffer_rendered) -- cgit v1.2.3 From f0fd4122f0526b7575d10f6699b57f03e9bfd1ec Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Tue, 24 Jan 2017 23:41:46 +0800 Subject: ALSA: x86: fix resource_size.cocci warnings sound/x86/intel_hdmi_lpe_audio.c:498:24-27: ERROR: Missing resource_size with res_mmio Use resource_size function on resource object instead of explicit computation. Generated by: scripts/coccinelle/api/resource_size.cocci CC: Jerome Anand Signed-off-by: Fengguang Wu Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_lpe_audio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c index ce24ef1dd491..ead2d3af168c 100644 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ b/sound/x86/intel_hdmi_lpe_audio.c @@ -496,8 +496,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) (unsigned int)res_mmio->end); mmio_start = ioremap_nocache(res_mmio->start, - (size_t)((res_mmio->end - - res_mmio->start) + 1)); + (size_t)(resource_size(res_mmio))); if (!mmio_start) { dev_err(&hlpe_pdev->dev, "Could not get ioremap\n"); return -EACCES; -- cgit v1.2.3 From 0369d6315bc2bc56da2a2b15c8074b889096a47e Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 24 Jan 2017 17:07:48 +0100 Subject: ALSA: x86: hdmi: fix returnvar.cocci warnings Remove unneeded variable used to store return value. Generated by: scripts/coccinelle/misc/returnvar.cocci CC: Jerome Anand Signed-off-by: Julia Lawall Signed-off-by: Fengguang Wu Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio_if.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/sound/x86/intel_hdmi_audio_if.c b/sound/x86/intel_hdmi_audio_if.c index c650ba46d8b9..9ae242d62eb2 100644 --- a/sound/x86/intel_hdmi_audio_if.c +++ b/sound/x86/intel_hdmi_audio_if.c @@ -239,7 +239,6 @@ static inline int had_chk_intrmiss(struct snd_intelhad *intelhaddata, int had_process_buffer_done(struct snd_intelhad *intelhaddata) { - int retval = 0; u32 len = 1; enum intel_had_aud_buf_type buf_id; enum intel_had_aud_buf_type buff_done; @@ -258,7 +257,7 @@ int had_process_buffer_done(struct snd_intelhad *intelhaddata) if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); pr_err("%s:Device already disconnected\n", __func__); - return retval; + return 0; } buf_id = intelhaddata->curr_buf; intelhaddata->buff_done = buf_id; @@ -280,7 +279,7 @@ int had_process_buffer_done(struct snd_intelhad *intelhaddata) if (!intr_count || (intr_count > 3)) { pr_err("HAD SW state in non-recoverable!!! mode\n"); pr_err("Already played stale data\n"); - return retval; + return 0; } buf_id += (intr_count - 1); buf_id = buf_id % 4; @@ -298,7 +297,7 @@ int had_process_buffer_done(struct snd_intelhad *intelhaddata) if (had_get_hwstate(intelhaddata)) { pr_err("HDMI cable plugged-out\n"); - return retval; + return 0; } /*Reprogram the registers with addr and length*/ @@ -322,12 +321,11 @@ int had_process_buffer_done(struct snd_intelhad *intelhaddata) stream->period_elapsed(stream->had_substream); } - return retval; + return 0; } int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) { - int retval = 0; enum intel_had_aud_buf_type buf_id; struct pcm_stream_info *stream; struct had_pvt_data *had_stream; @@ -355,7 +353,7 @@ int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) if (drv_status == HAD_DRV_DISCONNECTED) { pr_err("%s:Device already disconnected\n", __func__); - return retval; + return 0; } if (stream_type == HAD_RUNNING_STREAM) { @@ -364,12 +362,11 @@ int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) stream->period_elapsed(stream->had_substream); } - return retval; + return 0; } int had_process_hot_plug(struct snd_intelhad *intelhaddata) { - int retval = 0; enum intel_had_aud_buf_type buf_id; struct snd_pcm_substream *substream; struct had_pvt_data *had_stream; @@ -384,7 +381,7 @@ int had_process_hot_plug(struct snd_intelhad *intelhaddata) if (intelhaddata->drv_status == HAD_DRV_CONNECTED) { pr_debug("Device already connected\n"); spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - return retval; + return 0; } buf_id = intelhaddata->curr_buf; intelhaddata->buff_done = buf_id; @@ -422,12 +419,12 @@ int had_process_hot_plug(struct snd_intelhad *intelhaddata) had_build_channel_allocation_map(intelhaddata); - return retval; + return 0; err: pm_runtime_disable(intelhaddata->dev); intelhaddata->dev = NULL; - return retval; + return 0; } int had_process_hot_unplug(struct snd_intelhad *intelhaddata) -- cgit v1.2.3 From eacc8dafa8d9e3dc8eee378ed030a6a447aa13c2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 26 Jan 2017 10:50:43 +0100 Subject: Documentation/gpu: Move LPE audio section after HD-audio As Daniel suggested, it makes more sense and reduces the conflicts. Also, while we're at it, tidy up the section title from all lower letters. Signed-off-by: Takashi Iwai --- Documentation/gpu/i915.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Documentation/gpu/i915.rst b/Documentation/gpu/i915.rst index a671eee78945..7fb605af090e 100644 --- a/Documentation/gpu/i915.rst +++ b/Documentation/gpu/i915.rst @@ -144,6 +144,15 @@ High Definition Audio .. kernel-doc:: include/drm/i915_component.h :internal: +Intel HDMI LPE Audio Support +---------------------------- + +.. kernel-doc:: drivers/gpu/drm/i915/intel_lpe_audio.c + :doc: LPE Audio integration for HDMI or DP playback + +.. kernel-doc:: drivers/gpu/drm/i915/intel_lpe_audio.c + :internal: + Panel Self Refresh PSR (PSR/SRD) -------------------------------- @@ -213,15 +222,6 @@ Video BIOS Table (VBT) .. kernel-doc:: drivers/gpu/drm/i915/intel_vbt_defs.h :internal: -intel hdmi lpe audio support ----------------------------- - -.. kernel-doc:: drivers/gpu/drm/i915/intel_lpe_audio.c - :doc: LPE Audio integration for HDMI or DP playback - -.. kernel-doc:: drivers/gpu/drm/i915/intel_lpe_audio.c - :internal: - Memory Management and Command Submission ======================================== -- cgit v1.2.3 From a6f9dec2a99aaae9950f57ceb3be1ffd897f3867 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Thu, 26 Jan 2017 21:11:05 +0530 Subject: ALSA: cs46xx: constify snd_pcm_ops structures Declare snd_pcm_ops structures as const as they are either stored in the ops field of a snd_pcm_substream structure or passed as an argument to the function snd_pcm_set_ops. The function argument and the ops field are of type const, so snd_pcm_ops structures having this property can be made const too. File size before: sound/pci/cs46xx/cs46xx_lib.o text data bss dec hex filename 26047 5304 16 31367 7a87 sound/pci/cs46xx/cs46xx_lib.o File size after: sound/pci/cs46xx/cs46xx_lib.o text data bss dec hex filename 27335 4036 16 31387 7a9b sound/pci/cs46xx/cs46xx_lib.o Signed-off-by: Bhumika Goyal Signed-off-by: Takashi Iwai --- sound/pci/cs46xx/cs46xx_lib.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index e561fd536f5b..e4cf3187b4dd 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -72,18 +72,18 @@ static void amp_voyetra(struct snd_cs46xx *chip, int change); #ifdef CONFIG_SND_CS46XX_NEW_DSP -static struct snd_pcm_ops snd_cs46xx_playback_rear_ops; -static struct snd_pcm_ops snd_cs46xx_playback_indirect_rear_ops; -static struct snd_pcm_ops snd_cs46xx_playback_clfe_ops; -static struct snd_pcm_ops snd_cs46xx_playback_indirect_clfe_ops; -static struct snd_pcm_ops snd_cs46xx_playback_iec958_ops; -static struct snd_pcm_ops snd_cs46xx_playback_indirect_iec958_ops; +static const struct snd_pcm_ops snd_cs46xx_playback_rear_ops; +static const struct snd_pcm_ops snd_cs46xx_playback_indirect_rear_ops; +static const struct snd_pcm_ops snd_cs46xx_playback_clfe_ops; +static const struct snd_pcm_ops snd_cs46xx_playback_indirect_clfe_ops; +static const struct snd_pcm_ops snd_cs46xx_playback_iec958_ops; +static const struct snd_pcm_ops snd_cs46xx_playback_indirect_iec958_ops; #endif -static struct snd_pcm_ops snd_cs46xx_playback_ops; -static struct snd_pcm_ops snd_cs46xx_playback_indirect_ops; -static struct snd_pcm_ops snd_cs46xx_capture_ops; -static struct snd_pcm_ops snd_cs46xx_capture_indirect_ops; +static const struct snd_pcm_ops snd_cs46xx_playback_ops; +static const struct snd_pcm_ops snd_cs46xx_playback_indirect_ops; +static const struct snd_pcm_ops snd_cs46xx_capture_ops; +static const struct snd_pcm_ops snd_cs46xx_capture_indirect_ops; static unsigned short snd_cs46xx_codec_read(struct snd_cs46xx *chip, unsigned short reg, @@ -1654,7 +1654,7 @@ static int snd_cs46xx_capture_close(struct snd_pcm_substream *substream) } #ifdef CONFIG_SND_CS46XX_NEW_DSP -static struct snd_pcm_ops snd_cs46xx_playback_rear_ops = { +static const struct snd_pcm_ops snd_cs46xx_playback_rear_ops = { .open = snd_cs46xx_playback_open_rear, .close = snd_cs46xx_playback_close, .ioctl = snd_pcm_lib_ioctl, @@ -1665,7 +1665,7 @@ static struct snd_pcm_ops snd_cs46xx_playback_rear_ops = { .pointer = snd_cs46xx_playback_direct_pointer, }; -static struct snd_pcm_ops snd_cs46xx_playback_indirect_rear_ops = { +static const struct snd_pcm_ops snd_cs46xx_playback_indirect_rear_ops = { .open = snd_cs46xx_playback_open_rear, .close = snd_cs46xx_playback_close, .ioctl = snd_pcm_lib_ioctl, @@ -1677,7 +1677,7 @@ static struct snd_pcm_ops snd_cs46xx_playback_indirect_rear_ops = { .ack = snd_cs46xx_playback_transfer, }; -static struct snd_pcm_ops snd_cs46xx_playback_clfe_ops = { +static const struct snd_pcm_ops snd_cs46xx_playback_clfe_ops = { .open = snd_cs46xx_playback_open_clfe, .close = snd_cs46xx_playback_close, .ioctl = snd_pcm_lib_ioctl, @@ -1688,7 +1688,7 @@ static struct snd_pcm_ops snd_cs46xx_playback_clfe_ops = { .pointer = snd_cs46xx_playback_direct_pointer, }; -static struct snd_pcm_ops snd_cs46xx_playback_indirect_clfe_ops = { +static const struct snd_pcm_ops snd_cs46xx_playback_indirect_clfe_ops = { .open = snd_cs46xx_playback_open_clfe, .close = snd_cs46xx_playback_close, .ioctl = snd_pcm_lib_ioctl, @@ -1700,7 +1700,7 @@ static struct snd_pcm_ops snd_cs46xx_playback_indirect_clfe_ops = { .ack = snd_cs46xx_playback_transfer, }; -static struct snd_pcm_ops snd_cs46xx_playback_iec958_ops = { +static const struct snd_pcm_ops snd_cs46xx_playback_iec958_ops = { .open = snd_cs46xx_playback_open_iec958, .close = snd_cs46xx_playback_close_iec958, .ioctl = snd_pcm_lib_ioctl, @@ -1711,7 +1711,7 @@ static struct snd_pcm_ops snd_cs46xx_playback_iec958_ops = { .pointer = snd_cs46xx_playback_direct_pointer, }; -static struct snd_pcm_ops snd_cs46xx_playback_indirect_iec958_ops = { +static const struct snd_pcm_ops snd_cs46xx_playback_indirect_iec958_ops = { .open = snd_cs46xx_playback_open_iec958, .close = snd_cs46xx_playback_close_iec958, .ioctl = snd_pcm_lib_ioctl, @@ -1725,7 +1725,7 @@ static struct snd_pcm_ops snd_cs46xx_playback_indirect_iec958_ops = { #endif -static struct snd_pcm_ops snd_cs46xx_playback_ops = { +static const struct snd_pcm_ops snd_cs46xx_playback_ops = { .open = snd_cs46xx_playback_open, .close = snd_cs46xx_playback_close, .ioctl = snd_pcm_lib_ioctl, @@ -1736,7 +1736,7 @@ static struct snd_pcm_ops snd_cs46xx_playback_ops = { .pointer = snd_cs46xx_playback_direct_pointer, }; -static struct snd_pcm_ops snd_cs46xx_playback_indirect_ops = { +static const struct snd_pcm_ops snd_cs46xx_playback_indirect_ops = { .open = snd_cs46xx_playback_open, .close = snd_cs46xx_playback_close, .ioctl = snd_pcm_lib_ioctl, @@ -1748,7 +1748,7 @@ static struct snd_pcm_ops snd_cs46xx_playback_indirect_ops = { .ack = snd_cs46xx_playback_transfer, }; -static struct snd_pcm_ops snd_cs46xx_capture_ops = { +static const struct snd_pcm_ops snd_cs46xx_capture_ops = { .open = snd_cs46xx_capture_open, .close = snd_cs46xx_capture_close, .ioctl = snd_pcm_lib_ioctl, @@ -1759,7 +1759,7 @@ static struct snd_pcm_ops snd_cs46xx_capture_ops = { .pointer = snd_cs46xx_capture_direct_pointer, }; -static struct snd_pcm_ops snd_cs46xx_capture_indirect_ops = { +static const struct snd_pcm_ops snd_cs46xx_capture_indirect_ops = { .open = snd_cs46xx_capture_open, .close = snd_cs46xx_capture_close, .ioctl = snd_pcm_lib_ioctl, -- cgit v1.2.3 From fc28ab1882b59f65d88f99348fdf01073e67349c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 31 Jan 2017 14:33:31 +0300 Subject: sound: oss/ad1848: remove some dead code We never use the irq2dev[] array so we can remove this assignment. Signed-off-by: Dan Carpenter Signed-off-by: Takashi Iwai --- sound/oss/ad1848.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/sound/oss/ad1848.c b/sound/oss/ad1848.c index 6368e5c7d0ba..f6156d8169d0 100644 --- a/sound/oss/ad1848.c +++ b/sound/oss/ad1848.c @@ -121,11 +121,6 @@ static bool deskpro_xl; static bool deskpro_m; static bool soundpro; -static volatile signed char irq2dev[17] = { - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1 -}; - #ifndef EXCLUDE_TIMERS static int timer_installed = -1; #endif @@ -2060,7 +2055,7 @@ int ad1848_init (char *name, struct resource *ports, int irq, int dma_playback, else devc->irq_ok = 1; /* Couldn't test. assume it's OK */ } else if (irq < 0) - irq2dev[-irq] = devc->dev_no = my_dev; + devc->dev_no = my_dev; #ifndef EXCLUDE_TIMERS if ((capabilities[devc->model].flags & CAP_F_TIMER) && -- cgit v1.2.3 From b5f2be9ae5bf88f5751cc9f5813ed28e7f87402d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 31 Jan 2017 14:16:48 -0600 Subject: drm/i915: add DP support in LPE audio mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If DisplayPort is detected, pass flag and link rate to audio driver Signed-off-by: Pierre-Louis Bossart Acked-by: Ville Syrjälä Signed-off-by: Takashi Iwai --- drivers/gpu/drm/i915/i915_drv.h | 3 ++- drivers/gpu/drm/i915/intel_audio.c | 19 +++++++++++++++---- drivers/gpu/drm/i915/intel_lpe_audio.c | 7 ++++++- include/drm/intel_lpe_audio.h | 2 ++ 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 3e3102cedc82..836d823d476b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3401,7 +3401,8 @@ int intel_lpe_audio_init(struct drm_i915_private *dev_priv); void intel_lpe_audio_teardown(struct drm_i915_private *dev_priv); void intel_lpe_audio_irq_handler(struct drm_i915_private *dev_priv); void intel_lpe_audio_notify(struct drm_i915_private *dev_priv, - void *eld, int port, int tmds_clk_speed); + void *eld, int port, int tmds_clk_speed, + bool dp_output, int link_rate); /* intel_i2c.c */ extern int intel_setup_gmbus(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 364f96207c40..1645ce42b898 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -631,9 +631,20 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder, if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, (int) port, (int) pipe); - - intel_lpe_audio_notify(dev_priv, connector->eld, port, - crtc_state->port_clock); + switch (intel_encoder->type) { + case INTEL_OUTPUT_HDMI: + intel_lpe_audio_notify(dev_priv, connector->eld, port, + crtc_state->port_clock, + false, 0); + break; + case INTEL_OUTPUT_DP: + intel_lpe_audio_notify(dev_priv, connector->eld, port, + adjusted_mode->crtc_clock, + true, crtc_state->port_clock); + break; + default: + break; + } } /** @@ -668,7 +679,7 @@ void intel_audio_codec_disable(struct intel_encoder *intel_encoder) acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, (int) port, (int) pipe); - intel_lpe_audio_notify(dev_priv, NULL, port, 0); + intel_lpe_audio_notify(dev_priv, NULL, port, 0, false, 0); } /** diff --git a/drivers/gpu/drm/i915/intel_lpe_audio.c b/drivers/gpu/drm/i915/intel_lpe_audio.c index 27d94255872d..245523e14418 100644 --- a/drivers/gpu/drm/i915/intel_lpe_audio.c +++ b/drivers/gpu/drm/i915/intel_lpe_audio.c @@ -332,7 +332,8 @@ void intel_lpe_audio_teardown(struct drm_i915_private *dev_priv) * Notify lpe audio driver of eld change. */ void intel_lpe_audio_notify(struct drm_i915_private *dev_priv, - void *eld, int port, int tmds_clk_speed) + void *eld, int port, int tmds_clk_speed, + bool dp_output, int link_rate) { unsigned long irq_flags; struct intel_hdmi_lpe_audio_pdata *pdata = NULL; @@ -351,12 +352,16 @@ void intel_lpe_audio_notify(struct drm_i915_private *dev_priv, pdata->eld.port_id = port; pdata->hdmi_connected = true; + pdata->dp_output = dp_output; if (tmds_clk_speed) pdata->tmds_clock_speed = tmds_clk_speed; + if (link_rate) + pdata->link_rate = link_rate; } else { memset(pdata->eld.eld_data, 0, HDMI_MAX_ELD_BYTES); pdata->hdmi_connected = false; + pdata->dp_output = false; } if (pdata->notify_audio_lpe) diff --git a/include/drm/intel_lpe_audio.h b/include/drm/intel_lpe_audio.h index 952de05a9d76..857e0eafed79 100644 --- a/include/drm/intel_lpe_audio.h +++ b/include/drm/intel_lpe_audio.h @@ -38,6 +38,8 @@ struct intel_hdmi_lpe_audio_pdata { bool notify_pending; int tmds_clock_speed; bool hdmi_connected; + bool dp_output; + int link_rate; struct intel_hdmi_lpe_audio_eld eld; void (*notify_audio_lpe)(void *audio_ptr); spinlock_t lpe_audio_slock; -- cgit v1.2.3 From d5d8c3a19e43ca588555d88e1d43a00aeacd0e56 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 31 Jan 2017 14:16:49 -0600 Subject: drm/i915: add DisplayPort amp unmute for LPE audio mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable unmute/mute amp notification. This doesn't seem to affect HDMI support so this is done unconditionally. An earlier version of this patch set a chicken bit at address 0x62F38 prior to the mute/unmute but this register doesn't seem to do anything so this phase was removed. v1->v2: Drop needless pipe A check, avoid temporary reg offset variable. v2->v3: Add "_" prefix to VLV_AUD_PORT_EN_X_DBG as they are internal. Signed-off-by: Pierre-Louis Bossart Acked-by: Ville Syrjälä Signed-off-by: Takashi Iwai --- drivers/gpu/drm/i915/i915_reg.h | 10 ++++++++++ drivers/gpu/drm/i915/intel_lpe_audio.c | 12 ++++++++++++ 2 files changed, 22 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index a9ffc8df241b..4e24ba0cdbe8 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2061,6 +2061,16 @@ enum skl_disp_power_wells { #define I915_HDMI_LPE_AUDIO_BASE (VLV_DISPLAY_BASE + 0x65000) #define I915_HDMI_LPE_AUDIO_SIZE 0x1000 +/* DisplayPort Audio w/ LPE */ +#define _VLV_AUD_PORT_EN_B_DBG (VLV_DISPLAY_BASE + 0x62F20) +#define _VLV_AUD_PORT_EN_C_DBG (VLV_DISPLAY_BASE + 0x62F30) +#define _VLV_AUD_PORT_EN_D_DBG (VLV_DISPLAY_BASE + 0x62F34) +#define VLV_AUD_PORT_EN_DBG(port) _MMIO_PORT3((port) - PORT_B, \ + _VLV_AUD_PORT_EN_B_DBG, \ + _VLV_AUD_PORT_EN_C_DBG, \ + _VLV_AUD_PORT_EN_D_DBG) +#define VLV_AMP_MUTE (1 << 1) + #define GEN6_BSD_RNCID _MMIO(0x12198) #define GEN7_FF_THREAD_MODE _MMIO(0x20a0) diff --git a/drivers/gpu/drm/i915/intel_lpe_audio.c b/drivers/gpu/drm/i915/intel_lpe_audio.c index 245523e14418..5da14f40f94a 100644 --- a/drivers/gpu/drm/i915/intel_lpe_audio.c +++ b/drivers/gpu/drm/i915/intel_lpe_audio.c @@ -337,6 +337,7 @@ void intel_lpe_audio_notify(struct drm_i915_private *dev_priv, { unsigned long irq_flags; struct intel_hdmi_lpe_audio_pdata *pdata = NULL; + u32 audio_enable; if (!HAS_LPE_AUDIO(dev_priv)) return; @@ -346,6 +347,8 @@ void intel_lpe_audio_notify(struct drm_i915_private *dev_priv, spin_lock_irqsave(&pdata->lpe_audio_slock, irq_flags); + audio_enable = I915_READ(VLV_AUD_PORT_EN_DBG(port)); + if (eld != NULL) { memcpy(pdata->eld.eld_data, eld, HDMI_MAX_ELD_BYTES); @@ -357,11 +360,20 @@ void intel_lpe_audio_notify(struct drm_i915_private *dev_priv, pdata->tmds_clock_speed = tmds_clk_speed; if (link_rate) pdata->link_rate = link_rate; + + /* Unmute the amp for both DP and HDMI */ + I915_WRITE(VLV_AUD_PORT_EN_DBG(port), + audio_enable & ~VLV_AMP_MUTE); + } else { memset(pdata->eld.eld_data, 0, HDMI_MAX_ELD_BYTES); pdata->hdmi_connected = false; pdata->dp_output = false; + + /* Mute the amp for both DP and HDMI */ + I915_WRITE(VLV_AUD_PORT_EN_DBG(port), + audio_enable | VLV_AMP_MUTE); } if (pdata->notify_audio_lpe) -- cgit v1.2.3 From 9c9191f3de5926830346750ce4417d261027ab80 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 14:16:50 -0600 Subject: drm/i915: Avoid MST pipe handling for LPE audio MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pipe gets cleared to -1 for non-MST before the ELD audio notification due to the MST audio support. This makes sense for HD-audio that received the MST handling, but it's useless for LPE audio. Handle the MST pipe hack conditionally only for HD-audio. Reported-by: Pierre-Louis Bossart Acked-by: Ville Syrjälä Signed-off-by: Takashi Iwai --- drivers/gpu/drm/i915/intel_audio.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 1645ce42b898..d4e6d1136cfe 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -624,13 +624,14 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder, dev_priv->av_enc_map[pipe] = intel_encoder; mutex_unlock(&dev_priv->av_mutex); - /* audio drivers expect pipe = -1 to indicate Non-MST cases */ - if (intel_encoder->type != INTEL_OUTPUT_DP_MST) - pipe = -1; - - if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) + if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) { + /* audio drivers expect pipe = -1 to indicate Non-MST cases */ + if (intel_encoder->type != INTEL_OUTPUT_DP_MST) + pipe = -1; acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, (int) port, (int) pipe); + } + switch (intel_encoder->type) { case INTEL_OUTPUT_HDMI: intel_lpe_audio_notify(dev_priv, connector->eld, port, @@ -671,13 +672,13 @@ void intel_audio_codec_disable(struct intel_encoder *intel_encoder) dev_priv->av_enc_map[pipe] = NULL; mutex_unlock(&dev_priv->av_mutex); - /* audio drivers expect pipe = -1 to indicate Non-MST cases */ - if (intel_encoder->type != INTEL_OUTPUT_DP_MST) - pipe = -1; - - if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) + if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) { + /* audio drivers expect pipe = -1 to indicate Non-MST cases */ + if (intel_encoder->type != INTEL_OUTPUT_DP_MST) + pipe = -1; acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, (int) port, (int) pipe); + } intel_lpe_audio_notify(dev_priv, NULL, port, 0, false, 0); } -- cgit v1.2.3 From f95e29b92190607c66dc5c96b7e0de9c332062c2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 14:16:51 -0600 Subject: drm/i915: Pass pipe to LPE audio notification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The LPE audio configuration depends on the pipe, thus we need to pass the currently used pipe. It's now embedded in struct intel_hdmi_lpe_audio_eld as well as port id. Acked-by: Ville Syrjälä Signed-off-by: Takashi Iwai --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/intel_audio.c | 6 +++--- drivers/gpu/drm/i915/intel_lpe_audio.c | 3 ++- include/drm/intel_lpe_audio.h | 1 + 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 836d823d476b..27311a337e2b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3401,7 +3401,7 @@ int intel_lpe_audio_init(struct drm_i915_private *dev_priv); void intel_lpe_audio_teardown(struct drm_i915_private *dev_priv); void intel_lpe_audio_irq_handler(struct drm_i915_private *dev_priv); void intel_lpe_audio_notify(struct drm_i915_private *dev_priv, - void *eld, int port, int tmds_clk_speed, + void *eld, int port, int pipe, int tmds_clk_speed, bool dp_output, int link_rate); /* intel_i2c.c */ diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index d4e6d1136cfe..892169b7952b 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -634,12 +634,12 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder, switch (intel_encoder->type) { case INTEL_OUTPUT_HDMI: - intel_lpe_audio_notify(dev_priv, connector->eld, port, + intel_lpe_audio_notify(dev_priv, connector->eld, port, pipe, crtc_state->port_clock, false, 0); break; case INTEL_OUTPUT_DP: - intel_lpe_audio_notify(dev_priv, connector->eld, port, + intel_lpe_audio_notify(dev_priv, connector->eld, port, pipe, adjusted_mode->crtc_clock, true, crtc_state->port_clock); break; @@ -680,7 +680,7 @@ void intel_audio_codec_disable(struct intel_encoder *intel_encoder) (int) port, (int) pipe); } - intel_lpe_audio_notify(dev_priv, NULL, port, 0, false, 0); + intel_lpe_audio_notify(dev_priv, NULL, port, pipe, 0, false, 0); } /** diff --git a/drivers/gpu/drm/i915/intel_lpe_audio.c b/drivers/gpu/drm/i915/intel_lpe_audio.c index 5da14f40f94a..68ebf3830433 100644 --- a/drivers/gpu/drm/i915/intel_lpe_audio.c +++ b/drivers/gpu/drm/i915/intel_lpe_audio.c @@ -332,7 +332,7 @@ void intel_lpe_audio_teardown(struct drm_i915_private *dev_priv) * Notify lpe audio driver of eld change. */ void intel_lpe_audio_notify(struct drm_i915_private *dev_priv, - void *eld, int port, int tmds_clk_speed, + void *eld, int port, int pipe, int tmds_clk_speed, bool dp_output, int link_rate) { unsigned long irq_flags; @@ -353,6 +353,7 @@ void intel_lpe_audio_notify(struct drm_i915_private *dev_priv, memcpy(pdata->eld.eld_data, eld, HDMI_MAX_ELD_BYTES); pdata->eld.port_id = port; + pdata->eld.pipe_id = pipe; pdata->hdmi_connected = true; pdata->dp_output = dp_output; diff --git a/include/drm/intel_lpe_audio.h b/include/drm/intel_lpe_audio.h index 857e0eafed79..410128e4cd70 100644 --- a/include/drm/intel_lpe_audio.h +++ b/include/drm/intel_lpe_audio.h @@ -31,6 +31,7 @@ struct intel_hdmi_lpe_audio_eld { int port_id; + int pipe_id; unsigned char eld_data[HDMI_MAX_ELD_BYTES]; }; -- cgit v1.2.3 From 964ca8083c0239b5a729ed08c9f50b6c31ab3a93 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 31 Jan 2017 14:16:52 -0600 Subject: ALSA: x86: intel_hdmi: add definitions and logic for DP audio Imported from legacy patches Note: the new code doesn't assume a modified ELD but an explicit notification that DP is present. It appears that the i915 code does change the ELD so we could use the ELD-based tests to check for DP audio Signed-off-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 173 +++++++++++++++++++++++++++++++++------ sound/x86/intel_hdmi_audio.h | 8 +- sound/x86/intel_hdmi_lpe_audio.c | 36 +++++++- sound/x86/intel_hdmi_lpe_audio.h | 29 +++++++ 4 files changed, 216 insertions(+), 30 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index f30155446117..5ce139c1b21d 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -396,6 +396,7 @@ static int snd_intelhad_prog_audio_ctrl_v2(struct snd_pcm_substream *substream, else cfg_val.cfg_regx_v2.layout = LAYOUT1; + cfg_val.cfg_regx_v2.val_bit = 1; had_write_register(AUD_CONFIG, cfg_val.cfg_regval); return 0; } @@ -447,6 +448,7 @@ static int snd_intelhad_prog_audio_ctrl_v1(struct snd_pcm_substream *substream, } + cfg_val.cfg_regx.val_bit = 1; had_write_register(AUD_CONFIG, cfg_val.cfg_regval); return 0; } @@ -548,6 +550,7 @@ void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata) } had_get_caps(HAD_GET_ELD, &intelhaddata->eeld); + had_get_caps(HAD_GET_DP_OUTPUT, &intelhaddata->dp_output); pr_debug("eeld.speaker_allocation_block = %x\n", intelhaddata->eeld.speaker_allocation_block); @@ -685,7 +688,7 @@ static void snd_intelhad_prog_dip_v1(struct snd_pcm_substream *substream, /*Calculte the byte wide checksum for all valid DIP words*/ for (i = 0; i < BYTES_PER_WORD; i++) - checksum += (INFO_FRAME_WORD1 >> i*BITS_PER_BYTE) & MASK_BYTE0; + checksum += (HDMI_INFO_FRAME_WORD1 >> i*BITS_PER_BYTE) & MASK_BYTE0; for (i = 0; i < BYTES_PER_WORD; i++) checksum += (frame2.fr2_val >> i*BITS_PER_BYTE) & MASK_BYTE0; for (i = 0; i < BYTES_PER_WORD; i++) @@ -693,7 +696,7 @@ static void snd_intelhad_prog_dip_v1(struct snd_pcm_substream *substream, frame2.fr2_regx.chksum = -(checksum); - had_write_register(AUD_HDMIW_INFOFR, INFO_FRAME_WORD1); + had_write_register(AUD_HDMIW_INFOFR, HDMI_INFO_FRAME_WORD1); had_write_register(AUD_HDMIW_INFOFR, frame2.fr2_val); had_write_register(AUD_HDMIW_INFOFR, frame3.fr3_val); @@ -722,28 +725,35 @@ static void snd_intelhad_prog_dip_v2(struct snd_pcm_substream *substream, union aud_info_frame2 frame2 = {.fr2_val = 0}; union aud_info_frame3 frame3 = {.fr3_val = 0}; u8 checksum = 0; + u32 info_frame; int channels; channels = substream->runtime->channels; had_write_register(AUD_CNTL_ST, ctrl_state.ctrl_val); - frame2.fr2_regx.chnl_cnt = substream->runtime->channels - 1; + if (intelhaddata->dp_output) { + info_frame = DP_INFO_FRAME_WORD1; + frame2.fr2_val = 1; + } else { + info_frame = HDMI_INFO_FRAME_WORD1; + frame2.fr2_regx.chnl_cnt = substream->runtime->channels - 1; - frame3.fr3_regx.chnl_alloc = snd_intelhad_channel_allocation( - intelhaddata, channels); + frame3.fr3_regx.chnl_alloc = snd_intelhad_channel_allocation( + intelhaddata, channels); - /*Calculte the byte wide checksum for all valid DIP words*/ - for (i = 0; i < BYTES_PER_WORD; i++) - checksum += (INFO_FRAME_WORD1 >> i*BITS_PER_BYTE) & MASK_BYTE0; - for (i = 0; i < BYTES_PER_WORD; i++) - checksum += (frame2.fr2_val >> i*BITS_PER_BYTE) & MASK_BYTE0; - for (i = 0; i < BYTES_PER_WORD; i++) - checksum += (frame3.fr3_val >> i*BITS_PER_BYTE) & MASK_BYTE0; + /*Calculte the byte wide checksum for all valid DIP words*/ + for (i = 0; i < BYTES_PER_WORD; i++) + checksum += (info_frame >> i*BITS_PER_BYTE) & MASK_BYTE0; + for (i = 0; i < BYTES_PER_WORD; i++) + checksum += (frame2.fr2_val >> i*BITS_PER_BYTE) & MASK_BYTE0; + for (i = 0; i < BYTES_PER_WORD; i++) + checksum += (frame3.fr3_val >> i*BITS_PER_BYTE) & MASK_BYTE0; - frame2.fr2_regx.chksum = -(checksum); + frame2.fr2_regx.chksum = -(checksum); + } - had_write_register(AUD_HDMIW_INFOFR_v2, INFO_FRAME_WORD1); + had_write_register(AUD_HDMIW_INFOFR_v2, info_frame); had_write_register(AUD_HDMIW_INFOFR_v2, frame2.fr2_val); had_write_register(AUD_HDMIW_INFOFR_v2, frame3.fr3_val); @@ -839,6 +849,85 @@ int snd_intelhad_read_len(struct snd_intelhad *intelhaddata) return retval; } +static int had_calculate_maud_value(u32 aud_samp_freq, u32 link_rate) +{ + u32 maud_val; + + /* Select maud according to DP 1.2 spec*/ + if (link_rate == DP_2_7_GHZ) { + switch (aud_samp_freq) { + case AUD_SAMPLE_RATE_32: + maud_val = AUD_SAMPLE_RATE_32_DP_2_7_MAUD_VAL; + break; + + case AUD_SAMPLE_RATE_44_1: + maud_val = AUD_SAMPLE_RATE_44_1_DP_2_7_MAUD_VAL; + break; + + case AUD_SAMPLE_RATE_48: + maud_val = AUD_SAMPLE_RATE_48_DP_2_7_MAUD_VAL; + break; + + case AUD_SAMPLE_RATE_88_2: + maud_val = AUD_SAMPLE_RATE_88_2_DP_2_7_MAUD_VAL; + break; + + case AUD_SAMPLE_RATE_96: + maud_val = AUD_SAMPLE_RATE_96_DP_2_7_MAUD_VAL; + break; + + case AUD_SAMPLE_RATE_176_4: + maud_val = AUD_SAMPLE_RATE_176_4_DP_2_7_MAUD_VAL; + break; + + case HAD_MAX_RATE: + maud_val = HAD_MAX_RATE_DP_2_7_MAUD_VAL; + break; + + default: + maud_val = -EINVAL; + break; + } + } else if (link_rate == DP_1_62_GHZ) { + switch (aud_samp_freq) { + case AUD_SAMPLE_RATE_32: + maud_val = AUD_SAMPLE_RATE_32_DP_1_62_MAUD_VAL; + break; + + case AUD_SAMPLE_RATE_44_1: + maud_val = AUD_SAMPLE_RATE_44_1_DP_1_62_MAUD_VAL; + break; + + case AUD_SAMPLE_RATE_48: + maud_val = AUD_SAMPLE_RATE_48_DP_1_62_MAUD_VAL; + break; + + case AUD_SAMPLE_RATE_88_2: + maud_val = AUD_SAMPLE_RATE_88_2_DP_1_62_MAUD_VAL; + break; + + case AUD_SAMPLE_RATE_96: + maud_val = AUD_SAMPLE_RATE_96_DP_1_62_MAUD_VAL; + break; + + case AUD_SAMPLE_RATE_176_4: + maud_val = AUD_SAMPLE_RATE_176_4_DP_1_62_MAUD_VAL; + break; + + case HAD_MAX_RATE: + maud_val = HAD_MAX_RATE_DP_1_62_MAUD_VAL; + break; + + default: + maud_val = -EINVAL; + break; + } + } else + maud_val = -EINVAL; + + return maud_val; +} + /** * snd_intelhad_prog_cts_v1 - Program HDMI audio CTS value * @@ -849,8 +938,9 @@ int snd_intelhad_read_len(struct snd_intelhad *intelhaddata) * * Program CTS register based on the audio and display sampling frequency */ -static void snd_intelhad_prog_cts_v1(u32 aud_samp_freq, u32 tmds, u32 n_param, - struct snd_intelhad *intelhaddata) +static void snd_intelhad_prog_cts_v1(u32 aud_samp_freq, u32 tmds, + u32 link_rate, u32 n_param, + struct snd_intelhad *intelhaddata) { u32 cts_val; u64 dividend, divisor; @@ -874,18 +964,24 @@ static void snd_intelhad_prog_cts_v1(u32 aud_samp_freq, u32 tmds, u32 n_param, * * Program CTS register based on the audio and display sampling frequency */ -static void snd_intelhad_prog_cts_v2(u32 aud_samp_freq, u32 tmds, u32 n_param, - struct snd_intelhad *intelhaddata) +static void snd_intelhad_prog_cts_v2(u32 aud_samp_freq, u32 tmds, + u32 link_rate, u32 n_param, + struct snd_intelhad *intelhaddata) { u32 cts_val; u64 dividend, divisor; - /* Calculate CTS according to HDMI 1.3a spec*/ - dividend = (u64)tmds * n_param*1000; - divisor = 128 * aud_samp_freq; - cts_val = div64_u64(dividend, divisor); + if (intelhaddata->dp_output) { + /* Substitute cts_val with Maud according to DP 1.2 spec*/ + cts_val = had_calculate_maud_value(aud_samp_freq, link_rate); + } else { + /* Calculate CTS according to HDMI 1.3a spec*/ + dividend = (u64)tmds * n_param*1000; + divisor = 128 * aud_samp_freq; + cts_val = div64_u64(dividend, divisor); + } pr_debug("TMDS value=%d, N value=%d, CTS Value=%d\n", - tmds, n_param, cts_val); + tmds, n_param, cts_val); had_write_register(AUD_HDMI_CTS, (BIT(24) | cts_val)); } @@ -970,7 +1066,18 @@ static int snd_intelhad_prog_n_v2(u32 aud_samp_freq, u32 *n_param, { s32 n_val; - n_val = had_calculate_n_value(aud_samp_freq); + if (intelhaddata->dp_output) { + /* + * According to DP specs, Maud and Naud values hold + * a relationship, which is stated as: + * Maud/Naud = 512 * fs / f_LS_Clk + * where, fs is the sampling frequency of the audio stream + * and Naud is 32768 for Async clock. + */ + + n_val = DP_NAUD_VAL; + } else + n_val = had_calculate_n_value(aud_samp_freq); if (n_val < 0) return n_val; @@ -1343,6 +1450,7 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) { int retval; u32 disp_samp_freq, n_param; + u32 link_rate = 0; struct snd_intelhad *intelhaddata; struct snd_pcm_runtime *runtime; struct had_pvt_data *had_stream; @@ -1387,6 +1495,7 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) } had_get_caps(HAD_GET_ELD, &intelhaddata->eeld); + had_get_caps(HAD_GET_DP_OUTPUT, &intelhaddata->dp_output); retval = intelhaddata->ops->prog_n(substream->runtime->rate, &n_param, intelhaddata); @@ -1394,8 +1503,14 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) pr_err("programming N value failed %#x\n", retval); goto prep_end; } + + if (intelhaddata->dp_output) + had_get_caps(HAD_GET_LINK_RATE, &link_rate); + + intelhaddata->ops->prog_cts(substream->runtime->rate, - disp_samp_freq, n_param, intelhaddata); + disp_samp_freq, link_rate, + n_param, intelhaddata); intelhaddata->ops->prog_dip(substream, intelhaddata); @@ -1503,6 +1618,7 @@ int hdmi_audio_mode_change(struct snd_pcm_substream *substream) { int retval = 0; u32 disp_samp_freq, n_param; + u32 link_rate = 0; struct snd_intelhad *intelhaddata; intelhaddata = snd_pcm_substream_chip(substream); @@ -1523,8 +1639,13 @@ int hdmi_audio_mode_change(struct snd_pcm_substream *substream) pr_err("programming N value failed %#x\n", retval); goto out; } + + if (intelhaddata->dp_output) + had_get_caps(HAD_GET_LINK_RATE, &link_rate); + intelhaddata->ops->prog_cts(substream->runtime->rate, - disp_samp_freq, n_param, intelhaddata); + disp_samp_freq, link_rate, + n_param, intelhaddata); /* Enable Audio */ intelhaddata->ops->enable_audio(substream, 1); diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index d2015ec84843..034b3873ffa1 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -44,7 +44,8 @@ #define MAX_CAP_STREAMS 0 #define HDMI_AUDIO_DRIVER "hdmi-audio" -#define INFO_FRAME_WORD1 0x000a0184 +#define HDMI_INFO_FRAME_WORD1 0x000a0184 +#define DP_INFO_FRAME_WORD1 0x00441b84 #define FIFO_THRESHOLD 0xFE #define DMA_FIFO_THRESHOLD 0x7 #define BYTES_PER_WORD 0x4 @@ -134,6 +135,7 @@ struct snd_intelhad { struct ring_buf_info buf_info[HAD_NUM_OF_RING_BUFS]; struct pcm_stream_info stream_info; union otm_hdmi_eld_t eeld; + bool dp_output; enum intel_had_aud_buf_type curr_buf; int valid_buf_cnt; unsigned int aes_bits; @@ -156,8 +158,8 @@ struct had_ops { void (*reset_audio)(u8 reset); int (*prog_n)(u32 aud_samp_freq, u32 *n_param, struct snd_intelhad *intelhaddata); - void (*prog_cts)(u32 aud_samp_freq, u32 tmds, u32 n_param, - struct snd_intelhad *intelhaddata); + void (*prog_cts)(u32 aud_samp_freq, u32 tmds, u32 link_rate, + u32 n_param, struct snd_intelhad *intelhaddata); int (*audio_ctrl)(struct snd_pcm_substream *substream, struct snd_intelhad *intelhaddata); void (*prog_dip)(struct snd_pcm_substream *substream, diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c index ead2d3af168c..cea05dfc081a 100644 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ b/sound/x86/intel_hdmi_lpe_audio.c @@ -48,6 +48,8 @@ struct hdmi_lpe_audio_ctx { struct snd_intel_had_interface *had_interface; void *had_pvt_data; int tmds_clock_speed; + bool dp_output; + int link_rate; unsigned int had_config_offset; int hdmi_audio_interrupt_mask; struct work_struct hdmi_audio_wq; @@ -187,6 +189,15 @@ static int hdmi_audio_write(u32 reg, u32 val) dev_dbg(&hlpe_pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, reg, val); + if (ctx->dp_output) { + if ((reg == AUDIO_HDMI_CONFIG_A) || + (reg == AUDIO_HDMI_CONFIG_B) || + (reg == AUDIO_HDMI_CONFIG_C)) { + if (val & AUD_CONFIG_VALID_BIT) + val = val | AUD_CONFIG_DP_MODE | + AUD_CONFIG_BLOCK_BIT; + } + } iowrite32(val, (ctx->mmio_start+reg)); return 0; @@ -220,6 +231,16 @@ static int hdmi_audio_rmw(u32 reg, u32 val, u32 mask) val_tmp = (val & mask) | ((ioread32(ctx->mmio_start + reg)) & ~mask); + if (ctx->dp_output) { + if ((reg == AUDIO_HDMI_CONFIG_A) || + (reg == AUDIO_HDMI_CONFIG_B) || + (reg == AUDIO_HDMI_CONFIG_C)) { + if (val_tmp & AUD_CONFIG_VALID_BIT) + val_tmp = val_tmp | AUD_CONFIG_DP_MODE | + AUD_CONFIG_BLOCK_BIT; + } + } + iowrite32(val_tmp, (ctx->mmio_start+reg)); dev_dbg(&hlpe_pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, reg, val_tmp); @@ -249,7 +270,18 @@ static int hdmi_audio_get_caps(enum had_caps_list get_element, /* ToDo: Verify if sampling freq logic is correct */ *(u32 *)capabilities = ctx->tmds_clock_speed; dev_dbg(&hlpe_pdev->dev, "%s: tmds_clock_speed = 0x%x\n", - __func__, ctx->tmds_clock_speed); + __func__, ctx->tmds_clock_speed); + break; + case HAD_GET_LINK_RATE: + /* ToDo: Verify if sampling freq logic is correct */ + *(u32 *)capabilities = ctx->link_rate; + dev_dbg(&hlpe_pdev->dev, "%s: link rate = 0x%x\n", + __func__, ctx->link_rate); + break; + case HAD_GET_DP_OUTPUT: + *(u32 *)capabilities = ctx->dp_output; + dev_dbg(&hlpe_pdev->dev, "%s: dp_output = %d\n", + __func__, ctx->dp_output); break; default: break; @@ -442,6 +474,8 @@ static void notify_audio_lpe(void *audio_ptr) if (pdata->tmds_clock_speed) { ctx->tmds_clock_speed = pdata->tmds_clock_speed; + ctx->dp_output = pdata->dp_output; + ctx->link_rate = pdata->link_rate; mid_hdmi_audio_signal_event(HAD_EVENT_MODE_CHANGING); } } else diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index ec4bde50dba7..3aed89af5b45 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -31,6 +31,10 @@ #include #include +#define AUD_CONFIG_VALID_BIT (1<<9) +#define AUD_CONFIG_DP_MODE (1<<15) +#define AUD_CONFIG_BLOCK_BIT (1<<7) + #define HMDI_LPE_AUDIO_DRIVER_NAME "intel-hdmi-lpe-audio" #define HAD_MAX_DEVICES 1 #define HAD_MIN_CHANNEL 2 @@ -68,6 +72,29 @@ #define HAD_MAX_DIP_WORDS 16 #define INTEL_HAD "IntelHdmiLpeAudio" +/* DP Link Rates */ +#define DP_2_7_GHZ 270000 +#define DP_1_62_GHZ 162000 + +/* Maud Values */ +#define AUD_SAMPLE_RATE_32_DP_2_7_MAUD_VAL 1988 +#define AUD_SAMPLE_RATE_44_1_DP_2_7_MAUD_VAL 2740 +#define AUD_SAMPLE_RATE_48_DP_2_7_MAUD_VAL 2982 +#define AUD_SAMPLE_RATE_88_2_DP_2_7_MAUD_VAL 5480 +#define AUD_SAMPLE_RATE_96_DP_2_7_MAUD_VAL 5965 +#define AUD_SAMPLE_RATE_176_4_DP_2_7_MAUD_VAL 10961 +#define HAD_MAX_RATE_DP_2_7_MAUD_VAL 11930 +#define AUD_SAMPLE_RATE_32_DP_1_62_MAUD_VAL 3314 +#define AUD_SAMPLE_RATE_44_1_DP_1_62_MAUD_VAL 4567 +#define AUD_SAMPLE_RATE_48_DP_1_62_MAUD_VAL 4971 +#define AUD_SAMPLE_RATE_88_2_DP_1_62_MAUD_VAL 9134 +#define AUD_SAMPLE_RATE_96_DP_1_62_MAUD_VAL 9942 +#define AUD_SAMPLE_RATE_176_4_DP_1_62_MAUD_VAL 18268 +#define HAD_MAX_RATE_DP_1_62_MAUD_VAL 19884 + +/* Naud Value */ +#define DP_NAUD_VAL 32768 + /* _AUD_CONFIG register MASK */ #define AUD_CONFIG_MASK_UNDERRUN 0xC0000000 #define AUD_CONFIG_MASK_SRDBG 0x00000002 @@ -618,6 +645,8 @@ enum hdmi_connector_status { enum had_caps_list { HAD_GET_ELD = 1, HAD_GET_DISPLAY_RATE, + HAD_GET_DP_OUTPUT, + HAD_GET_LINK_RATE, HAD_SET_ENABLE_AUDIO, HAD_SET_DISABLE_AUDIO, HAD_SET_ENABLE_AUDIO_INT, -- cgit v1.2.3 From 0843e043cf2e5d12a4041efd9c794a213a3ef93b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 31 Jan 2017 14:16:53 -0600 Subject: ALSA: x86: Use config base depending on the pipe Now the pipe that is being used is passed over i915 notification, we can re-setup the relevant register offset depending on pipe assignments during hotplug. This allows playback on single port machines such Zotac Pi330 or dual-port machines such as Dell Wyse 3040 box Signed-off-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_lpe_audio.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c index cea05dfc081a..6d630f20bca8 100644 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ b/sound/x86/intel_hdmi_lpe_audio.c @@ -463,6 +463,22 @@ static void notify_audio_lpe(void *audio_ptr) } else if (eld != NULL) { + switch (eld->pipe_id) { + case 0: + ctx->had_config_offset = AUDIO_HDMI_CONFIG_A; + break; + case 1: + ctx->had_config_offset = AUDIO_HDMI_CONFIG_B; + break; + case 2: + ctx->had_config_offset = AUDIO_HDMI_CONFIG_C; + break; + default: + dev_dbg(&hlpe_pdev->dev, "Invalid pipe %d\n", + eld->pipe_id); + break; + } + hdmi_set_eld(eld->eld_data); mid_hdmi_audio_signal_event(HAD_EVENT_HOT_PLUG); @@ -560,15 +576,15 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) ctx->mmio_start = mmio_start; ctx->tmds_clock_speed = DIS_SAMPLE_RATE_148_5; - if (pci_dev_present(cherryview_ids)) { + if (pci_dev_present(cherryview_ids)) dev_dbg(&hlpe_pdev->dev, "%s: Cherrytrail LPE - Detected\n", __func__); - ctx->had_config_offset = AUDIO_HDMI_CONFIG_C; - } else { + else dev_dbg(&hlpe_pdev->dev, "%s: Baytrail LPE - Assume\n", __func__); - ctx->had_config_offset = AUDIO_HDMI_CONFIG_A; - } + + /* assume pipe A as default */ + ctx->had_config_offset = AUDIO_HDMI_CONFIG_A; pdata = pdev->dev.platform_data; -- cgit v1.2.3 From b1c01f4df20a6376fe6245644225ff9fe97c5f95 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Jan 2017 17:56:39 +0100 Subject: drm/i915: Pass platform device to LPE audio notifier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows the LPE HDMI driver to clean up its global variable reference. Also drop to pass the eld pointer because the connection status and the ELD bytes can be retrieved from the attached pdata. Acked-by: Ville Syrjälä Signed-off-by: Takashi Iwai --- drivers/gpu/drm/i915/intel_lpe_audio.c | 3 +-- include/drm/intel_lpe_audio.h | 4 +++- sound/x86/intel_hdmi_lpe_audio.c | 23 +++++++++++------------ 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lpe_audio.c b/drivers/gpu/drm/i915/intel_lpe_audio.c index 68ebf3830433..d3ffe0012692 100644 --- a/drivers/gpu/drm/i915/intel_lpe_audio.c +++ b/drivers/gpu/drm/i915/intel_lpe_audio.c @@ -378,8 +378,7 @@ void intel_lpe_audio_notify(struct drm_i915_private *dev_priv, } if (pdata->notify_audio_lpe) - pdata->notify_audio_lpe( - (eld != NULL) ? &pdata->eld : NULL); + pdata->notify_audio_lpe(dev_priv->lpe_audio.platdev); else pdata->notify_pending = true; diff --git a/include/drm/intel_lpe_audio.h b/include/drm/intel_lpe_audio.h index 410128e4cd70..e9892b4c3af1 100644 --- a/include/drm/intel_lpe_audio.h +++ b/include/drm/intel_lpe_audio.h @@ -27,6 +27,8 @@ #include #include +struct platform_device; + #define HDMI_MAX_ELD_BYTES 128 struct intel_hdmi_lpe_audio_eld { @@ -42,7 +44,7 @@ struct intel_hdmi_lpe_audio_pdata { bool dp_output; int link_rate; struct intel_hdmi_lpe_audio_eld eld; - void (*notify_audio_lpe)(void *audio_ptr); + void (*notify_audio_lpe)(struct platform_device *pdev); spinlock_t lpe_audio_slock; }; diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c index 6d630f20bca8..3cb0f642575c 100644 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ b/sound/x86/intel_hdmi_lpe_audio.c @@ -439,15 +439,14 @@ static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id) return IRQ_HANDLED; } -static void notify_audio_lpe(void *audio_ptr) +static void notify_audio_lpe(struct platform_device *pdev) { - struct hdmi_lpe_audio_ctx *ctx = get_hdmi_context(); - struct intel_hdmi_lpe_audio_pdata *pdata = hlpe_pdev->dev.platform_data; - struct intel_hdmi_lpe_audio_eld *eld = audio_ptr; + struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); + struct intel_hdmi_lpe_audio_pdata *pdata = pdev->dev.platform_data; if (pdata->hdmi_connected != true) { - dev_dbg(&hlpe_pdev->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG\n", + dev_dbg(&pdev->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG\n", __func__); if (hlpe_state == hdmi_connector_status_connected) { @@ -458,10 +457,11 @@ static void notify_audio_lpe(void *audio_ptr) mid_hdmi_audio_signal_event( HAD_EVENT_HOT_UNPLUG); } else - dev_dbg(&hlpe_pdev->dev, "%s: Already Unplugged!\n", + dev_dbg(&pdev->dev, "%s: Already Unplugged!\n", __func__); - } else if (eld != NULL) { + } else { + struct intel_hdmi_lpe_audio_eld *eld = &pdata->eld; switch (eld->pipe_id) { case 0: @@ -474,7 +474,7 @@ static void notify_audio_lpe(void *audio_ptr) ctx->had_config_offset = AUDIO_HDMI_CONFIG_C; break; default: - dev_dbg(&hlpe_pdev->dev, "Invalid pipe %d\n", + dev_dbg(&pdev->dev, "Invalid pipe %d\n", eld->pipe_id); break; } @@ -485,7 +485,7 @@ static void notify_audio_lpe(void *audio_ptr) hlpe_state = hdmi_connector_status_connected; - dev_dbg(&hlpe_pdev->dev, "%s: HAD_NOTIFY_ELD : port = %d, tmds = %d\n", + dev_dbg(&pdev->dev, "%s: HAD_NOTIFY_ELD : port = %d, tmds = %d\n", __func__, eld->port_id, pdata->tmds_clock_speed); if (pdata->tmds_clock_speed) { @@ -494,8 +494,7 @@ static void notify_audio_lpe(void *audio_ptr) ctx->link_rate = pdata->link_rate; mid_hdmi_audio_signal_event(HAD_EVENT_MODE_CHANGING); } - } else - dev_dbg(&hlpe_pdev->dev, "%s: Event: NULL EDID!!\n", __func__); + } } /** @@ -606,7 +605,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) if (pdata->notify_pending) { dev_dbg(&hlpe_pdev->dev, "%s: handle pending notification\n", __func__); - notify_audio_lpe(&pdata->eld); + notify_audio_lpe(pdev); pdata->notify_pending = false; } spin_unlock_irqrestore(&pdata->lpe_audio_slock, flag_irq); -- cgit v1.2.3 From 9db13e5f2d6dc85150cb8a69ab220b84d9b9fbe7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 2 Feb 2017 11:03:48 +0100 Subject: drm/i915: Enable VLV audio chicken bit for LPE audio MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The audio chicken bit (register offset 0x62f38) seems required to make DP audio working on some machines. At least, on Dell Wyse 3040, I failed to get the audio unless this bit is set once. Strangely, the bit seems necessary only once, and it persists after that, even some power-off cycles. The register is supposedly write-only, so it's no evidence whether the bit keeps effect persistently. But, judging from the experiment, it looks enough to set it up once at the device initialization. The patch is basically a cut from the original patch by Pierre-Louis Bossart. v1->v2: drop read since it's a write-only reg. Cc: Pierre-Louis Bossart Reviewed-by: Ville Syrjälä Signed-off-by: Takashi Iwai --- drivers/gpu/drm/i915/i915_reg.h | 3 +++ drivers/gpu/drm/i915/intel_lpe_audio.c | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 4e24ba0cdbe8..4f15a3dc6d98 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2062,6 +2062,9 @@ enum skl_disp_power_wells { #define I915_HDMI_LPE_AUDIO_SIZE 0x1000 /* DisplayPort Audio w/ LPE */ +#define VLV_AUD_CHICKEN_BIT_REG _MMIO(VLV_DISPLAY_BASE + 0x62F38) +#define VLV_CHICKEN_BIT_DBG_ENABLE (1 << 0) + #define _VLV_AUD_PORT_EN_B_DBG (VLV_DISPLAY_BASE + 0x62F20) #define _VLV_AUD_PORT_EN_C_DBG (VLV_DISPLAY_BASE + 0x62F30) #define _VLV_AUD_PORT_EN_D_DBG (VLV_DISPLAY_BASE + 0x62F34) diff --git a/drivers/gpu/drm/i915/intel_lpe_audio.c b/drivers/gpu/drm/i915/intel_lpe_audio.c index d3ffe0012692..7a5b41b1c024 100644 --- a/drivers/gpu/drm/i915/intel_lpe_audio.c +++ b/drivers/gpu/drm/i915/intel_lpe_audio.c @@ -248,6 +248,11 @@ static int lpe_audio_setup(struct drm_i915_private *dev_priv) goto err_free_irq; } + /* enable chicken bit; at least this is required for Dell Wyse 3040 + * with DP outputs (but only sometimes by some reason!) + */ + I915_WRITE(VLV_AUD_CHICKEN_BIT_REG, VLV_CHICKEN_BIT_DBG_ENABLE); + return 0; err_free_irq: irq_free_desc(dev_priv->lpe_audio.irq); -- cgit v1.2.3 From 716733032ab3203498f17f785c2e1d1ca08a51a1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 07:30:20 +0100 Subject: ALSA: x86: Don't set PCM state to DISCONNECTED Theoretically setting the state to SNDRV_PCM_STATE_DISCONNECTED is correct. But, unfortunately, PA gets confused by this action, and it won't re-probe the device after HDMI/DP is re-plugged. (It reprobes only when the card itself is recreated.) As a workaround, set SNDRV_PCM_STATE_SETUP instead. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio_if.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/x86/intel_hdmi_audio_if.c b/sound/x86/intel_hdmi_audio_if.c index 9ae242d62eb2..30b4b25acb24 100644 --- a/sound/x86/intel_hdmi_audio_if.c +++ b/sound/x86/intel_hdmi_audio_if.c @@ -464,7 +464,7 @@ int had_process_hot_unplug(struct snd_intelhad *intelhaddata) spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); pr_debug("%s: unlock -> sending pcm_stop -> lock\n", __func__); snd_pcm_stop(intelhaddata->stream_info.had_substream, - SNDRV_PCM_STATE_DISCONNECTED); + SNDRV_PCM_STATE_SETUP); spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); } -- cgit v1.2.3 From 4812dcc437fbe0ddc2319dae7c31254f57d4ae44 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Jan 2017 15:58:15 +0100 Subject: ALSA: x86: Remove v1 ops and structs The v1 code refers to Medfield/Clovertrail. It's not used at all in the current driver, and probably won't be ever. Let's clean this up, then we can go to the next stage of cleanup tasks. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 206 +-------------------------------------- sound/x86/intel_hdmi_lpe_audio.h | 29 ------ 2 files changed, 1 insertion(+), 234 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 5ce139c1b21d..1e0bc72a8f63 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -280,23 +280,12 @@ static int had_read_modify_aud_config_v2(struct snd_pcm_substream *substream, return had_read_modify(AUD_CONFIG, data, mask); } -static void snd_intelhad_enable_audio_v1(struct snd_pcm_substream *substream, - u8 enable) -{ - had_read_modify(AUD_CONFIG, enable, BIT(0)); -} - static void snd_intelhad_enable_audio_v2(struct snd_pcm_substream *substream, u8 enable) { had_read_modify_aud_config_v2(substream, enable, BIT(0)); } -static void snd_intelhad_reset_audio_v1(u8 reset) -{ - had_write_register(AUD_HDMI_STATUS, reset); -} - static void snd_intelhad_reset_audio_v2(u8 reset) { had_write_register(AUD_HDMI_STATUS_v2, reset); @@ -320,7 +309,7 @@ static int had_prog_status_reg(struct snd_pcm_substream *substream, IEC958_AES0_NONAUDIO)>>1; ch_stat0.status_0_regx.clk_acc = (intelhaddata->aes_bits & IEC958_AES3_CON_CLOCK)>>4; - cfg_val.cfg_regx.val_bit = ch_stat0.status_0_regx.lpcm_id; + cfg_val.cfg_regx_v2.val_bit = ch_stat0.status_0_regx.lpcm_id; switch (substream->runtime->rate) { case AUD_SAMPLE_RATE_32: @@ -401,58 +390,6 @@ static int snd_intelhad_prog_audio_ctrl_v2(struct snd_pcm_substream *substream, return 0; } -/** - * function to initialize audio - * registers and buffer confgiuration registers - * This function is called in the prepare callback - */ -static int snd_intelhad_prog_audio_ctrl_v1(struct snd_pcm_substream *substream, - struct snd_intelhad *intelhaddata) -{ - union aud_cfg cfg_val = {.cfg_regval = 0}; - union aud_buf_config buf_cfg = {.buf_cfgval = 0}; - u8 channels; - - had_prog_status_reg(substream, intelhaddata); - - buf_cfg.buf_cfg_regx.fifo_width = FIFO_THRESHOLD; - buf_cfg.buf_cfg_regx.aud_delay = 0; - had_write_register(AUD_BUF_CONFIG, buf_cfg.buf_cfgval); - - channels = substream->runtime->channels; - - switch (channels) { - case 1: - case 2: - cfg_val.cfg_regx.num_ch = CH_STEREO; - cfg_val.cfg_regx.layout = LAYOUT0; - break; - - case 3: - case 4: - cfg_val.cfg_regx.num_ch = CH_THREE_FOUR; - cfg_val.cfg_regx.layout = LAYOUT1; - break; - - case 5: - case 6: - cfg_val.cfg_regx.num_ch = CH_FIVE_SIX; - cfg_val.cfg_regx.layout = LAYOUT1; - break; - - case 7: - case 8: - cfg_val.cfg_regx.num_ch = CH_SEVEN_EIGHT; - cfg_val.cfg_regx.layout = LAYOUT1; - break; - - } - - cfg_val.cfg_regx.val_bit = 1; - had_write_register(AUD_CONFIG, cfg_val.cfg_regval); - return 0; -} - /* * Compute derived values in channel_allocations[]. */ @@ -659,56 +596,6 @@ static int had_register_chmap_ctls(struct snd_intelhad *intelhaddata, return 0; } -/** - * snd_intelhad_prog_dip_v1 - to initialize Data Island Packets registers - * - * @substream:substream for which the prepare function is called - * @intelhaddata:substream private data - * - * This function is called in the prepare callback - */ -static void snd_intelhad_prog_dip_v1(struct snd_pcm_substream *substream, - struct snd_intelhad *intelhaddata) -{ - int i; - union aud_ctrl_st ctrl_state = {.ctrl_val = 0}; - union aud_info_frame2 frame2 = {.fr2_val = 0}; - union aud_info_frame3 frame3 = {.fr3_val = 0}; - u8 checksum = 0; - int channels; - - channels = substream->runtime->channels; - - had_write_register(AUD_CNTL_ST, ctrl_state.ctrl_val); - - frame2.fr2_regx.chnl_cnt = substream->runtime->channels - 1; - - frame3.fr3_regx.chnl_alloc = snd_intelhad_channel_allocation( - intelhaddata, channels); - - /*Calculte the byte wide checksum for all valid DIP words*/ - for (i = 0; i < BYTES_PER_WORD; i++) - checksum += (HDMI_INFO_FRAME_WORD1 >> i*BITS_PER_BYTE) & MASK_BYTE0; - for (i = 0; i < BYTES_PER_WORD; i++) - checksum += (frame2.fr2_val >> i*BITS_PER_BYTE) & MASK_BYTE0; - for (i = 0; i < BYTES_PER_WORD; i++) - checksum += (frame3.fr3_val >> i*BITS_PER_BYTE) & MASK_BYTE0; - - frame2.fr2_regx.chksum = -(checksum); - - had_write_register(AUD_HDMIW_INFOFR, HDMI_INFO_FRAME_WORD1); - had_write_register(AUD_HDMIW_INFOFR, frame2.fr2_val); - had_write_register(AUD_HDMIW_INFOFR, frame3.fr3_val); - - /* program remaining DIP words with zero */ - for (i = 0; i < HAD_MAX_DIP_WORDS-VALID_DIP_WORDS; i++) - had_write_register(AUD_HDMIW_INFOFR, 0x0); - - ctrl_state.ctrl_regx.dip_freq = 1; - ctrl_state.ctrl_regx.dip_en_sta = 1; - had_write_register(AUD_CNTL_ST, ctrl_state.ctrl_val); -} - /** * snd_intelhad_prog_dip_v2 - to initialize Data Island Packets registers * @@ -928,32 +815,6 @@ static int had_calculate_maud_value(u32 aud_samp_freq, u32 link_rate) return maud_val; } -/** - * snd_intelhad_prog_cts_v1 - Program HDMI audio CTS value - * - * @aud_samp_freq: sampling frequency of audio data - * @tmds: sampling frequency of the display data - * @n_param: N value, depends on aud_samp_freq - * @intelhaddata:substream private data - * - * Program CTS register based on the audio and display sampling frequency - */ -static void snd_intelhad_prog_cts_v1(u32 aud_samp_freq, u32 tmds, - u32 link_rate, u32 n_param, - struct snd_intelhad *intelhaddata) -{ - u32 cts_val; - u64 dividend, divisor; - - /* Calculate CTS according to HDMI 1.3a spec*/ - dividend = (u64)tmds * n_param*1000; - divisor = 128 * aud_samp_freq; - cts_val = div64_u64(dividend, divisor); - pr_debug("TMDS value=%d, N value=%d, CTS Value=%d\n", - tmds, n_param, cts_val); - had_write_register(AUD_HDMI_CTS, (BIT(20) | cts_val)); -} - /** * snd_intelhad_prog_cts_v2 - Program HDMI audio CTS value * @@ -1026,31 +887,6 @@ static int had_calculate_n_value(u32 aud_samp_freq) return n_val; } -/** - * snd_intelhad_prog_n_v1 - Program HDMI audio N value - * - * @aud_samp_freq: sampling frequency of audio data - * @n_param: N value, depends on aud_samp_freq - * @intelhaddata:substream private data - * - * This function is called in the prepare callback. - * It programs based on the audio and display sampling frequency - */ -static int snd_intelhad_prog_n_v1(u32 aud_samp_freq, u32 *n_param, - struct snd_intelhad *intelhaddata) -{ - s32 n_val; - - n_val = had_calculate_n_value(aud_samp_freq); - - if (n_val < 0) - return n_val; - - had_write_register(AUD_N_ENABLE, (BIT(20) | n_val)); - *n_param = n_val; - return 0; -} - /** * snd_intelhad_prog_n_v2 - Program HDMI audio N value * @@ -1087,35 +923,6 @@ static int snd_intelhad_prog_n_v2(u32 aud_samp_freq, u32 *n_param, return 0; } -static void had_clear_underrun_intr_v1(struct snd_intelhad *intelhaddata) -{ - u32 hdmi_status, i = 0; - - /* Handle Underrun interrupt within Audio Unit */ - had_write_register(AUD_CONFIG, 0); - /* Reset buffer pointers */ - had_write_register(AUD_HDMI_STATUS, 1); - had_write_register(AUD_HDMI_STATUS, 0); - /** - * The interrupt status 'sticky' bits might not be cleared by - * setting '1' to that bit once... - */ - do { /* clear bit30, 31 AUD_HDMI_STATUS */ - had_read_register(AUD_HDMI_STATUS, &hdmi_status); - pr_debug("HDMI status =0x%x\n", hdmi_status); - if (hdmi_status & AUD_CONFIG_MASK_UNDERRUN) { - i++; - hdmi_status &= (AUD_CONFIG_MASK_SRDBG | - AUD_CONFIG_MASK_FUNCRST); - hdmi_status |= ~AUD_CONFIG_MASK_UNDERRUN; - had_write_register(AUD_HDMI_STATUS, hdmi_status); - } else - break; - } while (i < MAX_CNT); - if (i >= MAX_CNT) - pr_err("Unable to clear UNDERRUN bits\n"); -} - static void had_clear_underrun_intr_v2(struct snd_intelhad *intelhaddata) { u32 hdmi_status, i = 0; @@ -1775,16 +1582,6 @@ static struct snd_intel_had_interface had_interface = { .resume = hdmi_audio_resume, }; -static struct had_ops had_ops_v1 = { - .enable_audio = snd_intelhad_enable_audio_v1, - .reset_audio = snd_intelhad_reset_audio_v1, - .prog_n = snd_intelhad_prog_n_v1, - .prog_cts = snd_intelhad_prog_cts_v1, - .audio_ctrl = snd_intelhad_prog_audio_ctrl_v1, - .prog_dip = snd_intelhad_prog_dip_v1, - .handle_underrun = had_clear_underrun_intr_v1, -}; - static struct had_ops had_ops_v2 = { .enable_audio = snd_intelhad_enable_audio_v2, .reset_audio = snd_intelhad_reset_audio_v2, @@ -1934,7 +1731,6 @@ int hdmi_audio_probe(void *deviceptr) } intelhaddata->hw_silence = 1; - had_ops_v1 = had_ops_v1; /* unused */ intelhaddata->ops = &had_ops_v2; return retval; diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index 3aed89af5b45..5d94aaf0b980 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -358,19 +358,6 @@ struct channel_map_table { * */ union aud_cfg { - struct { - u32 aud_en:1; - u32 layout:1; - u32 fmt:2; - u32 num_ch:2; - u32 rsvd0:1; - u32 set:1; - u32 flat:1; - u32 val_bit:1; - u32 user_bit:1; - u32 underrun:1; - u32 rsvd1:20; - } cfg_regx; struct { u32 aud_en:1; u32 layout:1; @@ -438,11 +425,6 @@ union aud_ch_status_1 { * */ union aud_hdmi_cts { - struct { - u32 cts_val:20; - u32 en_cts_prog:1; - u32 rsvd:11; - } cts_regx; struct { u32 cts_val:24; u32 en_cts_prog:1; @@ -459,11 +441,6 @@ union aud_hdmi_cts { * */ union aud_hdmi_n_enable { - struct { - u32 n_val:20; - u32 en_n_prog:1; - u32 rsvd:11; - } n_regx; struct { u32 n_val:24; u32 en_n_prog:1; @@ -480,12 +457,6 @@ union aud_hdmi_n_enable { * */ union aud_buf_config { - struct { - u32 fifo_width:8; - u32 rsvd0:8; - u32 aud_delay:8; - u32 rsvd1:8; - } buf_cfg_regx; struct { u32 audio_fifo_watermark:8; u32 dma_fifo_watermark:3; -- cgit v1.2.3 From 76296ef0ecec9bb887be22105744e429c6a5422a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Jan 2017 16:09:11 +0100 Subject: ALSA: x86: Drop indirect calls of had_ops We have only a single implementation of had_ops, hence there is no merit to use the indirect calls at all. Let's replace it with the direct calls -- which allows the compiler more optimizations. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 85 ++++++++++++++++++----------------------- sound/x86/intel_hdmi_audio.h | 21 ++-------- sound/x86/intel_hdmi_audio_if.c | 4 +- 3 files changed, 42 insertions(+), 68 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 1e0bc72a8f63..84ce4e09ada5 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -280,13 +280,12 @@ static int had_read_modify_aud_config_v2(struct snd_pcm_substream *substream, return had_read_modify(AUD_CONFIG, data, mask); } -static void snd_intelhad_enable_audio_v2(struct snd_pcm_substream *substream, - u8 enable) +void snd_intelhad_enable_audio(struct snd_pcm_substream *substream, u8 enable) { had_read_modify_aud_config_v2(substream, enable, BIT(0)); } -static void snd_intelhad_reset_audio_v2(u8 reset) +static void snd_intelhad_reset_audio(u8 reset) { had_write_register(AUD_HDMI_STATUS_v2, reset); } @@ -359,13 +358,13 @@ static int had_prog_status_reg(struct snd_pcm_substream *substream, return 0; } -/** +/* * function to initialize audio * registers and buffer confgiuration registers * This function is called in the prepare callback */ -static int snd_intelhad_prog_audio_ctrl_v2(struct snd_pcm_substream *substream, - struct snd_intelhad *intelhaddata) +static int snd_intelhad_audio_ctrl(struct snd_pcm_substream *substream, + struct snd_intelhad *intelhaddata) { union aud_cfg cfg_val = {.cfg_regval = 0}; union aud_buf_config buf_cfg = {.buf_cfgval = 0}; @@ -596,16 +595,16 @@ static int had_register_chmap_ctls(struct snd_intelhad *intelhaddata, return 0; } -/** - * snd_intelhad_prog_dip_v2 - to initialize Data Island Packets registers +/* + * snd_intelhad_prog_dip - to initialize Data Island Packets registers * * @substream:substream for which the prepare function is called * @intelhaddata:substream private data * * This function is called in the prepare callback */ -static void snd_intelhad_prog_dip_v2(struct snd_pcm_substream *substream, - struct snd_intelhad *intelhaddata) +static void snd_intelhad_prog_dip(struct snd_pcm_substream *substream, + struct snd_intelhad *intelhaddata) { int i; union aud_ctrl_st ctrl_state = {.ctrl_val = 0}; @@ -815,8 +814,8 @@ static int had_calculate_maud_value(u32 aud_samp_freq, u32 link_rate) return maud_val; } -/** - * snd_intelhad_prog_cts_v2 - Program HDMI audio CTS value +/* + * snd_intelhad_prog_cts - Program HDMI audio CTS value * * @aud_samp_freq: sampling frequency of audio data * @tmds: sampling frequency of the display data @@ -825,9 +824,9 @@ static int had_calculate_maud_value(u32 aud_samp_freq, u32 link_rate) * * Program CTS register based on the audio and display sampling frequency */ -static void snd_intelhad_prog_cts_v2(u32 aud_samp_freq, u32 tmds, - u32 link_rate, u32 n_param, - struct snd_intelhad *intelhaddata) +static void snd_intelhad_prog_cts(u32 aud_samp_freq, u32 tmds, + u32 link_rate, u32 n_param, + struct snd_intelhad *intelhaddata) { u32 cts_val; u64 dividend, divisor; @@ -887,8 +886,8 @@ static int had_calculate_n_value(u32 aud_samp_freq) return n_val; } -/** - * snd_intelhad_prog_n_v2 - Program HDMI audio N value +/* + * snd_intelhad_prog_n - Program HDMI audio N value * * @aud_samp_freq: sampling frequency of audio data * @n_param: N value, depends on aud_samp_freq @@ -897,8 +896,8 @@ static int had_calculate_n_value(u32 aud_samp_freq) * This function is called in the prepare callback. * It programs based on the audio and display sampling frequency */ -static int snd_intelhad_prog_n_v2(u32 aud_samp_freq, u32 *n_param, - struct snd_intelhad *intelhaddata) +static int snd_intelhad_prog_n(u32 aud_samp_freq, u32 *n_param, + struct snd_intelhad *intelhaddata) { s32 n_val; @@ -923,7 +922,7 @@ static int snd_intelhad_prog_n_v2(u32 aud_samp_freq, u32 *n_param, return 0; } -static void had_clear_underrun_intr_v2(struct snd_intelhad *intelhaddata) +void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata) { u32 hdmi_status, i = 0; @@ -1209,7 +1208,7 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, caps = HDMI_AUDIO_BUFFER_DONE; retval = had_set_caps(HAD_SET_ENABLE_AUDIO_INT, &caps); retval = had_set_caps(HAD_SET_ENABLE_AUDIO, NULL); - intelhaddata->ops->enable_audio(substream, 1); + snd_intelhad_enable_audio(substream, 1); pr_debug("Processed _Start\n"); @@ -1232,10 +1231,10 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, */ caps = HDMI_AUDIO_BUFFER_DONE; had_set_caps(HAD_SET_DISABLE_AUDIO_INT, &caps); - intelhaddata->ops->enable_audio(substream, 0); + snd_intelhad_enable_audio(substream, 0); /* Reset buffer pointers */ - intelhaddata->ops->reset_audio(1); - intelhaddata->ops->reset_audio(0); + snd_intelhad_reset_audio(1); + snd_intelhad_reset_audio(0); stream->stream_status = STREAM_DROPPED; had_set_caps(HAD_SET_DISABLE_AUDIO, NULL); break; @@ -1304,8 +1303,8 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) had_get_caps(HAD_GET_ELD, &intelhaddata->eeld); had_get_caps(HAD_GET_DP_OUTPUT, &intelhaddata->dp_output); - retval = intelhaddata->ops->prog_n(substream->runtime->rate, &n_param, - intelhaddata); + retval = snd_intelhad_prog_n(substream->runtime->rate, &n_param, + intelhaddata); if (retval) { pr_err("programming N value failed %#x\n", retval); goto prep_end; @@ -1315,13 +1314,13 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) had_get_caps(HAD_GET_LINK_RATE, &link_rate); - intelhaddata->ops->prog_cts(substream->runtime->rate, - disp_samp_freq, link_rate, - n_param, intelhaddata); + snd_intelhad_prog_cts(substream->runtime->rate, + disp_samp_freq, link_rate, + n_param, intelhaddata); - intelhaddata->ops->prog_dip(substream, intelhaddata); + snd_intelhad_prog_dip(substream, intelhaddata); - retval = intelhaddata->ops->audio_ctrl(substream, intelhaddata); + retval = snd_intelhad_audio_ctrl(substream, intelhaddata); /* Prog buffer address */ retval = snd_intelhad_prog_buffer(intelhaddata, @@ -1431,7 +1430,7 @@ int hdmi_audio_mode_change(struct snd_pcm_substream *substream) intelhaddata = snd_pcm_substream_chip(substream); /* Disable Audio */ - intelhaddata->ops->enable_audio(substream, 0); + snd_intelhad_enable_audio(substream, 0); /* Update CTS value */ retval = had_get_caps(HAD_GET_DISPLAY_RATE, &disp_samp_freq); @@ -1440,8 +1439,8 @@ int hdmi_audio_mode_change(struct snd_pcm_substream *substream) goto out; } - retval = intelhaddata->ops->prog_n(substream->runtime->rate, &n_param, - intelhaddata); + retval = snd_intelhad_prog_n(substream->runtime->rate, &n_param, + intelhaddata); if (retval) { pr_err("programming N value failed %#x\n", retval); goto out; @@ -1450,12 +1449,12 @@ int hdmi_audio_mode_change(struct snd_pcm_substream *substream) if (intelhaddata->dp_output) had_get_caps(HAD_GET_LINK_RATE, &link_rate); - intelhaddata->ops->prog_cts(substream->runtime->rate, - disp_samp_freq, link_rate, - n_param, intelhaddata); + snd_intelhad_prog_cts(substream->runtime->rate, + disp_samp_freq, link_rate, + n_param, intelhaddata); /* Enable Audio */ - intelhaddata->ops->enable_audio(substream, 1); + snd_intelhad_enable_audio(substream, 1); out: return retval; @@ -1582,15 +1581,6 @@ static struct snd_intel_had_interface had_interface = { .resume = hdmi_audio_resume, }; -static struct had_ops had_ops_v2 = { - .enable_audio = snd_intelhad_enable_audio_v2, - .reset_audio = snd_intelhad_reset_audio_v2, - .prog_n = snd_intelhad_prog_n_v2, - .prog_cts = snd_intelhad_prog_cts_v2, - .audio_ctrl = snd_intelhad_prog_audio_ctrl_v2, - .prog_dip = snd_intelhad_prog_dip_v2, - .handle_underrun = had_clear_underrun_intr_v2, -}; /** * hdmi_audio_probe - to create sound card instance for HDMI audio playabck * @@ -1731,7 +1721,6 @@ int hdmi_audio_probe(void *deviceptr) } intelhaddata->hw_silence = 1; - intelhaddata->ops = &had_ops_v2; return retval; err: diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 034b3873ffa1..394959f0bd2e 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -123,7 +123,6 @@ struct had_callback_ops { * @chmap: holds channel map info * @audio_reg_base: hdmi audio register base offset * @hw_silence: flag indicates SoC support for HW silence/Keep alive - * @ops: holds ops functions based on platform */ struct snd_intelhad { struct snd_card *card; @@ -149,25 +148,8 @@ struct snd_intelhad { unsigned int *audio_reg_base; unsigned int audio_cfg_offset; bool hw_silence; - struct had_ops *ops; }; -struct had_ops { - void (*enable_audio)(struct snd_pcm_substream *substream, - u8 enable); - void (*reset_audio)(u8 reset); - int (*prog_n)(u32 aud_samp_freq, u32 *n_param, - struct snd_intelhad *intelhaddata); - void (*prog_cts)(u32 aud_samp_freq, u32 tmds, u32 link_rate, - u32 n_param, struct snd_intelhad *intelhaddata); - int (*audio_ctrl)(struct snd_pcm_substream *substream, - struct snd_intelhad *intelhaddata); - void (*prog_dip)(struct snd_pcm_substream *substream, - struct snd_intelhad *intelhaddata); - void (*handle_underrun)(struct snd_intelhad *intelhaddata); -}; - - int had_event_handler(enum had_event_type event_type, void *data); int hdmi_audio_query(void *drv_data, struct hdmi_audio_event event); @@ -185,6 +167,9 @@ int snd_intelhad_invd_buffer(int start, int end); int snd_intelhad_read_len(struct snd_intelhad *intelhaddata); void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata); +void snd_intelhad_enable_audio(struct snd_pcm_substream *substream, u8 enable); +void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata); + /* Register access functions */ int had_get_hwstate(struct snd_intelhad *intelhaddata); int had_get_caps(enum had_caps_list query_element, void *capabilties); diff --git a/sound/x86/intel_hdmi_audio_if.c b/sound/x86/intel_hdmi_audio_if.c index 30b4b25acb24..d92fe48d916b 100644 --- a/sound/x86/intel_hdmi_audio_if.c +++ b/sound/x86/intel_hdmi_audio_if.c @@ -349,7 +349,7 @@ int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) pr_debug("Enter:%s buf_id=%d, stream_type=%d\n", __func__, buf_id, stream_type); - intelhaddata->ops->handle_underrun(intelhaddata); + snd_intelhad_handle_underrun(intelhaddata); if (drv_status == HAD_DRV_DISCONNECTED) { pr_err("%s:Device already disconnected\n", __func__); @@ -451,7 +451,7 @@ int had_process_hot_unplug(struct snd_intelhad *intelhaddata) caps = HDMI_AUDIO_BUFFER_DONE; retval = had_set_caps(HAD_SET_DISABLE_AUDIO_INT, &caps); retval = had_set_caps(HAD_SET_DISABLE_AUDIO, NULL); - intelhaddata->ops->enable_audio( + snd_intelhad_enable_audio( intelhaddata->stream_info.had_substream, 0); } -- cgit v1.2.3 From f23df8071b178dcfa4f6014baf9323ddaa33e1fd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Jan 2017 16:29:39 +0100 Subject: ALSA: x86: Replace indirect register ops with direct calls Now about the indirect register ops: they are replaced with direct calls, too. The read / write / modify ops are simply replaced with the corresponding functions. The difference is that we calculate the offset inside the function now. So all the had_config_offset references in the caller side are dropped. This also simplifies the DP-audio check in hdmi_audio_write() and hdmi_audio_rmw(). The hdmi_audio_get_register_base is dropped since it's no longer used when the base address and config offset are referred in the read/write functions. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 11 ++--- sound/x86/intel_hdmi_audio.h | 2 - sound/x86/intel_hdmi_audio_if.c | 21 ---------- sound/x86/intel_hdmi_lpe_audio.c | 91 ++++++++++------------------------------ sound/x86/intel_hdmi_lpe_audio.h | 14 ++----- 5 files changed, 30 insertions(+), 109 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 84ce4e09ada5..d101a27e4a27 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -205,8 +205,7 @@ int had_read_register(u32 offset, u32 *data) retval = had_get_hwstate(intelhaddata); if (!retval) - retval = intelhaddata->reg_ops.hdmi_audio_read_register( - offset + intelhaddata->audio_cfg_offset, data); + retval = mid_hdmi_audio_read(offset, data); return retval; } @@ -218,8 +217,7 @@ int had_write_register(u32 offset, u32 data) retval = had_get_hwstate(intelhaddata); if (!retval) - retval = intelhaddata->reg_ops.hdmi_audio_write_register( - offset + intelhaddata->audio_cfg_offset, data); + retval = mid_hdmi_audio_write(offset, data); return retval; } @@ -231,9 +229,7 @@ int had_read_modify(u32 offset, u32 data, u32 mask) retval = had_get_hwstate(intelhaddata); if (!retval) - retval = intelhaddata->reg_ops.hdmi_audio_read_modify( - offset + intelhaddata->audio_cfg_offset, - data, mask); + retval = mid_hdmi_audio_rmw(offset, data, mask); return retval; } @@ -1622,7 +1618,6 @@ int hdmi_audio_probe(void *deviceptr) retval = mid_hdmi_audio_setup( ops_cb.intel_had_event_call_back, - &(intelhaddata->reg_ops), &(intelhaddata->query_ops)); if (retval) { pr_err("querying display driver APIs failed %#x\n", retval); diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 394959f0bd2e..5ba06042f669 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -107,7 +107,6 @@ struct had_callback_ops { * @card: ptr to hold card details * @card_index: sound card index * @card_id: detected sound card id - * @reg_ops: register operations to program registers * @query_ops: caps call backs for get/set operations * @drv_status: driver status * @buf_info: ring buffer info @@ -128,7 +127,6 @@ struct snd_intelhad { struct snd_card *card; int card_index; char *card_id; - struct hdmi_audio_registers_ops reg_ops; struct hdmi_audio_query_set_ops query_ops; enum had_drv_status drv_status; struct ring_buf_info buf_info[HAD_NUM_OF_RING_BUFS]; diff --git a/sound/x86/intel_hdmi_audio_if.c b/sound/x86/intel_hdmi_audio_if.c index d92fe48d916b..4334be100655 100644 --- a/sound/x86/intel_hdmi_audio_if.c +++ b/sound/x86/intel_hdmi_audio_if.c @@ -392,22 +392,6 @@ int had_process_hot_plug(struct snd_intelhad *intelhaddata) pr_debug("Processing HOT_PLUG, buf_id = %d\n", buf_id); - /* Query display driver for audio register base */ - if (intelhaddata->reg_ops.hdmi_audio_get_register_base( - &intelhaddata->audio_reg_base, - &intelhaddata->audio_cfg_offset)) { - pr_err("Unable to get audio reg base from Display driver\n"); - goto err; - } - - if (intelhaddata->audio_reg_base == NULL) { - pr_err("audio reg base value is NULL\n"); - goto err; - } - - pr_debug("%s audio_reg_base = 0x%p\n", __func__, - intelhaddata->audio_reg_base); - /* Safety check */ if (substream) { pr_debug("There should not be active PB from ALSA\n"); @@ -420,11 +404,6 @@ int had_process_hot_plug(struct snd_intelhad *intelhaddata) had_build_channel_allocation_map(intelhaddata); return 0; - -err: - pm_runtime_disable(intelhaddata->dev); - intelhaddata->dev = NULL; - return 0; } int had_process_hot_unplug(struct snd_intelhad *intelhaddata) diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c index 3cb0f642575c..a7a07bfe52ed 100644 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ b/sound/x86/intel_hdmi_lpe_audio.c @@ -178,10 +178,10 @@ void mid_hdmi_audio_signal_event(enum had_event_type event) ctx->had_pvt_data); } -/** +/* * used to write into display controller HDMI audio registers. */ -static int hdmi_audio_write(u32 reg, u32 val) +int mid_hdmi_audio_write(u32 reg, u32 val) { struct hdmi_lpe_audio_ctx *ctx; @@ -190,58 +190,49 @@ static int hdmi_audio_write(u32 reg, u32 val) dev_dbg(&hlpe_pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, reg, val); if (ctx->dp_output) { - if ((reg == AUDIO_HDMI_CONFIG_A) || - (reg == AUDIO_HDMI_CONFIG_B) || - (reg == AUDIO_HDMI_CONFIG_C)) { - if (val & AUD_CONFIG_VALID_BIT) - val = val | AUD_CONFIG_DP_MODE | - AUD_CONFIG_BLOCK_BIT; - } + if (reg == AUD_CONFIG && (val & AUD_CONFIG_VALID_BIT)) + val |= AUD_CONFIG_DP_MODE | AUD_CONFIG_BLOCK_BIT; } - iowrite32(val, (ctx->mmio_start+reg)); + iowrite32(val, ctx->mmio_start + ctx->had_config_offset + reg); return 0; } -/** +/* * used to get the register value read from * display controller HDMI audio registers. */ -static int hdmi_audio_read(u32 reg, u32 *val) +int mid_hdmi_audio_read(u32 reg, u32 *val) { struct hdmi_lpe_audio_ctx *ctx; ctx = platform_get_drvdata(hlpe_pdev); - *val = ioread32(ctx->mmio_start+reg); + *val = ioread32(ctx->mmio_start + ctx->had_config_offset + reg); dev_dbg(&hlpe_pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, reg, *val); return 0; } -/** +/* * used to update the masked bits in display controller HDMI * audio registers. */ -static int hdmi_audio_rmw(u32 reg, u32 val, u32 mask) +int mid_hdmi_audio_rmw(u32 reg, u32 val, u32 mask) { struct hdmi_lpe_audio_ctx *ctx; u32 val_tmp = 0; ctx = platform_get_drvdata(hlpe_pdev); - val_tmp = (val & mask) | - ((ioread32(ctx->mmio_start + reg)) & ~mask); + val_tmp = ioread32(ctx->mmio_start + ctx->had_config_offset + reg); + val_tmp &= ~mask; + val_tmp |= (val & mask); if (ctx->dp_output) { - if ((reg == AUDIO_HDMI_CONFIG_A) || - (reg == AUDIO_HDMI_CONFIG_B) || - (reg == AUDIO_HDMI_CONFIG_C)) { - if (val_tmp & AUD_CONFIG_VALID_BIT) - val_tmp = val_tmp | AUD_CONFIG_DP_MODE | - AUD_CONFIG_BLOCK_BIT; - } + if (reg == AUD_CONFIG && (val_tmp & AUD_CONFIG_VALID_BIT)) + val_tmp |= AUD_CONFIG_DP_MODE | AUD_CONFIG_BLOCK_BIT; } - iowrite32(val_tmp, (ctx->mmio_start+reg)); + iowrite32(val_tmp, ctx->mmio_start + ctx->had_config_offset + reg); dev_dbg(&hlpe_pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, reg, val_tmp); @@ -290,22 +281,6 @@ static int hdmi_audio_get_caps(enum had_caps_list get_element, return ret; } -/** - * used to get the current hdmi base address - */ -int hdmi_audio_get_register_base(u32 **reg_base, - u32 *config_offset) -{ - struct hdmi_lpe_audio_ctx *ctx; - - ctx = platform_get_drvdata(hlpe_pdev); - *reg_base = (u32 *)(ctx->mmio_start); - *config_offset = ctx->had_config_offset; - dev_dbg(&hlpe_pdev->dev, "%s: reg_base = 0x%p, cfg_off = 0x%x\n", - __func__, *reg_base, *config_offset); - return 0; -} - /** * used to set the HDMI audio capabilities. * e.g. Audio INT. @@ -324,15 +299,11 @@ int hdmi_audio_set_caps(enum had_caps_list set_element, { u32 status_reg; - hdmi_audio_read(AUD_HDMI_STATUS_v2 + - ctx->had_config_offset, &status_reg); + mid_hdmi_audio_read(AUD_HDMI_STATUS_v2, &status_reg); status_reg |= HDMI_AUDIO_BUFFER_DONE | HDMI_AUDIO_UNDERRUN; - hdmi_audio_write(AUD_HDMI_STATUS_v2 + - ctx->had_config_offset, status_reg); - hdmi_audio_read(AUD_HDMI_STATUS_v2 + - ctx->had_config_offset, &status_reg); - + mid_hdmi_audio_write(AUD_HDMI_STATUS_v2, status_reg); + mid_hdmi_audio_read(AUD_HDMI_STATUS_v2, &status_reg); } break; default: @@ -342,13 +313,6 @@ int hdmi_audio_set_caps(enum had_caps_list set_element, return 0; } -static struct hdmi_audio_registers_ops hdmi_audio_reg_ops = { - .hdmi_audio_get_register_base = hdmi_audio_get_register_base, - .hdmi_audio_read_register = hdmi_audio_read, - .hdmi_audio_write_register = hdmi_audio_write, - .hdmi_audio_read_modify = hdmi_audio_rmw, -}; - static struct hdmi_audio_query_set_ops hdmi_audio_get_set_ops = { .hdmi_audio_get_caps = hdmi_audio_get_caps, .hdmi_audio_set_caps = hdmi_audio_set_caps, @@ -356,7 +320,6 @@ static struct hdmi_audio_query_set_ops hdmi_audio_get_set_ops = { int mid_hdmi_audio_setup( had_event_call_back audio_callbacks, - struct hdmi_audio_registers_ops *reg_ops, struct hdmi_audio_query_set_ops *query_ops) { struct hdmi_lpe_audio_ctx *ctx; @@ -365,14 +328,6 @@ int mid_hdmi_audio_setup( dev_dbg(&hlpe_pdev->dev, "%s: called\n", __func__); - reg_ops->hdmi_audio_get_register_base = - (hdmi_audio_reg_ops.hdmi_audio_get_register_base); - reg_ops->hdmi_audio_read_register = - (hdmi_audio_reg_ops.hdmi_audio_read_register); - reg_ops->hdmi_audio_write_register = - (hdmi_audio_reg_ops.hdmi_audio_write_register); - reg_ops->hdmi_audio_read_modify = - (hdmi_audio_reg_ops.hdmi_audio_read_modify); query_ops->hdmi_audio_get_caps = hdmi_audio_get_set_ops.hdmi_audio_get_caps; query_ops->hdmi_audio_set_caps = @@ -421,17 +376,17 @@ static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id) ctx = platform_get_drvdata(hlpe_pdev); - audio_reg = ctx->had_config_offset + AUD_HDMI_STATUS_v2; - hdmi_audio_read(audio_reg, &audio_stat); + audio_reg = AUD_HDMI_STATUS_v2; + mid_hdmi_audio_read(audio_reg, &audio_stat); if (audio_stat & HDMI_AUDIO_UNDERRUN) { - hdmi_audio_write(audio_reg, HDMI_AUDIO_UNDERRUN); + mid_hdmi_audio_write(audio_reg, HDMI_AUDIO_UNDERRUN); mid_hdmi_audio_signal_event( HAD_EVENT_AUDIO_BUFFER_UNDERRUN); } if (audio_stat & HDMI_AUDIO_BUFFER_DONE) { - hdmi_audio_write(audio_reg, HDMI_AUDIO_BUFFER_DONE); + mid_hdmi_audio_write(audio_reg, HDMI_AUDIO_BUFFER_DONE); mid_hdmi_audio_signal_event( HAD_EVENT_AUDIO_BUFFER_DONE); } diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index 5d94aaf0b980..ea90cf919948 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -641,15 +641,6 @@ enum had_event_type { typedef int (*had_event_call_back) (enum had_event_type event_type, void *ctxt_info); -struct hdmi_audio_registers_ops { - int (*hdmi_audio_get_register_base)(u32 **reg_base, - u32 *config_offset); - int (*hdmi_audio_read_register)(u32 reg_addr, u32 *data); - int (*hdmi_audio_write_register)(u32 reg_addr, u32 data); - int (*hdmi_audio_read_modify)(u32 reg_addr, u32 data, - u32 mask); -}; - struct hdmi_audio_query_set_ops { int (*hdmi_audio_get_caps)(enum had_caps_list query_element, void *capabilties); @@ -674,10 +665,13 @@ void mid_hdmi_audio_resume(void *dev); void mid_hdmi_audio_signal_event(enum had_event_type event); int mid_hdmi_audio_setup( had_event_call_back audio_callbacks, - struct hdmi_audio_registers_ops *reg_ops, struct hdmi_audio_query_set_ops *query_ops); int mid_hdmi_audio_register( struct snd_intel_had_interface *driver, void *had_data); +int mid_hdmi_audio_read(u32 reg, u32 *val); +int mid_hdmi_audio_write(u32 reg, u32 val); +int mid_hdmi_audio_rmw(u32 reg, u32 val, u32 mask); + #endif -- cgit v1.2.3 From 9eca88c881f1c74c7f5dda3c67cb0b4178429e93 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Jan 2017 16:37:06 +0100 Subject: ALSA: x86: Replace indirect query_ops with direct calls Like the previous patch, this replaces the indirect query_ops calls via direct function calls. They are only get_caps and set_caps, so fairly straightforward at this time. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 10 +++------- sound/x86/intel_hdmi_audio.h | 2 -- sound/x86/intel_hdmi_lpe_audio.c | 26 +++++++------------------- sound/x86/intel_hdmi_lpe_audio.h | 16 ++++++---------- 4 files changed, 16 insertions(+), 38 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index d101a27e4a27..a4c2f3f8d669 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -179,8 +179,7 @@ int had_get_caps(enum had_caps_list query, void *caps) retval = had_get_hwstate(intelhaddata); if (!retval) - retval = intelhaddata->query_ops.hdmi_audio_get_caps(query, - caps); + retval = mid_hdmi_audio_get_caps(query, caps); return retval; } @@ -192,8 +191,7 @@ int had_set_caps(enum had_caps_list set_element, void *caps) retval = had_get_hwstate(intelhaddata); if (!retval) - retval = intelhaddata->query_ops.hdmi_audio_set_caps( - set_element, caps); + retval = mid_hdmi_audio_set_caps(set_element, caps); return retval; } @@ -1616,9 +1614,7 @@ int hdmi_audio_probe(void *deviceptr) /* registering with display driver to get access to display APIs */ - retval = mid_hdmi_audio_setup( - ops_cb.intel_had_event_call_back, - &(intelhaddata->query_ops)); + retval = mid_hdmi_audio_setup(ops_cb.intel_had_event_call_back); if (retval) { pr_err("querying display driver APIs failed %#x\n", retval); goto free_hadstream; diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 5ba06042f669..e7c7432c5078 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -107,7 +107,6 @@ struct had_callback_ops { * @card: ptr to hold card details * @card_index: sound card index * @card_id: detected sound card id - * @query_ops: caps call backs for get/set operations * @drv_status: driver status * @buf_info: ring buffer info * @stream_info: stream information @@ -127,7 +126,6 @@ struct snd_intelhad { struct snd_card *card; int card_index; char *card_id; - struct hdmi_audio_query_set_ops query_ops; enum had_drv_status drv_status; struct ring_buf_info buf_info[HAD_NUM_OF_RING_BUFS]; struct pcm_stream_info stream_info; diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c index a7a07bfe52ed..1747ff259903 100644 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ b/sound/x86/intel_hdmi_lpe_audio.c @@ -239,12 +239,12 @@ int mid_hdmi_audio_rmw(u32 reg, u32 val, u32 mask) return 0; } -/** +/* * used to return the HDMI audio capabilities. * e.g. resolution, frame rate. */ -static int hdmi_audio_get_caps(enum had_caps_list get_element, - void *capabilities) +int mid_hdmi_audio_get_caps(enum had_caps_list get_element, + void *capabilities) { struct hdmi_lpe_audio_ctx *ctx; int ret = 0; @@ -281,12 +281,12 @@ static int hdmi_audio_get_caps(enum had_caps_list get_element, return ret; } -/** +/* * used to set the HDMI audio capabilities. * e.g. Audio INT. */ -int hdmi_audio_set_caps(enum had_caps_list set_element, - void *capabilties) +int mid_hdmi_audio_set_caps(enum had_caps_list set_element, + void *capabilties) { struct hdmi_lpe_audio_ctx *ctx; @@ -313,14 +313,7 @@ int hdmi_audio_set_caps(enum had_caps_list set_element, return 0; } -static struct hdmi_audio_query_set_ops hdmi_audio_get_set_ops = { - .hdmi_audio_get_caps = hdmi_audio_get_caps, - .hdmi_audio_set_caps = hdmi_audio_set_caps, -}; - -int mid_hdmi_audio_setup( - had_event_call_back audio_callbacks, - struct hdmi_audio_query_set_ops *query_ops) +int mid_hdmi_audio_setup(had_event_call_back audio_callbacks) { struct hdmi_lpe_audio_ctx *ctx; @@ -328,11 +321,6 @@ int mid_hdmi_audio_setup( dev_dbg(&hlpe_pdev->dev, "%s: called\n", __func__); - query_ops->hdmi_audio_get_caps = - hdmi_audio_get_set_ops.hdmi_audio_get_caps; - query_ops->hdmi_audio_set_caps = - hdmi_audio_get_set_ops.hdmi_audio_set_caps; - ctx->had_event_callbacks = audio_callbacks; return 0; diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index ea90cf919948..5e925b728302 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -641,13 +641,6 @@ enum had_event_type { typedef int (*had_event_call_back) (enum had_event_type event_type, void *ctxt_info); -struct hdmi_audio_query_set_ops { - int (*hdmi_audio_get_caps)(enum had_caps_list query_element, - void *capabilties); - int (*hdmi_audio_set_caps)(enum had_caps_list set_element, - void *capabilties); -}; - struct hdmi_audio_event { int type; }; @@ -663,9 +656,7 @@ bool mid_hdmi_audio_is_busy(void *dev); bool mid_hdmi_audio_suspend(void *dev); void mid_hdmi_audio_resume(void *dev); void mid_hdmi_audio_signal_event(enum had_event_type event); -int mid_hdmi_audio_setup( - had_event_call_back audio_callbacks, - struct hdmi_audio_query_set_ops *query_ops); +int mid_hdmi_audio_setup(had_event_call_back audio_callbacks); int mid_hdmi_audio_register( struct snd_intel_had_interface *driver, void *had_data); @@ -674,4 +665,9 @@ int mid_hdmi_audio_read(u32 reg, u32 *val); int mid_hdmi_audio_write(u32 reg, u32 val); int mid_hdmi_audio_rmw(u32 reg, u32 val, u32 mask); +int mid_hdmi_audio_get_caps(enum had_caps_list get_element, + void *capabilities); +int mid_hdmi_audio_set_caps(enum had_caps_list set_element, + void *capabilties); + #endif -- cgit v1.2.3 From 6f9ecc76f4e04b111160d789f36a8c5bf1cc9ab6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Jan 2017 16:52:06 +0100 Subject: ALSA: x86: Drop snd_intel_had_interface indirect calls Yet another indirection is killed: at this time, it's snd_intel_had_interface. It contains also the name string, but it's nowhere used, thus we can kill it, too. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 9 +---- sound/x86/intel_hdmi_audio.h | 2 +- sound/x86/intel_hdmi_audio_if.c | 3 +- sound/x86/intel_hdmi_lpe_audio.c | 87 +++++++++------------------------------- sound/x86/intel_hdmi_lpe_audio.h | 13 +----- 5 files changed, 23 insertions(+), 91 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index a4c2f3f8d669..bff46061e5c5 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1568,13 +1568,6 @@ static struct snd_kcontrol_new had_control_iec958 = { .put = had_iec958_put }; -static struct snd_intel_had_interface had_interface = { - .name = "hdmi-audio", - .query = hdmi_audio_query, - .suspend = hdmi_audio_suspend, - .resume = hdmi_audio_resume, -}; - /** * hdmi_audio_probe - to create sound card instance for HDMI audio playabck * @@ -1704,7 +1697,7 @@ int hdmi_audio_probe(void *deviceptr) pm_runtime_enable(intelhaddata->dev); mutex_unlock(&had_mutex); - retval = mid_hdmi_audio_register(&had_interface, intelhaddata); + retval = mid_hdmi_audio_register(intelhaddata); if (retval) { pr_err("registering with display driver failed %#x\n", retval); snd_card_free(card); diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index e7c7432c5078..ba13ae63bea3 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -149,7 +149,7 @@ struct snd_intelhad { int had_event_handler(enum had_event_type event_type, void *data); int hdmi_audio_query(void *drv_data, struct hdmi_audio_event event); -int hdmi_audio_suspend(void *drv_data, struct hdmi_audio_event event); +int hdmi_audio_suspend(void *drv_data); int hdmi_audio_resume(void *drv_data); int hdmi_audio_mode_change(struct snd_pcm_substream *substream); extern struct snd_pcm_ops snd_intelhad_playback_ops; diff --git a/sound/x86/intel_hdmi_audio_if.c b/sound/x86/intel_hdmi_audio_if.c index 4334be100655..88ebcb5f7388 100644 --- a/sound/x86/intel_hdmi_audio_if.c +++ b/sound/x86/intel_hdmi_audio_if.c @@ -91,12 +91,11 @@ int hdmi_audio_query(void *haddata, struct hdmi_audio_event event) * hdmi_audio_suspend - power management suspend function * *@haddata: pointer to HAD private data - *@event: pm event for which this method is invoked * * This function is called by client driver to suspend the * hdmi audio. */ -int hdmi_audio_suspend(void *haddata, struct hdmi_audio_event event) +int hdmi_audio_suspend(void *haddata) { int caps, retval = 0; struct had_pvt_data *had_stream; diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c index 1747ff259903..51ba3493ff30 100644 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ b/sound/x86/intel_hdmi_lpe_audio.c @@ -45,7 +45,6 @@ struct hdmi_lpe_audio_ctx { int irq; void __iomem *mmio_start; had_event_call_back had_event_callbacks; - struct snd_intel_had_interface *had_interface; void *had_pvt_data; int tmds_clock_speed; bool dp_output; @@ -103,63 +102,9 @@ bool mid_hdmi_audio_is_busy(void *ddev) return false; } - if (ctx->had_interface) { - hdmi_audio_event.type = HAD_EVENT_QUERY_IS_AUDIO_BUSY; - hdmi_audio_busy = ctx->had_interface->query( - ctx->had_pvt_data, - hdmi_audio_event); - return hdmi_audio_busy != 0; - } - return false; -} - -/* - * return true if HDMI audio device is suspended/ disconnected - */ -bool mid_hdmi_audio_suspend(void *ddev) -{ - struct hdmi_lpe_audio_ctx *ctx; - struct hdmi_audio_event hdmi_audio_event; - int ret = 0; - - ctx = platform_get_drvdata(hlpe_pdev); - - if (hlpe_state == hdmi_connector_status_disconnected) { - /* HDMI is not connected, assuming audio device - * is suspended already. - */ - return true; - } - - dev_dbg(&hlpe_pdev->dev, "%s: hlpe_state %d", __func__, - hlpe_state); - - if (ctx->had_interface) { - hdmi_audio_event.type = 0; - ret = ctx->had_interface->suspend(ctx->had_pvt_data, - hdmi_audio_event); - return (ret == 0) ? true : false; - } - return true; -} - -void mid_hdmi_audio_resume(void *ddev) -{ - struct hdmi_lpe_audio_ctx *ctx; - - ctx = platform_get_drvdata(hlpe_pdev); - - if (hlpe_state == hdmi_connector_status_disconnected) { - /* HDMI is not connected, there is no need - * to resume audio device. - */ - return; - } - - dev_dbg(&hlpe_pdev->dev, "%s: hlpe_state %d", __func__, hlpe_state); - - if (ctx->had_interface) - ctx->had_interface->resume(ctx->had_pvt_data); + hdmi_audio_event.type = HAD_EVENT_QUERY_IS_AUDIO_BUSY; + hdmi_audio_busy = hdmi_audio_query(ctx->had_pvt_data, hdmi_audio_event); + return hdmi_audio_busy != 0; } void mid_hdmi_audio_signal_event(enum had_event_type event) @@ -331,8 +276,7 @@ static void _had_wq(struct work_struct *work) mid_hdmi_audio_signal_event(HAD_EVENT_HOT_PLUG); } -int mid_hdmi_audio_register(struct snd_intel_had_interface *driver, - void *had_data) +int mid_hdmi_audio_register(void *had_data) { struct hdmi_lpe_audio_ctx *ctx; @@ -341,7 +285,6 @@ int mid_hdmi_audio_register(struct snd_intel_had_interface *driver, dev_dbg(&hlpe_pdev->dev, "%s: called\n", __func__); ctx->had_pvt_data = had_data; - ctx->had_interface = driver; /* The Audio driver is loading now and we need to notify * it if there is an HDMI device attached @@ -578,18 +521,26 @@ static int hdmi_lpe_audio_remove(struct platform_device *pdev) return 0; } -static int hdmi_lpe_audio_suspend(struct platform_device *pt_dev, - pm_message_t state) +static int hdmi_lpe_audio_suspend(struct platform_device *pdev, + pm_message_t state) { - dev_dbg(&hlpe_pdev->dev, "Enter %s\n", __func__); - mid_hdmi_audio_suspend(NULL); + struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); + + dev_dbg(&pdev->dev, "%s: hlpe_state %d", __func__, hlpe_state); + /* HDMI is not connected, assuming audio device is suspended already */ + if (hlpe_state != hdmi_connector_status_disconnected) + hdmi_audio_suspend(ctx->had_pvt_data); return 0; } -static int hdmi_lpe_audio_resume(struct platform_device *pt_dev) +static int hdmi_lpe_audio_resume(struct platform_device *pdev) { - dev_dbg(&hlpe_pdev->dev, "Enter %s\n", __func__); - mid_hdmi_audio_resume(NULL); + struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); + + dev_dbg(&pdev->dev, "%s: hlpe_state %d", __func__, hlpe_state); + /* HDMI is not connected, there is no need to resume audio device */ + if (hlpe_state != hdmi_connector_status_disconnected) + hdmi_audio_resume(ctx->had_pvt_data); return 0; } diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index 5e925b728302..518d897f1806 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -645,21 +645,10 @@ struct hdmi_audio_event { int type; }; -struct snd_intel_had_interface { - const char *name; - int (*query)(void *had_data, struct hdmi_audio_event event); - int (*suspend)(void *had_data, struct hdmi_audio_event event); - int (*resume)(void *had_data); -}; - bool mid_hdmi_audio_is_busy(void *dev); -bool mid_hdmi_audio_suspend(void *dev); -void mid_hdmi_audio_resume(void *dev); void mid_hdmi_audio_signal_event(enum had_event_type event); int mid_hdmi_audio_setup(had_event_call_back audio_callbacks); -int mid_hdmi_audio_register( - struct snd_intel_had_interface *driver, - void *had_data); +int mid_hdmi_audio_register(void *had_data); int mid_hdmi_audio_read(u32 reg, u32 *val); int mid_hdmi_audio_write(u32 reg, u32 val); -- cgit v1.2.3 From 79dda75a2cfc5628f25338122d24ee8789b367cf Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Jan 2017 17:23:39 +0100 Subject: ALSA: x86: Pass snd_intelhad object to helpers For reducing the global variable reference, keep snd_intelhad object in the context and pass it to each helper. It's a preliminary change for further cleanup. This also includes the simplification of the probe procedure: the LPE platform driver directly gets the created snd_intelhad object by hdmi_audio_probe(), and passes it to each helper and destructor, hdmi_audio_remove(). The hdmi_audio_probe() function doesn't call the back-registration any longer, which is fairly useless. The LPE platform driver initializes the stuff instead at the right place, and calls the wq after the object creation in the probe function itself. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 143 ++++++++++++++++++++------------------- sound/x86/intel_hdmi_audio.h | 24 ++++--- sound/x86/intel_hdmi_audio_if.c | 44 ++++++------ sound/x86/intel_hdmi_lpe_audio.c | 49 +++++--------- sound/x86/intel_hdmi_lpe_audio.h | 1 - 5 files changed, 131 insertions(+), 130 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index bff46061e5c5..45ba16e27323 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -42,7 +42,6 @@ static DEFINE_MUTEX(had_mutex); /*standard module options for ALSA. This module supports only one card*/ static int hdmi_card_index = SNDRV_DEFAULT_IDX1; static char *hdmi_card_id = SNDRV_DEFAULT_STR1; -static struct snd_intelhad *had_data; static int underrun_count; module_param_named(index, hdmi_card_index, int, 0444); @@ -172,10 +171,10 @@ int had_get_hwstate(struct snd_intelhad *intelhaddata) return 0; } -int had_get_caps(enum had_caps_list query, void *caps) +int had_get_caps(struct snd_intelhad *intelhaddata, + enum had_caps_list query, void *caps) { int retval; - struct snd_intelhad *intelhaddata = had_data; retval = had_get_hwstate(intelhaddata); if (!retval) @@ -184,10 +183,10 @@ int had_get_caps(enum had_caps_list query, void *caps) return retval; } -int had_set_caps(enum had_caps_list set_element, void *caps) +int had_set_caps(struct snd_intelhad *intelhaddata, + enum had_caps_list set_element, void *caps) { int retval; - struct snd_intelhad *intelhaddata = had_data; retval = had_get_hwstate(intelhaddata); if (!retval) @@ -196,10 +195,9 @@ int had_set_caps(enum had_caps_list set_element, void *caps) return retval; } -int had_read_register(u32 offset, u32 *data) +int had_read_register(struct snd_intelhad *intelhaddata, u32 offset, u32 *data) { int retval; - struct snd_intelhad *intelhaddata = had_data; retval = had_get_hwstate(intelhaddata); if (!retval) @@ -208,10 +206,9 @@ int had_read_register(u32 offset, u32 *data) return retval; } -int had_write_register(u32 offset, u32 data) +int had_write_register(struct snd_intelhad *intelhaddata, u32 offset, u32 data) { int retval; - struct snd_intelhad *intelhaddata = had_data; retval = had_get_hwstate(intelhaddata); if (!retval) @@ -220,10 +217,10 @@ int had_write_register(u32 offset, u32 data) return retval; } -int had_read_modify(u32 offset, u32 data, u32 mask) +int had_read_modify(struct snd_intelhad *intelhaddata, u32 offset, + u32 data, u32 mask) { int retval; - struct snd_intelhad *intelhaddata = had_data; retval = had_get_hwstate(intelhaddata); if (!retval) @@ -253,6 +250,7 @@ int had_read_modify(u32 offset, u32 data, u32 mask) static int had_read_modify_aud_config_v2(struct snd_pcm_substream *substream, u32 data, u32 mask) { + struct snd_intelhad *intelhaddata = snd_pcm_substream_chip(substream); union aud_cfg cfg_val = {.cfg_regval = 0}; u8 channels; @@ -271,7 +269,7 @@ static int had_read_modify_aud_config_v2(struct snd_pcm_substream *substream, pr_debug("%s : data = %x, mask =%x\n", __func__, data, mask); - return had_read_modify(AUD_CONFIG, data, mask); + return had_read_modify(intelhaddata, AUD_CONFIG, data, mask); } void snd_intelhad_enable_audio(struct snd_pcm_substream *substream, u8 enable) @@ -279,9 +277,10 @@ void snd_intelhad_enable_audio(struct snd_pcm_substream *substream, u8 enable) had_read_modify_aud_config_v2(substream, enable, BIT(0)); } -static void snd_intelhad_reset_audio(u8 reset) +static void snd_intelhad_reset_audio(struct snd_intelhad *intelhaddata, + u8 reset) { - had_write_register(AUD_HDMI_STATUS_v2, reset); + had_write_register(intelhaddata, AUD_HDMI_STATUS_v2, reset); } /** @@ -334,7 +333,8 @@ static int had_prog_status_reg(struct snd_pcm_substream *substream, break; } - had_write_register(AUD_CH_STATUS_0, ch_stat0.status_0_regval); + had_write_register(intelhaddata, + AUD_CH_STATUS_0, ch_stat0.status_0_regval); format = substream->runtime->format; @@ -348,7 +348,8 @@ static int had_prog_status_reg(struct snd_pcm_substream *substream, ch_stat1.status_1_regx.max_wrd_len = 0; ch_stat1.status_1_regx.wrd_len = 0; } - had_write_register(AUD_CH_STATUS_1, ch_stat1.status_1_regval); + had_write_register(intelhaddata, + AUD_CH_STATUS_1, ch_stat1.status_1_regval); return 0; } @@ -369,7 +370,7 @@ static int snd_intelhad_audio_ctrl(struct snd_pcm_substream *substream, buf_cfg.buf_cfg_regx_v2.audio_fifo_watermark = FIFO_THRESHOLD; buf_cfg.buf_cfg_regx_v2.dma_fifo_watermark = DMA_FIFO_THRESHOLD; buf_cfg.buf_cfg_regx_v2.aud_delay = 0; - had_write_register(AUD_BUF_CONFIG, buf_cfg.buf_cfgval); + had_write_register(intelhaddata, AUD_BUF_CONFIG, buf_cfg.buf_cfgval); channels = substream->runtime->channels; cfg_val.cfg_regx_v2.num_ch = channels - 2; @@ -379,7 +380,7 @@ static int snd_intelhad_audio_ctrl(struct snd_pcm_substream *substream, cfg_val.cfg_regx_v2.layout = LAYOUT1; cfg_val.cfg_regx_v2.val_bit = 1; - had_write_register(AUD_CONFIG, cfg_val.cfg_regval); + had_write_register(intelhaddata, AUD_CONFIG, cfg_val.cfg_regval); return 0; } @@ -479,8 +480,8 @@ void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata) return; } - had_get_caps(HAD_GET_ELD, &intelhaddata->eeld); - had_get_caps(HAD_GET_DP_OUTPUT, &intelhaddata->dp_output); + had_get_caps(intelhaddata, HAD_GET_ELD, &intelhaddata->eeld); + had_get_caps(intelhaddata, HAD_GET_DP_OUTPUT, &intelhaddata->dp_output); pr_debug("eeld.speaker_allocation_block = %x\n", intelhaddata->eeld.speaker_allocation_block); @@ -610,7 +611,7 @@ static void snd_intelhad_prog_dip(struct snd_pcm_substream *substream, channels = substream->runtime->channels; - had_write_register(AUD_CNTL_ST, ctrl_state.ctrl_val); + had_write_register(intelhaddata, AUD_CNTL_ST, ctrl_state.ctrl_val); if (intelhaddata->dp_output) { info_frame = DP_INFO_FRAME_WORD1; @@ -633,17 +634,17 @@ static void snd_intelhad_prog_dip(struct snd_pcm_substream *substream, frame2.fr2_regx.chksum = -(checksum); } - had_write_register(AUD_HDMIW_INFOFR_v2, info_frame); - had_write_register(AUD_HDMIW_INFOFR_v2, frame2.fr2_val); - had_write_register(AUD_HDMIW_INFOFR_v2, frame3.fr3_val); + had_write_register(intelhaddata, AUD_HDMIW_INFOFR_v2, info_frame); + had_write_register(intelhaddata, AUD_HDMIW_INFOFR_v2, frame2.fr2_val); + had_write_register(intelhaddata, AUD_HDMIW_INFOFR_v2, frame3.fr3_val); /* program remaining DIP words with zero */ for (i = 0; i < HAD_MAX_DIP_WORDS-VALID_DIP_WORDS; i++) - had_write_register(AUD_HDMIW_INFOFR_v2, 0x0); + had_write_register(intelhaddata, AUD_HDMIW_INFOFR_v2, 0x0); ctrl_state.ctrl_regx.dip_freq = 1; ctrl_state.ctrl_regx.dip_en_sta = 1; - had_write_register(AUD_CNTL_ST, ctrl_state.ctrl_val); + had_write_register(intelhaddata, AUD_CNTL_ST, ctrl_state.ctrl_val); } /** @@ -696,10 +697,12 @@ int snd_intelhad_prog_buffer(struct snd_intelhad *intelhaddata, intelhaddata->buf_info[i].buf_size = ring_buf_size - (period_bytes*i); - had_write_register(AUD_BUF_A_ADDR + (i * HAD_REG_WIDTH), + had_write_register(intelhaddata, + AUD_BUF_A_ADDR + (i * HAD_REG_WIDTH), intelhaddata->buf_info[i].buf_addr | BIT(0) | BIT(1)); - had_write_register(AUD_BUF_A_LENGTH + (i * HAD_REG_WIDTH), + had_write_register(intelhaddata, + AUD_BUF_A_LENGTH + (i * HAD_REG_WIDTH), period_bytes); intelhaddata->buf_info[i].is_valid = true; } @@ -716,8 +719,9 @@ int snd_intelhad_read_len(struct snd_intelhad *intelhaddata) u32 len[4]; for (i = 0; i < 4 ; i++) { - had_read_register(AUD_BUF_A_LENGTH + (i * HAD_REG_WIDTH), - &len[i]); + had_read_register(intelhaddata, + AUD_BUF_A_LENGTH + (i * HAD_REG_WIDTH), + &len[i]); if (!len[i]) retval++; } @@ -836,7 +840,7 @@ static void snd_intelhad_prog_cts(u32 aud_samp_freq, u32 tmds, } pr_debug("TMDS value=%d, N value=%d, CTS Value=%d\n", tmds, n_param, cts_val); - had_write_register(AUD_HDMI_CTS, (BIT(24) | cts_val)); + had_write_register(intelhaddata, AUD_HDMI_CTS, (BIT(24) | cts_val)); } static int had_calculate_n_value(u32 aud_samp_freq) @@ -911,7 +915,7 @@ static int snd_intelhad_prog_n(u32 aud_samp_freq, u32 *n_param, if (n_val < 0) return n_val; - had_write_register(AUD_N_ENABLE, (BIT(24) | n_val)); + had_write_register(intelhaddata, AUD_N_ENABLE, (BIT(24) | n_val)); *n_param = n_val; return 0; } @@ -921,20 +925,22 @@ void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata) u32 hdmi_status, i = 0; /* Handle Underrun interrupt within Audio Unit */ - had_write_register(AUD_CONFIG, 0); + had_write_register(intelhaddata, AUD_CONFIG, 0); /* Reset buffer pointers */ - had_write_register(AUD_HDMI_STATUS_v2, 1); - had_write_register(AUD_HDMI_STATUS_v2, 0); + had_write_register(intelhaddata, AUD_HDMI_STATUS_v2, 1); + had_write_register(intelhaddata, AUD_HDMI_STATUS_v2, 0); /** * The interrupt status 'sticky' bits might not be cleared by * setting '1' to that bit once... */ do { /* clear bit30, 31 AUD_HDMI_STATUS */ - had_read_register(AUD_HDMI_STATUS_v2, &hdmi_status); + had_read_register(intelhaddata, AUD_HDMI_STATUS_v2, + &hdmi_status); pr_debug("HDMI status =0x%x\n", hdmi_status); if (hdmi_status & AUD_CONFIG_MASK_UNDERRUN) { i++; - had_write_register(AUD_HDMI_STATUS_v2, hdmi_status); + had_write_register(intelhaddata, + AUD_HDMI_STATUS_v2, hdmi_status); } else break; } while (i < MAX_CNT); @@ -1200,8 +1206,9 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, * caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE; */ caps = HDMI_AUDIO_BUFFER_DONE; - retval = had_set_caps(HAD_SET_ENABLE_AUDIO_INT, &caps); - retval = had_set_caps(HAD_SET_ENABLE_AUDIO, NULL); + retval = had_set_caps(intelhaddata, HAD_SET_ENABLE_AUDIO_INT, + &caps); + retval = had_set_caps(intelhaddata, HAD_SET_ENABLE_AUDIO, NULL); snd_intelhad_enable_audio(substream, 1); pr_debug("Processed _Start\n"); @@ -1224,13 +1231,13 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, * caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE; */ caps = HDMI_AUDIO_BUFFER_DONE; - had_set_caps(HAD_SET_DISABLE_AUDIO_INT, &caps); + had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO_INT, &caps); snd_intelhad_enable_audio(substream, 0); /* Reset buffer pointers */ - snd_intelhad_reset_audio(1); - snd_intelhad_reset_audio(0); + snd_intelhad_reset_audio(intelhaddata, 1); + snd_intelhad_reset_audio(intelhaddata, 0); stream->stream_status = STREAM_DROPPED; - had_set_caps(HAD_SET_DISABLE_AUDIO, NULL); + had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO, NULL); break; default: @@ -1288,14 +1295,15 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) /* Get N value in KHz */ - retval = had_get_caps(HAD_GET_DISPLAY_RATE, &disp_samp_freq); + retval = had_get_caps(intelhaddata, HAD_GET_DISPLAY_RATE, + &disp_samp_freq); if (retval) { pr_err("querying display sampling freq failed %#x\n", retval); goto prep_end; } - had_get_caps(HAD_GET_ELD, &intelhaddata->eeld); - had_get_caps(HAD_GET_DP_OUTPUT, &intelhaddata->dp_output); + had_get_caps(intelhaddata, HAD_GET_ELD, &intelhaddata->eeld); + had_get_caps(intelhaddata, HAD_GET_DP_OUTPUT, &intelhaddata->dp_output); retval = snd_intelhad_prog_n(substream->runtime->rate, &n_param, intelhaddata); @@ -1305,7 +1313,7 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) } if (intelhaddata->dp_output) - had_get_caps(HAD_GET_LINK_RATE, &link_rate); + had_get_caps(intelhaddata, HAD_GET_LINK_RATE, &link_rate); snd_intelhad_prog_cts(substream->runtime->rate, @@ -1325,7 +1333,7 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) * FL, FR, C, LFE, RL, RR */ - had_write_register(AUD_BUF_CH_SWAP, SWAP_LFE_CENTER); + had_write_register(intelhaddata, AUD_BUF_CH_SWAP, SWAP_LFE_CENTER); prep_end: return retval; @@ -1361,7 +1369,8 @@ static snd_pcm_uframes_t snd_intelhad_pcm_pointer( */ buf_id = intelhaddata->curr_buf % 4; - had_read_register(AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH), &t); + had_read_register(intelhaddata, + AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH), &t); if ((t == 0) || (t == ((u32)-1L))) { underrun_count++; @@ -1427,7 +1436,8 @@ int hdmi_audio_mode_change(struct snd_pcm_substream *substream) snd_intelhad_enable_audio(substream, 0); /* Update CTS value */ - retval = had_get_caps(HAD_GET_DISPLAY_RATE, &disp_samp_freq); + retval = had_get_caps(intelhaddata, HAD_GET_DISPLAY_RATE, + &disp_samp_freq); if (retval) { pr_err("querying display sampling freq failed %#x\n", retval); goto out; @@ -1441,7 +1451,7 @@ int hdmi_audio_mode_change(struct snd_pcm_substream *substream) } if (intelhaddata->dp_output) - had_get_caps(HAD_GET_LINK_RATE, &link_rate); + had_get_caps(intelhaddata, HAD_GET_LINK_RATE, &link_rate); snd_intelhad_prog_cts(substream->runtime->rate, disp_samp_freq, link_rate, @@ -1568,16 +1578,17 @@ static struct snd_kcontrol_new had_control_iec958 = { .put = had_iec958_put }; -/** +/* * hdmi_audio_probe - to create sound card instance for HDMI audio playabck * - *@haddata: pointer to HAD private data - *@card_id: card for which probe is called + * @devptr: platform device + * @had_ret: pointer to store the created snd_intelhad object * - * This function is called when the hdmi cable is plugged in. This function + * This function is called when the platform device is probed. This function * creates and registers the sound card with ALSA */ -int hdmi_audio_probe(void *deviceptr) +int hdmi_audio_probe(struct platform_device *devptr, + struct snd_intelhad **had_ret) { int retval; struct snd_pcm *pcm; @@ -1585,7 +1596,6 @@ int hdmi_audio_probe(void *deviceptr) struct had_callback_ops ops_cb; struct snd_intelhad *intelhaddata; struct had_pvt_data *had_stream; - struct platform_device *devptr = deviceptr; pr_debug("Enter %s\n", __func__); @@ -1602,7 +1612,6 @@ int hdmi_audio_probe(void *deviceptr) goto free_haddata; } - had_data = intelhaddata; ops_cb.intel_had_event_call_back = had_event_handler; /* registering with display driver to get access to display APIs */ @@ -1697,16 +1706,11 @@ int hdmi_audio_probe(void *deviceptr) pm_runtime_enable(intelhaddata->dev); mutex_unlock(&had_mutex); - retval = mid_hdmi_audio_register(intelhaddata); - if (retval) { - pr_err("registering with display driver failed %#x\n", retval); - snd_card_free(card); - goto free_hadstream; - } intelhaddata->hw_silence = 1; + *had_ret = intelhaddata; - return retval; + return 0; err: snd_card_free(card); unlock_mutex: @@ -1722,7 +1726,7 @@ free_haddata: return retval; } -/** +/* * hdmi_audio_remove - removes the alsa card * *@haddata: pointer to HAD private data @@ -1730,9 +1734,8 @@ free_haddata: * This function is called when the hdmi cable is un-plugged. This function * free the sound card. */ -int hdmi_audio_remove(void *pdevptr) +int hdmi_audio_remove(struct snd_intelhad *intelhaddata) { - struct snd_intelhad *intelhaddata = had_data; int caps; pr_debug("Enter %s\n", __func__); @@ -1742,8 +1745,8 @@ int hdmi_audio_remove(void *pdevptr) if (intelhaddata->drv_status != HAD_DRV_DISCONNECTED) { caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE; - had_set_caps(HAD_SET_DISABLE_AUDIO_INT, &caps); - had_set_caps(HAD_SET_DISABLE_AUDIO, NULL); + had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO_INT, &caps); + had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO, NULL); } snd_card_free(intelhaddata->card); kfree(intelhaddata->private_data); diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index ba13ae63bea3..5a82a3f429d7 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -39,6 +39,8 @@ #include #include "intel_hdmi_lpe_audio.h" +struct platform_device; + #define PCM_INDEX 0 #define MAX_PB_STREAMS 1 #define MAX_CAP_STREAMS 0 @@ -168,13 +170,19 @@ void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata); /* Register access functions */ int had_get_hwstate(struct snd_intelhad *intelhaddata); -int had_get_caps(enum had_caps_list query_element, void *capabilties); -int had_set_caps(enum had_caps_list set_element, void *capabilties); -int had_read_register(u32 reg_addr, u32 *data); -int had_write_register(u32 reg_addr, u32 data); -int had_read_modify(u32 reg_addr, u32 data, u32 mask); - -int hdmi_audio_probe(void *devptr); -int hdmi_audio_remove(void *pdev); +int had_get_caps(struct snd_intelhad *intelhaddata, + enum had_caps_list query_element, void *capabilties); +int had_set_caps(struct snd_intelhad *intelhaddata, + enum had_caps_list set_element, void *capabilties); +int had_read_register(struct snd_intelhad *intelhaddata, + u32 reg_addr, u32 *data); +int had_write_register(struct snd_intelhad *intelhaddata, + u32 reg_addr, u32 data); +int had_read_modify(struct snd_intelhad *intelhaddata, + u32 reg_addr, u32 data, u32 mask); + +int hdmi_audio_probe(struct platform_device *devptr, + struct snd_intelhad **had_ret); +int hdmi_audio_remove(struct snd_intelhad *intelhaddata); #endif /* _INTEL_HDMI_AUDIO_ */ diff --git a/sound/x86/intel_hdmi_audio_if.c b/sound/x86/intel_hdmi_audio_if.c index 88ebcb5f7388..8e3a0943332b 100644 --- a/sound/x86/intel_hdmi_audio_if.c +++ b/sound/x86/intel_hdmi_audio_if.c @@ -137,8 +137,8 @@ int hdmi_audio_suspend(void *haddata) * caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE; */ caps = HDMI_AUDIO_BUFFER_DONE; - had_set_caps(HAD_SET_DISABLE_AUDIO_INT, &caps); - had_set_caps(HAD_SET_DISABLE_AUDIO, NULL); + had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO_INT, &caps); + had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO, NULL); pr_debug("Exit:%s", __func__); return retval; } @@ -187,8 +187,8 @@ int hdmi_audio_resume(void *haddata) * caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE; */ caps = HDMI_AUDIO_BUFFER_DONE; - retval = had_set_caps(HAD_SET_ENABLE_AUDIO_INT, &caps); - retval = had_set_caps(HAD_SET_ENABLE_AUDIO, NULL); + retval = had_set_caps(intelhaddata, HAD_SET_ENABLE_AUDIO_INT, &caps); + retval = had_set_caps(intelhaddata, HAD_SET_ENABLE_AUDIO, NULL); pr_debug("Exit:%s", __func__); return retval; } @@ -221,11 +221,12 @@ static inline int had_chk_intrmiss(struct snd_intelhad *intelhaddata, buf_size = intelhaddata->buf_info[j].buf_size; buf_addr = intelhaddata->buf_info[j].buf_addr; - had_write_register(AUD_BUF_A_LENGTH + - (j * HAD_REG_WIDTH), buf_size); - had_write_register( - AUD_BUF_A_ADDR+(j * HAD_REG_WIDTH), - (buf_addr | BIT(0) | BIT(1))); + had_write_register(intelhaddata, + AUD_BUF_A_LENGTH + + (j * HAD_REG_WIDTH), buf_size); + had_write_register(intelhaddata, + AUD_BUF_A_ADDR+(j * HAD_REG_WIDTH), + (buf_addr | BIT(0) | BIT(1))); } buf_id = buf_id % 4; spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); @@ -300,14 +301,17 @@ int had_process_buffer_done(struct snd_intelhad *intelhaddata) } /*Reprogram the registers with addr and length*/ - had_write_register(AUD_BUF_A_LENGTH + - (buf_id * HAD_REG_WIDTH), buf_size); - had_write_register(AUD_BUF_A_ADDR+(buf_id * HAD_REG_WIDTH), - intelhaddata->buf_info[buf_id].buf_addr| - BIT(0) | BIT(1)); - - had_read_register(AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH), - &len); + had_write_register(intelhaddata, + AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH), + buf_size); + had_write_register(intelhaddata, + AUD_BUF_A_ADDR + (buf_id * HAD_REG_WIDTH), + intelhaddata->buf_info[buf_id].buf_addr | + BIT(0) | BIT(1)); + + had_read_register(intelhaddata, + AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH), + &len); pr_debug("%s:Enabled buf[%d]\n", __func__, buf_id); /* In case of actual data, @@ -427,8 +431,10 @@ int had_process_hot_unplug(struct snd_intelhad *intelhaddata) } else { /* Disable Audio */ caps = HDMI_AUDIO_BUFFER_DONE; - retval = had_set_caps(HAD_SET_DISABLE_AUDIO_INT, &caps); - retval = had_set_caps(HAD_SET_DISABLE_AUDIO, NULL); + retval = had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO_INT, + &caps); + retval = had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO, + NULL); snd_intelhad_enable_audio( intelhaddata->stream_info.had_substream, 0); } diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c index 51ba3493ff30..18a2ae6796b8 100644 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ b/sound/x86/intel_hdmi_lpe_audio.c @@ -45,7 +45,7 @@ struct hdmi_lpe_audio_ctx { int irq; void __iomem *mmio_start; had_event_call_back had_event_callbacks; - void *had_pvt_data; + struct snd_intelhad *had; int tmds_clock_speed; bool dp_output; int link_rate; @@ -103,7 +103,7 @@ bool mid_hdmi_audio_is_busy(void *ddev) } hdmi_audio_event.type = HAD_EVENT_QUERY_IS_AUDIO_BUSY; - hdmi_audio_busy = hdmi_audio_query(ctx->had_pvt_data, hdmi_audio_event); + hdmi_audio_busy = hdmi_audio_query(ctx->had, hdmi_audio_event); return hdmi_audio_busy != 0; } @@ -119,8 +119,7 @@ void mid_hdmi_audio_signal_event(enum had_event_type event) * event handlers to avoid races */ if (ctx->had_event_callbacks) - (*ctx->had_event_callbacks)(event, - ctx->had_pvt_data); + (*ctx->had_event_callbacks)(event, ctx->had); } /* @@ -276,27 +275,6 @@ static void _had_wq(struct work_struct *work) mid_hdmi_audio_signal_event(HAD_EVENT_HOT_PLUG); } -int mid_hdmi_audio_register(void *had_data) -{ - struct hdmi_lpe_audio_ctx *ctx; - - ctx = platform_get_drvdata(hlpe_pdev); - - dev_dbg(&hlpe_pdev->dev, "%s: called\n", __func__); - - ctx->had_pvt_data = had_data; - - /* The Audio driver is loading now and we need to notify - * it if there is an HDMI device attached - */ - INIT_WORK(&ctx->hdmi_audio_wq, _had_wq); - dev_dbg(&hlpe_pdev->dev, "%s: Scheduling HDMI audio work queue\n", - __func__); - schedule_work(&ctx->hdmi_audio_wq); - - return 0; -} - static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id) { u32 audio_stat, audio_reg; @@ -460,6 +438,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) dev_dbg(&hlpe_pdev->dev, "hdmi lpe audio: irq num = %d\n", irq); ctx->mmio_start = mmio_start; ctx->tmds_clock_speed = DIS_SAMPLE_RATE_148_5; + INIT_WORK(&ctx->hdmi_audio_wq, _had_wq); if (pci_dev_present(cherryview_ids)) dev_dbg(&hlpe_pdev->dev, "%s: Cherrytrail LPE - Detected\n", @@ -483,9 +462,16 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ctx); - ret = hdmi_audio_probe((void *)pdev); + ret = hdmi_audio_probe(pdev, &ctx->had); dev_dbg(&hlpe_pdev->dev, "hdmi lpe audio: setting pin eld notify callback\n"); + /* The Audio driver is loading now and we need to notify + * it if there is an HDMI device attached + */ + dev_dbg(&hlpe_pdev->dev, "%s: Scheduling HDMI audio work queue\n", + __func__); + schedule_work(&ctx->hdmi_audio_wq); + spin_lock_irqsave(&pdata->lpe_audio_slock, flag_irq); pdata->notify_audio_lpe = notify_audio_lpe; if (pdata->notify_pending) { @@ -507,14 +493,13 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) */ static int hdmi_lpe_audio_remove(struct platform_device *pdev) { - struct hdmi_lpe_audio_ctx *ctx; + struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); dev_dbg(&hlpe_pdev->dev, "Enter %s\n", __func__); - hdmi_audio_remove(pdev); + hdmi_audio_remove(ctx->had); - /* get context, release resources */ - ctx = platform_get_drvdata(pdev); + /* release resources */ iounmap(ctx->mmio_start); free_irq(ctx->irq, NULL); kfree(ctx); @@ -529,7 +514,7 @@ static int hdmi_lpe_audio_suspend(struct platform_device *pdev, dev_dbg(&pdev->dev, "%s: hlpe_state %d", __func__, hlpe_state); /* HDMI is not connected, assuming audio device is suspended already */ if (hlpe_state != hdmi_connector_status_disconnected) - hdmi_audio_suspend(ctx->had_pvt_data); + hdmi_audio_suspend(ctx->had); return 0; } @@ -540,7 +525,7 @@ static int hdmi_lpe_audio_resume(struct platform_device *pdev) dev_dbg(&pdev->dev, "%s: hlpe_state %d", __func__, hlpe_state); /* HDMI is not connected, there is no need to resume audio device */ if (hlpe_state != hdmi_connector_status_disconnected) - hdmi_audio_resume(ctx->had_pvt_data); + hdmi_audio_resume(ctx->had); return 0; } diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index 518d897f1806..0d285ce8d4e6 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -648,7 +648,6 @@ struct hdmi_audio_event { bool mid_hdmi_audio_is_busy(void *dev); void mid_hdmi_audio_signal_event(enum had_event_type event); int mid_hdmi_audio_setup(had_event_call_back audio_callbacks); -int mid_hdmi_audio_register(void *had_data); int mid_hdmi_audio_read(u32 reg, u32 *val); int mid_hdmi_audio_write(u32 reg, u32 val); -- cgit v1.2.3 From 45459d16867988a792a18233bdfc294492976841 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 08:29:56 +0100 Subject: ALSA: x86: Handle the error from hdmi_audio_probe() properly The error from hdmi_audio_probe() wasn't handled properly, and it may leave some resources leaked or mapped. Fix it and also clean up the error paths. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_lpe_audio.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c index 18a2ae6796b8..0c11d82eb99b 100644 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ b/sound/x86/intel_hdmi_lpe_audio.c @@ -422,16 +422,14 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) NULL); if (ret < 0) { dev_err(&hlpe_pdev->dev, "request_irq failed\n"); - iounmap(mmio_start); - return -ENODEV; + goto error_irq; } /* alloc and save context */ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (ctx == NULL) { - free_irq(irq, NULL); - iounmap(mmio_start); - return -ENOMEM; + ret = -ENOMEM; + goto error_ctx; } ctx->irq = irq; @@ -454,15 +452,16 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) if (pdata == NULL) { dev_err(&hlpe_pdev->dev, "%s: quit: pdata not allocated by i915!!\n", __func__); - kfree(ctx); - free_irq(irq, NULL); - iounmap(mmio_start); - return -ENOMEM; + ret = -ENOMEM; + goto error_probe; } platform_set_drvdata(pdev, ctx); ret = hdmi_audio_probe(pdev, &ctx->had); + if (ret < 0) + goto error_probe; + dev_dbg(&hlpe_pdev->dev, "hdmi lpe audio: setting pin eld notify callback\n"); /* The Audio driver is loading now and we need to notify @@ -483,6 +482,14 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) spin_unlock_irqrestore(&pdata->lpe_audio_slock, flag_irq); return ret; + + error_probe: + kfree(ctx); + error_ctx: + free_irq(irq, NULL); + error_irq: + iounmap(mmio_start); + return ret; } /** -- cgit v1.2.3 From dd895f2e9b013a5387372dbf3a7d8405aaeb494e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Jan 2017 17:31:29 +0100 Subject: ALSA: x86: Drop useless mutex at probe had_mutex is (supposedly) used to protect the concurrent calls of hdmi_audio_probe(). But we may have only one device at most, so it's utterly useless. Drop it. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 45ba16e27323..7165f14d5229 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -37,8 +37,6 @@ #include #include "intel_hdmi_audio.h" -static DEFINE_MUTEX(had_mutex); - /*standard module options for ALSA. This module supports only one card*/ static int hdmi_card_index = SNDRV_DEFAULT_IDX1; static char *hdmi_card_id = SNDRV_DEFAULT_STR1; @@ -1621,7 +1619,7 @@ int hdmi_audio_probe(struct platform_device *devptr, pr_err("querying display driver APIs failed %#x\n", retval); goto free_hadstream; } - mutex_lock(&had_mutex); + spin_lock_init(&intelhaddata->had_spinlock); intelhaddata->drv_status = HAD_DRV_DISCONNECTED; pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", @@ -1632,7 +1630,7 @@ int hdmi_audio_probe(struct platform_device *devptr, THIS_MODULE, 0, &card); if (retval) - goto unlock_mutex; + goto free_hadstream; intelhaddata->card = card; intelhaddata->card_id = hdmi_card_id; intelhaddata->card_index = card->number; @@ -1705,16 +1703,12 @@ int hdmi_audio_probe(struct platform_device *devptr, pm_runtime_set_active(intelhaddata->dev); pm_runtime_enable(intelhaddata->dev); - mutex_unlock(&had_mutex); - intelhaddata->hw_silence = 1; *had_ret = intelhaddata; return 0; err: snd_card_free(card); -unlock_mutex: - mutex_unlock(&had_mutex); free_hadstream: kfree(had_stream); pm_runtime_disable(intelhaddata->dev); -- cgit v1.2.3 From 437af8f2946231ee141bc2a8d37063a8bb6047b0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Jan 2017 17:38:00 +0100 Subject: ALSA: x86: Call event callback directly Currently the driver calls the event callback stored in its ctx pointer, but it's obviously inefficient. Replace it with the direct calls. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 11 ----------- sound/x86/intel_hdmi_audio.h | 4 ---- sound/x86/intel_hdmi_lpe_audio.c | 17 +---------------- sound/x86/intel_hdmi_lpe_audio.h | 4 ---- 4 files changed, 1 insertion(+), 35 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 7165f14d5229..571ec07a3611 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1591,7 +1591,6 @@ int hdmi_audio_probe(struct platform_device *devptr, int retval; struct snd_pcm *pcm; struct snd_card *card; - struct had_callback_ops ops_cb; struct snd_intelhad *intelhaddata; struct had_pvt_data *had_stream; @@ -1610,16 +1609,6 @@ int hdmi_audio_probe(struct platform_device *devptr, goto free_haddata; } - ops_cb.intel_had_event_call_back = had_event_handler; - - /* registering with display driver to get access to display APIs */ - - retval = mid_hdmi_audio_setup(ops_cb.intel_had_event_call_back); - if (retval) { - pr_err("querying display driver APIs failed %#x\n", retval); - goto free_hadstream; - } - spin_lock_init(&intelhaddata->had_spinlock); intelhaddata->drv_status = HAD_DRV_DISCONNECTED; pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 5a82a3f429d7..110d1d083000 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -99,10 +99,6 @@ struct had_pvt_data { enum had_status_stream stream_type; }; -struct had_callback_ops { - had_event_call_back intel_had_event_call_back; -}; - /** * struct snd_intelhad - intelhad driver structure * diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c index 0c11d82eb99b..54cc30f034f3 100644 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ b/sound/x86/intel_hdmi_lpe_audio.c @@ -44,7 +44,6 @@ static union otm_hdmi_eld_t hlpe_eld; struct hdmi_lpe_audio_ctx { int irq; void __iomem *mmio_start; - had_event_call_back had_event_callbacks; struct snd_intelhad *had; int tmds_clock_speed; bool dp_output; @@ -118,8 +117,7 @@ void mid_hdmi_audio_signal_event(enum had_event_type event) /* The handler is protected in the respective * event handlers to avoid races */ - if (ctx->had_event_callbacks) - (*ctx->had_event_callbacks)(event, ctx->had); + had_event_handler(event, ctx->had); } /* @@ -257,19 +255,6 @@ int mid_hdmi_audio_set_caps(enum had_caps_list set_element, return 0; } -int mid_hdmi_audio_setup(had_event_call_back audio_callbacks) -{ - struct hdmi_lpe_audio_ctx *ctx; - - ctx = platform_get_drvdata(hlpe_pdev); - - dev_dbg(&hlpe_pdev->dev, "%s: called\n", __func__); - - ctx->had_event_callbacks = audio_callbacks; - - return 0; -} - static void _had_wq(struct work_struct *work) { mid_hdmi_audio_signal_event(HAD_EVENT_HOT_PLUG); diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index 0d285ce8d4e6..511bdc30dca1 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -638,16 +638,12 @@ enum had_event_type { * HDMI Display Controller Audio Interface * */ -typedef int (*had_event_call_back) (enum had_event_type event_type, - void *ctxt_info); - struct hdmi_audio_event { int type; }; bool mid_hdmi_audio_is_busy(void *dev); void mid_hdmi_audio_signal_event(enum had_event_type event); -int mid_hdmi_audio_setup(had_event_call_back audio_callbacks); int mid_hdmi_audio_read(u32 reg, u32 *val); int mid_hdmi_audio_write(u32 reg, u32 val); -- cgit v1.2.3 From 033e925f68c92d058f2be67f941804e7e4f06f7c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Jan 2017 17:40:04 +0100 Subject: ALSA: x86: Fix possible stale interrupt calls Registering the irq handler at the too early place may cause a system stall because the irq handler may be triggered before the other initializations. Move the irq handler registration to the later point. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_lpe_audio.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c index 54cc30f034f3..f5249b0a4ce4 100644 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ b/sound/x86/intel_hdmi_lpe_audio.c @@ -400,16 +400,6 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) return -EACCES; } - /* setup interrupt handler */ - ret = request_irq(irq, display_pipe_interrupt_handler, - 0, - pdev->name, - NULL); - if (ret < 0) { - dev_err(&hlpe_pdev->dev, "request_irq failed\n"); - goto error_irq; - } - /* alloc and save context */ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (ctx == NULL) { @@ -438,11 +428,21 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) if (pdata == NULL) { dev_err(&hlpe_pdev->dev, "%s: quit: pdata not allocated by i915!!\n", __func__); ret = -ENOMEM; - goto error_probe; + goto error_irq; } platform_set_drvdata(pdev, ctx); + /* setup interrupt handler */ + ret = request_irq(irq, display_pipe_interrupt_handler, + 0, + pdev->name, + NULL); + if (ret < 0) { + dev_err(&hlpe_pdev->dev, "request_irq failed\n"); + goto error_irq; + } + ret = hdmi_audio_probe(pdev, &ctx->had); if (ret < 0) goto error_probe; @@ -469,10 +469,10 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) return ret; error_probe: - kfree(ctx); - error_ctx: free_irq(irq, NULL); error_irq: + kfree(ctx); + error_ctx: iounmap(mmio_start); return ret; } -- cgit v1.2.3 From af3e5c9c5d370e262da97fb8a8310a9d578efa0d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Jan 2017 17:44:00 +0100 Subject: ALSA: x86: Drop unused mid_hdmi_audio_is_busy() The function is nowhere used. Kill it. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_lpe_audio.c | 23 ----------------------- sound/x86/intel_hdmi_lpe_audio.h | 1 - 2 files changed, 24 deletions(-) diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c index f5249b0a4ce4..452128a941cb 100644 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ b/sound/x86/intel_hdmi_lpe_audio.c @@ -83,29 +83,6 @@ static struct hdmi_lpe_audio_ctx *get_hdmi_context(void) return ctx; } -/* - * return whether HDMI audio device is busy. - */ -bool mid_hdmi_audio_is_busy(void *ddev) -{ - struct hdmi_lpe_audio_ctx *ctx; - int hdmi_audio_busy = 0; - struct hdmi_audio_event hdmi_audio_event; - - dev_dbg(&hlpe_pdev->dev, "%s: Enter", __func__); - - ctx = platform_get_drvdata(hlpe_pdev); - - if (hlpe_state == hdmi_connector_status_disconnected) { - /* HDMI is not connected, assuming audio device is idle. */ - return false; - } - - hdmi_audio_event.type = HAD_EVENT_QUERY_IS_AUDIO_BUSY; - hdmi_audio_busy = hdmi_audio_query(ctx->had, hdmi_audio_event); - return hdmi_audio_busy != 0; -} - void mid_hdmi_audio_signal_event(enum had_event_type event) { struct hdmi_lpe_audio_ctx *ctx; diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index 511bdc30dca1..a1c3aa0fbc57 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -642,7 +642,6 @@ struct hdmi_audio_event { int type; }; -bool mid_hdmi_audio_is_busy(void *dev); void mid_hdmi_audio_signal_event(enum had_event_type event); int mid_hdmi_audio_read(u32 reg, u32 *val); -- cgit v1.2.3 From bf8b24f8169096050795b552a778faaac349c73c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Jan 2017 18:09:01 +0100 Subject: ALSA: x86: Drop the global platform device reference Instead of referring to the global hlpe_pdev variable, pass the platform device object to each function properly. Accessing to the global object is really ugly and error-prone. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 15 ++-- sound/x86/intel_hdmi_lpe_audio.c | 146 ++++++++++++++++++--------------------- sound/x86/intel_hdmi_lpe_audio.h | 17 +++-- 3 files changed, 87 insertions(+), 91 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 571ec07a3611..ed9db2ebe9cf 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -172,11 +172,12 @@ int had_get_hwstate(struct snd_intelhad *intelhaddata) int had_get_caps(struct snd_intelhad *intelhaddata, enum had_caps_list query, void *caps) { + struct platform_device *pdev = to_platform_device(intelhaddata->dev); int retval; retval = had_get_hwstate(intelhaddata); if (!retval) - retval = mid_hdmi_audio_get_caps(query, caps); + retval = mid_hdmi_audio_get_caps(pdev, query, caps); return retval; } @@ -184,33 +185,36 @@ int had_get_caps(struct snd_intelhad *intelhaddata, int had_set_caps(struct snd_intelhad *intelhaddata, enum had_caps_list set_element, void *caps) { + struct platform_device *pdev = to_platform_device(intelhaddata->dev); int retval; retval = had_get_hwstate(intelhaddata); if (!retval) - retval = mid_hdmi_audio_set_caps(set_element, caps); + retval = mid_hdmi_audio_set_caps(pdev, set_element, caps); return retval; } int had_read_register(struct snd_intelhad *intelhaddata, u32 offset, u32 *data) { + struct platform_device *pdev = to_platform_device(intelhaddata->dev); int retval; retval = had_get_hwstate(intelhaddata); if (!retval) - retval = mid_hdmi_audio_read(offset, data); + retval = mid_hdmi_audio_read(pdev, offset, data); return retval; } int had_write_register(struct snd_intelhad *intelhaddata, u32 offset, u32 data) { + struct platform_device *pdev = to_platform_device(intelhaddata->dev); int retval; retval = had_get_hwstate(intelhaddata); if (!retval) - retval = mid_hdmi_audio_write(offset, data); + retval = mid_hdmi_audio_write(pdev, offset, data); return retval; } @@ -218,11 +222,12 @@ int had_write_register(struct snd_intelhad *intelhaddata, u32 offset, u32 data) int had_read_modify(struct snd_intelhad *intelhaddata, u32 offset, u32 data, u32 mask) { + struct platform_device *pdev = to_platform_device(intelhaddata->dev); int retval; retval = had_get_hwstate(intelhaddata); if (!retval) - retval = mid_hdmi_audio_rmw(offset, data, mask); + retval = mid_hdmi_audio_rmw(pdev, offset, data, mask); return retval; } diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c index 452128a941cb..09c21346071c 100644 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ b/sound/x86/intel_hdmi_lpe_audio.c @@ -37,11 +37,11 @@ #include "intel_hdmi_audio.h" /* globals*/ -static struct platform_device *hlpe_pdev; static int hlpe_state; static union otm_hdmi_eld_t hlpe_eld; struct hdmi_lpe_audio_ctx { + struct platform_device *pdev; int irq; void __iomem *mmio_start; struct snd_intelhad *had; @@ -74,22 +74,12 @@ static int hdmi_get_eld(void *eld) return 0; } - -static struct hdmi_lpe_audio_ctx *get_hdmi_context(void) +static void mid_hdmi_audio_signal_event(struct platform_device *pdev, + enum had_event_type event) { - struct hdmi_lpe_audio_ctx *ctx; - - ctx = platform_get_drvdata(hlpe_pdev); - return ctx; -} - -void mid_hdmi_audio_signal_event(enum had_event_type event) -{ - struct hdmi_lpe_audio_ctx *ctx; - - dev_dbg(&hlpe_pdev->dev, "%s: Enter\n", __func__); + struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); - ctx = platform_get_drvdata(hlpe_pdev); + dev_dbg(&pdev->dev, "%s: Enter\n", __func__); /* The handler is protected in the respective * event handlers to avoid races @@ -100,13 +90,11 @@ void mid_hdmi_audio_signal_event(enum had_event_type event) /* * used to write into display controller HDMI audio registers. */ -int mid_hdmi_audio_write(u32 reg, u32 val) +int mid_hdmi_audio_write(struct platform_device *pdev, u32 reg, u32 val) { - struct hdmi_lpe_audio_ctx *ctx; - - ctx = platform_get_drvdata(hlpe_pdev); + struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); - dev_dbg(&hlpe_pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, reg, val); + dev_dbg(&pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, reg, val); if (ctx->dp_output) { if (reg == AUD_CONFIG && (val & AUD_CONFIG_VALID_BIT)) @@ -121,13 +109,12 @@ int mid_hdmi_audio_write(u32 reg, u32 val) * used to get the register value read from * display controller HDMI audio registers. */ -int mid_hdmi_audio_read(u32 reg, u32 *val) +int mid_hdmi_audio_read(struct platform_device *pdev, u32 reg, u32 *val) { - struct hdmi_lpe_audio_ctx *ctx; + struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); - ctx = platform_get_drvdata(hlpe_pdev); *val = ioread32(ctx->mmio_start + ctx->had_config_offset + reg); - dev_dbg(&hlpe_pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, reg, *val); + dev_dbg(&pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, reg, *val); return 0; } @@ -135,13 +122,12 @@ int mid_hdmi_audio_read(u32 reg, u32 *val) * used to update the masked bits in display controller HDMI * audio registers. */ -int mid_hdmi_audio_rmw(u32 reg, u32 val, u32 mask) +int mid_hdmi_audio_rmw(struct platform_device *pdev, + u32 reg, u32 val, u32 mask) { - struct hdmi_lpe_audio_ctx *ctx; + struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); u32 val_tmp = 0; - ctx = platform_get_drvdata(hlpe_pdev); - val_tmp = ioread32(ctx->mmio_start + ctx->had_config_offset + reg); val_tmp &= ~mask; val_tmp |= (val & mask); @@ -152,7 +138,7 @@ int mid_hdmi_audio_rmw(u32 reg, u32 val, u32 mask) } iowrite32(val_tmp, ctx->mmio_start + ctx->had_config_offset + reg); - dev_dbg(&hlpe_pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, + dev_dbg(&pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, reg, val_tmp); return 0; @@ -162,15 +148,14 @@ int mid_hdmi_audio_rmw(u32 reg, u32 val, u32 mask) * used to return the HDMI audio capabilities. * e.g. resolution, frame rate. */ -int mid_hdmi_audio_get_caps(enum had_caps_list get_element, +int mid_hdmi_audio_get_caps(struct platform_device *pdev, + enum had_caps_list get_element, void *capabilities) { - struct hdmi_lpe_audio_ctx *ctx; + struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); int ret = 0; - ctx = get_hdmi_context(); - - dev_dbg(&hlpe_pdev->dev, "%s: Enter\n", __func__); + dev_dbg(&pdev->dev, "%s: Enter\n", __func__); switch (get_element) { case HAD_GET_ELD: @@ -179,18 +164,18 @@ int mid_hdmi_audio_get_caps(enum had_caps_list get_element, case HAD_GET_DISPLAY_RATE: /* ToDo: Verify if sampling freq logic is correct */ *(u32 *)capabilities = ctx->tmds_clock_speed; - dev_dbg(&hlpe_pdev->dev, "%s: tmds_clock_speed = 0x%x\n", + dev_dbg(&pdev->dev, "%s: tmds_clock_speed = 0x%x\n", __func__, ctx->tmds_clock_speed); break; case HAD_GET_LINK_RATE: /* ToDo: Verify if sampling freq logic is correct */ *(u32 *)capabilities = ctx->link_rate; - dev_dbg(&hlpe_pdev->dev, "%s: link rate = 0x%x\n", + dev_dbg(&pdev->dev, "%s: link rate = 0x%x\n", __func__, ctx->link_rate); break; case HAD_GET_DP_OUTPUT: *(u32 *)capabilities = ctx->dp_output; - dev_dbg(&hlpe_pdev->dev, "%s: dp_output = %d\n", + dev_dbg(&pdev->dev, "%s: dp_output = %d\n", __func__, ctx->dp_output); break; default: @@ -204,25 +189,25 @@ int mid_hdmi_audio_get_caps(enum had_caps_list get_element, * used to set the HDMI audio capabilities. * e.g. Audio INT. */ -int mid_hdmi_audio_set_caps(enum had_caps_list set_element, +int mid_hdmi_audio_set_caps(struct platform_device *pdev, + enum had_caps_list set_element, void *capabilties) { - struct hdmi_lpe_audio_ctx *ctx; - - ctx = platform_get_drvdata(hlpe_pdev); - - dev_dbg(&hlpe_pdev->dev, "%s: cap_id = 0x%x\n", __func__, set_element); + dev_dbg(&pdev->dev, "%s: cap_id = 0x%x\n", __func__, set_element); switch (set_element) { case HAD_SET_ENABLE_AUDIO_INT: { u32 status_reg; - mid_hdmi_audio_read(AUD_HDMI_STATUS_v2, &status_reg); + mid_hdmi_audio_read(pdev, AUD_HDMI_STATUS_v2, + &status_reg); status_reg |= HDMI_AUDIO_BUFFER_DONE | HDMI_AUDIO_UNDERRUN; - mid_hdmi_audio_write(AUD_HDMI_STATUS_v2, status_reg); - mid_hdmi_audio_read(AUD_HDMI_STATUS_v2, &status_reg); + mid_hdmi_audio_write(pdev, AUD_HDMI_STATUS_v2, + status_reg); + mid_hdmi_audio_read(pdev, AUD_HDMI_STATUS_v2, + &status_reg); } break; default: @@ -234,31 +219,34 @@ int mid_hdmi_audio_set_caps(enum had_caps_list set_element, static void _had_wq(struct work_struct *work) { - mid_hdmi_audio_signal_event(HAD_EVENT_HOT_PLUG); + struct hdmi_lpe_audio_ctx *ctx = + container_of(work, struct hdmi_lpe_audio_ctx, hdmi_audio_wq); + + mid_hdmi_audio_signal_event(ctx->pdev, HAD_EVENT_HOT_PLUG); } static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id) { + struct platform_device *pdev = dev_id; u32 audio_stat, audio_reg; - struct hdmi_lpe_audio_ctx *ctx; - dev_dbg(&hlpe_pdev->dev, "%s: Enter\n", __func__); + dev_dbg(&pdev->dev, "%s: Enter\n", __func__); - ctx = platform_get_drvdata(hlpe_pdev); + ctx = platform_get_drvdata(pdev); audio_reg = AUD_HDMI_STATUS_v2; - mid_hdmi_audio_read(audio_reg, &audio_stat); + mid_hdmi_audio_read(pdev, audio_reg, &audio_stat); if (audio_stat & HDMI_AUDIO_UNDERRUN) { - mid_hdmi_audio_write(audio_reg, HDMI_AUDIO_UNDERRUN); - mid_hdmi_audio_signal_event( + mid_hdmi_audio_write(pdev, audio_reg, HDMI_AUDIO_UNDERRUN); + mid_hdmi_audio_signal_event(pdev, HAD_EVENT_AUDIO_BUFFER_UNDERRUN); } if (audio_stat & HDMI_AUDIO_BUFFER_DONE) { - mid_hdmi_audio_write(audio_reg, HDMI_AUDIO_BUFFER_DONE); - mid_hdmi_audio_signal_event( + mid_hdmi_audio_write(pdev, audio_reg, HDMI_AUDIO_BUFFER_DONE); + mid_hdmi_audio_signal_event(pdev, HAD_EVENT_AUDIO_BUFFER_DONE); } @@ -280,7 +268,7 @@ static void notify_audio_lpe(struct platform_device *pdev) hlpe_state = hdmi_connector_status_disconnected; - mid_hdmi_audio_signal_event( + mid_hdmi_audio_signal_event(pdev, HAD_EVENT_HOT_UNPLUG); } else dev_dbg(&pdev->dev, "%s: Already Unplugged!\n", @@ -307,7 +295,7 @@ static void notify_audio_lpe(struct platform_device *pdev) hdmi_set_eld(eld->eld_data); - mid_hdmi_audio_signal_event(HAD_EVENT_HOT_PLUG); + mid_hdmi_audio_signal_event(pdev, HAD_EVENT_HOT_PLUG); hlpe_state = hdmi_connector_status_connected; @@ -318,7 +306,8 @@ static void notify_audio_lpe(struct platform_device *pdev) ctx->tmds_clock_speed = pdata->tmds_clock_speed; ctx->dp_output = pdata->dp_output; ctx->link_rate = pdata->link_rate; - mid_hdmi_audio_signal_event(HAD_EVENT_MODE_CHANGING); + mid_hdmi_audio_signal_event(pdev, + HAD_EVENT_MODE_CHANGING); } } } @@ -347,33 +336,32 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) {} }; - dev_dbg(&hlpe_pdev->dev, "Enter %s\n", __func__); + dev_dbg(&pdev->dev, "Enter %s\n", __func__); /*TBD:remove globals*/ - hlpe_pdev = pdev; hlpe_state = hdmi_connector_status_disconnected; /* get resources */ irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(&hlpe_pdev->dev, "Could not get irq resource\n"); + dev_err(&pdev->dev, "Could not get irq resource\n"); return -ENODEV; } res_mmio = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res_mmio) { - dev_err(&hlpe_pdev->dev, "Could not get IO_MEM resources\n"); + dev_err(&pdev->dev, "Could not get IO_MEM resources\n"); return -ENXIO; } - dev_dbg(&hlpe_pdev->dev, "%s: mmio_start = 0x%x, mmio_end = 0x%x\n", + dev_dbg(&pdev->dev, "%s: mmio_start = 0x%x, mmio_end = 0x%x\n", __func__, (unsigned int)res_mmio->start, (unsigned int)res_mmio->end); mmio_start = ioremap_nocache(res_mmio->start, (size_t)(resource_size(res_mmio))); if (!mmio_start) { - dev_err(&hlpe_pdev->dev, "Could not get ioremap\n"); + dev_err(&pdev->dev, "Could not get ioremap\n"); return -EACCES; } @@ -384,17 +372,18 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) goto error_ctx; } + ctx->pdev = pdev; ctx->irq = irq; - dev_dbg(&hlpe_pdev->dev, "hdmi lpe audio: irq num = %d\n", irq); + dev_dbg(&pdev->dev, "hdmi lpe audio: irq num = %d\n", irq); ctx->mmio_start = mmio_start; ctx->tmds_clock_speed = DIS_SAMPLE_RATE_148_5; INIT_WORK(&ctx->hdmi_audio_wq, _had_wq); if (pci_dev_present(cherryview_ids)) - dev_dbg(&hlpe_pdev->dev, "%s: Cherrytrail LPE - Detected\n", + dev_dbg(&pdev->dev, "%s: Cherrytrail LPE - Detected\n", __func__); else - dev_dbg(&hlpe_pdev->dev, "%s: Baytrail LPE - Assume\n", + dev_dbg(&pdev->dev, "%s: Baytrail LPE - Assume\n", __func__); /* assume pipe A as default */ @@ -403,7 +392,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) pdata = pdev->dev.platform_data; if (pdata == NULL) { - dev_err(&hlpe_pdev->dev, "%s: quit: pdata not allocated by i915!!\n", __func__); + dev_err(&pdev->dev, "%s: quit: pdata not allocated by i915!!\n", __func__); ret = -ENOMEM; goto error_irq; } @@ -411,12 +400,11 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ctx); /* setup interrupt handler */ - ret = request_irq(irq, display_pipe_interrupt_handler, - 0, - pdev->name, - NULL); + ret = request_irq(irq, display_pipe_interrupt_handler, 0, + pdev->name, pdev); + if (ret < 0) { - dev_err(&hlpe_pdev->dev, "request_irq failed\n"); + dev_err(&pdev->dev, "request_irq failed\n"); goto error_irq; } @@ -424,12 +412,12 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) if (ret < 0) goto error_probe; - dev_dbg(&hlpe_pdev->dev, "hdmi lpe audio: setting pin eld notify callback\n"); + dev_dbg(&pdev->dev, "hdmi lpe audio: setting pin eld notify callback\n"); /* The Audio driver is loading now and we need to notify * it if there is an HDMI device attached */ - dev_dbg(&hlpe_pdev->dev, "%s: Scheduling HDMI audio work queue\n", + dev_dbg(&pdev->dev, "%s: Scheduling HDMI audio work queue\n", __func__); schedule_work(&ctx->hdmi_audio_wq); @@ -437,7 +425,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) pdata->notify_audio_lpe = notify_audio_lpe; if (pdata->notify_pending) { - dev_dbg(&hlpe_pdev->dev, "%s: handle pending notification\n", __func__); + dev_dbg(&pdev->dev, "%s: handle pending notification\n", __func__); notify_audio_lpe(pdev); pdata->notify_pending = false; } @@ -446,7 +434,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) return ret; error_probe: - free_irq(irq, NULL); + free_irq(irq, pdev); error_irq: kfree(ctx); error_ctx: @@ -464,13 +452,13 @@ static int hdmi_lpe_audio_remove(struct platform_device *pdev) { struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); - dev_dbg(&hlpe_pdev->dev, "Enter %s\n", __func__); + dev_dbg(&pdev->dev, "Enter %s\n", __func__); hdmi_audio_remove(ctx->had); /* release resources */ iounmap(ctx->mmio_start); - free_irq(ctx->irq, NULL); + free_irq(ctx->irq, pdev); kfree(ctx); return 0; } diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index a1c3aa0fbc57..a9d51b7c5bae 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -31,6 +31,8 @@ #include #include +struct platform_device; + #define AUD_CONFIG_VALID_BIT (1<<9) #define AUD_CONFIG_DP_MODE (1<<15) #define AUD_CONFIG_BLOCK_BIT (1<<7) @@ -642,15 +644,16 @@ struct hdmi_audio_event { int type; }; -void mid_hdmi_audio_signal_event(enum had_event_type event); - -int mid_hdmi_audio_read(u32 reg, u32 *val); -int mid_hdmi_audio_write(u32 reg, u32 val); -int mid_hdmi_audio_rmw(u32 reg, u32 val, u32 mask); +int mid_hdmi_audio_read(struct platform_device *pdev, u32 reg, u32 *val); +int mid_hdmi_audio_write(struct platform_device *pdev, u32 reg, u32 val); +int mid_hdmi_audio_rmw(struct platform_device *pdev, + u32 reg, u32 val, u32 mask); -int mid_hdmi_audio_get_caps(enum had_caps_list get_element, +int mid_hdmi_audio_get_caps(struct platform_device *pdev, + enum had_caps_list get_element, void *capabilities); -int mid_hdmi_audio_set_caps(enum had_caps_list set_element, +int mid_hdmi_audio_set_caps(struct platform_device *pdev, + enum had_caps_list set_element, void *capabilties); #endif -- cgit v1.2.3 From 055610b002c1066b8ca1919b8d051d80c9e2d86e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Jan 2017 18:11:13 +0100 Subject: ALSA: x86: Drop global hlpe_state Now it's the turn to drop the global hlpe_state variable. It can be gracefully embedded in hdmi_lpe_audio_ctx struct. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_lpe_audio.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c index 09c21346071c..775a8b947213 100644 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ b/sound/x86/intel_hdmi_lpe_audio.c @@ -37,7 +37,6 @@ #include "intel_hdmi_audio.h" /* globals*/ -static int hlpe_state; static union otm_hdmi_eld_t hlpe_eld; struct hdmi_lpe_audio_ctx { @@ -51,6 +50,7 @@ struct hdmi_lpe_audio_ctx { unsigned int had_config_offset; int hdmi_audio_interrupt_mask; struct work_struct hdmi_audio_wq; + int state; /* connection state */ }; static void hdmi_set_eld(void *eld) @@ -263,10 +263,9 @@ static void notify_audio_lpe(struct platform_device *pdev) dev_dbg(&pdev->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG\n", __func__); - if (hlpe_state == hdmi_connector_status_connected) { + if (ctx->state == hdmi_connector_status_connected) { - hlpe_state = - hdmi_connector_status_disconnected; + ctx->state = hdmi_connector_status_disconnected; mid_hdmi_audio_signal_event(pdev, HAD_EVENT_HOT_UNPLUG); @@ -297,7 +296,7 @@ static void notify_audio_lpe(struct platform_device *pdev) mid_hdmi_audio_signal_event(pdev, HAD_EVENT_HOT_PLUG); - hlpe_state = hdmi_connector_status_connected; + ctx->state = hdmi_connector_status_connected; dev_dbg(&pdev->dev, "%s: HAD_NOTIFY_ELD : port = %d, tmds = %d\n", __func__, eld->port_id, pdata->tmds_clock_speed); @@ -338,9 +337,6 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "Enter %s\n", __func__); - /*TBD:remove globals*/ - hlpe_state = hdmi_connector_status_disconnected; - /* get resources */ irq = platform_get_irq(pdev, 0); if (irq < 0) { @@ -378,6 +374,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) ctx->mmio_start = mmio_start; ctx->tmds_clock_speed = DIS_SAMPLE_RATE_148_5; INIT_WORK(&ctx->hdmi_audio_wq, _had_wq); + ctx->state = hdmi_connector_status_disconnected; if (pci_dev_present(cherryview_ids)) dev_dbg(&pdev->dev, "%s: Cherrytrail LPE - Detected\n", @@ -468,9 +465,9 @@ static int hdmi_lpe_audio_suspend(struct platform_device *pdev, { struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); - dev_dbg(&pdev->dev, "%s: hlpe_state %d", __func__, hlpe_state); + dev_dbg(&pdev->dev, "%s: state %d", __func__, ctx->state); /* HDMI is not connected, assuming audio device is suspended already */ - if (hlpe_state != hdmi_connector_status_disconnected) + if (ctx->state != hdmi_connector_status_disconnected) hdmi_audio_suspend(ctx->had); return 0; } @@ -479,9 +476,9 @@ static int hdmi_lpe_audio_resume(struct platform_device *pdev) { struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); - dev_dbg(&pdev->dev, "%s: hlpe_state %d", __func__, hlpe_state); + dev_dbg(&pdev->dev, "%s: state %d", __func__, ctx->state); /* HDMI is not connected, there is no need to resume audio device */ - if (hlpe_state != hdmi_connector_status_disconnected) + if (ctx->state != hdmi_connector_status_disconnected) hdmi_audio_resume(ctx->had); return 0; } -- cgit v1.2.3 From 7f2e9ab5a2e1afcedd1e50650670c309e46822ac Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Jan 2017 18:15:40 +0100 Subject: ALSA: x86: Drop global ELD copy Similarly like the previous patch, drop the global variable to keep the ELD copy. It can be embedded in hdmi_lpe_audio_ctx as well. And this makes easier to code, it's just a memcpy(), after all. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_lpe_audio.c | 31 +++++-------------------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c index 775a8b947213..53864d372861 100644 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ b/sound/x86/intel_hdmi_lpe_audio.c @@ -36,9 +36,6 @@ #include "intel_hdmi_lpe_audio.h" #include "intel_hdmi_audio.h" -/* globals*/ -static union otm_hdmi_eld_t hlpe_eld; - struct hdmi_lpe_audio_ctx { struct platform_device *pdev; int irq; @@ -51,29 +48,9 @@ struct hdmi_lpe_audio_ctx { int hdmi_audio_interrupt_mask; struct work_struct hdmi_audio_wq; int state; /* connection state */ + union otm_hdmi_eld_t eld; /* ELD copy */ }; -static void hdmi_set_eld(void *eld) -{ - int size; - - BUILD_BUG_ON(sizeof(hlpe_eld) > HDMI_MAX_ELD_BYTES); - - size = sizeof(hlpe_eld); - memcpy((void *)&hlpe_eld, eld, size); -} - -static int hdmi_get_eld(void *eld) -{ - u8 *eld_data = (u8 *)&hlpe_eld; - - memcpy(eld, (void *)&hlpe_eld, sizeof(hlpe_eld)); - - print_hex_dump_bytes("eld: ", DUMP_PREFIX_NONE, eld_data, - sizeof(hlpe_eld)); - return 0; -} - static void mid_hdmi_audio_signal_event(struct platform_device *pdev, enum had_event_type event) { @@ -159,7 +136,9 @@ int mid_hdmi_audio_get_caps(struct platform_device *pdev, switch (get_element) { case HAD_GET_ELD: - ret = hdmi_get_eld(capabilities); + memcpy(capabilities, &ctx->eld, sizeof(ctx->eld)); + print_hex_dump_bytes("eld: ", DUMP_PREFIX_NONE, + (u8 *)&ctx->eld, sizeof(ctx->eld)); break; case HAD_GET_DISPLAY_RATE: /* ToDo: Verify if sampling freq logic is correct */ @@ -292,7 +271,7 @@ static void notify_audio_lpe(struct platform_device *pdev) break; } - hdmi_set_eld(eld->eld_data); + memcpy(&ctx->eld, eld->eld_data, sizeof(ctx->eld)); mid_hdmi_audio_signal_event(pdev, HAD_EVENT_HOT_PLUG); -- cgit v1.2.3 From 6ddb3ab66f94109c524859ba4dd9d43772893676 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Jan 2017 18:17:44 +0100 Subject: ALSA: x86: Move the global underrun_count to struct snd_intelhad The last one is in intel_hdmi_audio.c, underrun_count: this can be embedded in snd_intelhad object. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 15 +++++++-------- sound/x86/intel_hdmi_audio.h | 2 ++ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index ed9db2ebe9cf..e08691110a48 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -40,7 +40,6 @@ /*standard module options for ALSA. This module supports only one card*/ static int hdmi_card_index = SNDRV_DEFAULT_IDX1; static char *hdmi_card_id = SNDRV_DEFAULT_STR1; -static int underrun_count; module_param_named(index, hdmi_card_index, int, 0444); MODULE_PARM_DESC(index, @@ -969,7 +968,7 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) intelhaddata = snd_pcm_substream_chip(substream); had_stream = intelhaddata->private_data; runtime = substream->runtime; - underrun_count = 0; + intelhaddata->underrun_count = 0; pm_runtime_get(intelhaddata->dev); @@ -1376,19 +1375,19 @@ static snd_pcm_uframes_t snd_intelhad_pcm_pointer( AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH), &t); if ((t == 0) || (t == ((u32)-1L))) { - underrun_count++; + intelhaddata->underrun_count++; pr_debug("discovered buffer done for buf %d, count = %d\n", - buf_id, underrun_count); + buf_id, intelhaddata->underrun_count); - if (underrun_count > (HAD_MIN_PERIODS/2)) { + if (intelhaddata->underrun_count > (HAD_MIN_PERIODS/2)) { pr_debug("assume audio_codec_reset, underrun = %d - do xrun\n", - underrun_count); - underrun_count = 0; + intelhaddata->underrun_count); + intelhaddata->underrun_count = 0; return SNDRV_PCM_POS_XRUN; } } else { /* Reset Counter */ - underrun_count = 0; + intelhaddata->underrun_count = 0; } t = intelhaddata->buf_info[buf_id].buf_size - t; diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 110d1d083000..da0a927d37fe 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -119,6 +119,7 @@ struct had_pvt_data { * @chmap: holds channel map info * @audio_reg_base: hdmi audio register base offset * @hw_silence: flag indicates SoC support for HW silence/Keep alive + * @underrun_count: PCM stream underrun counter */ struct snd_intelhad { struct snd_card *card; @@ -142,6 +143,7 @@ struct snd_intelhad { unsigned int *audio_reg_base; unsigned int audio_cfg_offset; bool hw_silence; + int underrun_count; }; int had_event_handler(enum had_event_type event_type, void *data); -- cgit v1.2.3 From 0e18060f99a42c20f87d64eb30e5f424509643ae Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 07:53:56 +0100 Subject: ALSA: x86: Drop unused hw_silence field It's nowhere used. Let's drop it. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 1 - sound/x86/intel_hdmi_audio.h | 2 -- 2 files changed, 3 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index e08691110a48..efc56544af17 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1696,7 +1696,6 @@ int hdmi_audio_probe(struct platform_device *devptr, pm_runtime_set_active(intelhaddata->dev); pm_runtime_enable(intelhaddata->dev); - intelhaddata->hw_silence = 1; *had_ret = intelhaddata; return 0; diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index da0a927d37fe..32a2fb766e47 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -118,7 +118,6 @@ struct had_pvt_data { * @kctl: holds kctl ptrs used for channel map * @chmap: holds channel map info * @audio_reg_base: hdmi audio register base offset - * @hw_silence: flag indicates SoC support for HW silence/Keep alive * @underrun_count: PCM stream underrun counter */ struct snd_intelhad { @@ -142,7 +141,6 @@ struct snd_intelhad { struct snd_pcm_chmap *chmap; unsigned int *audio_reg_base; unsigned int audio_cfg_offset; - bool hw_silence; int underrun_count; }; -- cgit v1.2.3 From dae15a9d960e513d5b60c00c306cddd87465f1c4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 08:02:16 +0100 Subject: ALSA: x86: Move dma_mask debug print into intel_hdmi_lpe_audio.c It belongs to the right place. And, remove a few sanity checks (e.g. NULL card) and debug prints as well. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 11 ----------- sound/x86/intel_hdmi_lpe_audio.c | 1 + 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index efc56544af17..49cb95072a88 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1600,8 +1600,6 @@ int hdmi_audio_probe(struct platform_device *devptr, pr_debug("Enter %s\n", __func__); - pr_debug("hdmi_audio_probe dma_mask: %p\n", devptr->dev.dma_mask); - /* allocate memory for saving internal context and working */ intelhaddata = kzalloc(sizeof(*intelhaddata), GFP_KERNEL); if (!intelhaddata) @@ -1653,15 +1651,6 @@ int hdmi_audio_probe(struct platform_device *devptr, retval = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, NULL, HAD_MAX_BUFFER, HAD_MAX_BUFFER); - - if (card->dev == NULL) - pr_debug("card->dev is NULL!!!!! Should not be this case\n"); - else if (card->dev->dma_mask == NULL) - pr_debug("hdmi_audio_probe dma_mask is NULL!!!!!\n"); - else - pr_debug("hdmi_audio_probe dma_mask is : %p\n", - card->dev->dma_mask); - if (retval) goto err; diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c index 53864d372861..6f823d4278bb 100644 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ b/sound/x86/intel_hdmi_lpe_audio.c @@ -315,6 +315,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) }; dev_dbg(&pdev->dev, "Enter %s\n", __func__); + dev_dbg(&pdev->dev, "dma_mask: %p\n", pdev->dev.dma_mask); /* get resources */ irq = platform_get_irq(pdev, 0); -- cgit v1.2.3 From 5647aec26640ffdf099d51b3403eaeac10d74147 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 08:14:34 +0100 Subject: ALSA: x86: Embed snd_intelhad into snd_card Instead of allocating snd_intelhad struct, use the card's private_data and embed it. It simplifies the code a lot. While we're at it, embed had_stream into snd_intelhad struct instead of individually allocating, and rename had_pvt_data to a bit more specific name, had_stream_data. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 77 +++++++---------------------------------- sound/x86/intel_hdmi_audio.h | 4 +-- sound/x86/intel_hdmi_audio_if.c | 32 ++++++++--------- 3 files changed, 31 insertions(+), 82 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 49cb95072a88..dfc4452afee1 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -961,12 +961,12 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) struct snd_intelhad *intelhaddata; struct snd_pcm_runtime *runtime; struct had_stream_pvt *stream; - struct had_pvt_data *had_stream; + struct had_stream_data *had_stream; int retval; pr_debug("snd_intelhad_open called\n"); intelhaddata = snd_pcm_substream_chip(substream); - had_stream = intelhaddata->private_data; + had_stream = &intelhaddata->stream_data; runtime = substream->runtime; intelhaddata->underrun_count = 0; @@ -1180,13 +1180,13 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, unsigned long flag_irq; struct snd_intelhad *intelhaddata; struct had_stream_pvt *stream; - struct had_pvt_data *had_stream; + struct had_stream_data *had_stream; pr_debug("snd_intelhad_pcm_trigger called\n"); intelhaddata = snd_pcm_substream_chip(substream); stream = substream->runtime->private_data; - had_stream = intelhaddata->private_data; + had_stream = &intelhaddata->stream_data; switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -1262,13 +1262,13 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) u32 link_rate = 0; struct snd_intelhad *intelhaddata; struct snd_pcm_runtime *runtime; - struct had_pvt_data *had_stream; + struct had_stream_data *had_stream; pr_debug("snd_intelhad_pcm_prepare called\n"); intelhaddata = snd_pcm_substream_chip(substream); runtime = substream->runtime; - had_stream = intelhaddata->private_data; + had_stream = &intelhaddata->stream_data; if (had_get_hwstate(intelhaddata)) { pr_err("%s: HDMI cable plugged-out\n", __func__); @@ -1479,31 +1479,6 @@ struct snd_pcm_ops snd_intelhad_playback_ops = { .mmap = snd_intelhad_pcm_mmap, }; -/** - * snd_intelhad_create - to crete alsa card instance - * - * @intelhaddata: pointer to internal context - * @card: pointer to card - * - * This function is called when the hdmi cable is plugged in - */ -static int snd_intelhad_create( - struct snd_intelhad *intelhaddata, - struct snd_card *card) -{ - int retval; - static struct snd_device_ops ops = { - }; - - pr_debug("snd_intelhad_create called\n"); - - if (!intelhaddata) - return -EINVAL; - - /* ALSA api to register the device */ - retval = snd_device_new(card, SNDRV_DEV_LOWLEVEL, intelhaddata, &ops); - return retval; -} /** * snd_intelhad_pcm_free - to free the memory allocated * @@ -1596,36 +1571,24 @@ int hdmi_audio_probe(struct platform_device *devptr, struct snd_pcm *pcm; struct snd_card *card; struct snd_intelhad *intelhaddata; - struct had_pvt_data *had_stream; pr_debug("Enter %s\n", __func__); - /* allocate memory for saving internal context and working */ - intelhaddata = kzalloc(sizeof(*intelhaddata), GFP_KERNEL); - if (!intelhaddata) - return -ENOMEM; - - had_stream = kzalloc(sizeof(*had_stream), GFP_KERNEL); - if (!had_stream) { - retval = -ENOMEM; - goto free_haddata; - } + /* create a card instance with ALSA framework */ + retval = snd_card_new(&devptr->dev, hdmi_card_index, hdmi_card_id, + THIS_MODULE, sizeof(*intelhaddata), &card); + if (retval) + return retval; + intelhaddata = card->private_data; spin_lock_init(&intelhaddata->had_spinlock); intelhaddata->drv_status = HAD_DRV_DISCONNECTED; pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", __func__, __LINE__); - /* create a card instance with ALSA framework */ - retval = snd_card_new(&devptr->dev, hdmi_card_index, hdmi_card_id, - THIS_MODULE, 0, &card); - - if (retval) - goto free_hadstream; intelhaddata->card = card; intelhaddata->card_id = hdmi_card_id; intelhaddata->card_index = card->number; - intelhaddata->private_data = had_stream; intelhaddata->flag_underrun = 0; intelhaddata->aes_bits = SNDRV_PCM_DEFAULT_CON_SPDIF; strncpy(card->driver, INTEL_HAD, strlen(INTEL_HAD)); @@ -1654,12 +1617,6 @@ int hdmi_audio_probe(struct platform_device *devptr, if (retval) goto err; - /* internal function call to register device with ALSA */ - retval = snd_intelhad_create(intelhaddata, card); - if (retval) - goto err; - - card->private_data = &intelhaddata; retval = snd_card_register(card); if (retval) goto err; @@ -1688,15 +1645,9 @@ int hdmi_audio_probe(struct platform_device *devptr, *had_ret = intelhaddata; return 0; + err: snd_card_free(card); -free_hadstream: - kfree(had_stream); - pm_runtime_disable(intelhaddata->dev); - intelhaddata->dev = NULL; -free_haddata: - kfree(intelhaddata); - intelhaddata = NULL; pr_err("Error returned from %s api %#x\n", __func__, retval); return retval; } @@ -1724,8 +1675,6 @@ int hdmi_audio_remove(struct snd_intelhad *intelhaddata) had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO, NULL); } snd_card_free(intelhaddata->card); - kfree(intelhaddata->private_data); - kfree(intelhaddata); return 0; } diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 32a2fb766e47..98a004499f3c 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -95,7 +95,7 @@ struct had_stream_pvt { ssize_t dbg_cum_bytes; }; -struct had_pvt_data { +struct had_stream_data { enum had_status_stream stream_type; }; @@ -133,7 +133,7 @@ struct snd_intelhad { int valid_buf_cnt; unsigned int aes_bits; int flag_underrun; - struct had_pvt_data *private_data; + struct had_stream_data stream_data; spinlock_t had_spinlock; enum intel_had_aud_buf_type buff_done; struct device *dev; diff --git a/sound/x86/intel_hdmi_audio_if.c b/sound/x86/intel_hdmi_audio_if.c index 8e3a0943332b..caf982e55ec6 100644 --- a/sound/x86/intel_hdmi_audio_if.c +++ b/sound/x86/intel_hdmi_audio_if.c @@ -45,13 +45,13 @@ int hdmi_audio_query(void *haddata, struct hdmi_audio_event event) { struct snd_pcm_substream *substream = NULL; - struct had_pvt_data *had_stream; + struct had_stream_data *had_stream; unsigned long flag_irqs; struct snd_intelhad *intelhaddata = (struct snd_intelhad *)haddata; if (intelhaddata->stream_info.had_substream) substream = intelhaddata->stream_info.had_substream; - had_stream = intelhaddata->private_data; + had_stream = &intelhaddata->stream_data; switch (event.type) { case HAD_EVENT_QUERY_IS_AUDIO_BUSY: spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); @@ -98,14 +98,14 @@ int hdmi_audio_query(void *haddata, struct hdmi_audio_event event) int hdmi_audio_suspend(void *haddata) { int caps, retval = 0; - struct had_pvt_data *had_stream; + struct had_stream_data *had_stream; unsigned long flag_irqs; struct snd_pcm_substream *substream; struct snd_intelhad *intelhaddata = (struct snd_intelhad *)haddata; pr_debug("Enter:%s\n", __func__); - had_stream = intelhaddata->private_data; + had_stream = &intelhaddata->stream_data; substream = intelhaddata->stream_info.had_substream; if (intelhaddata->dev->power.runtime_status != RPM_SUSPENDED) { @@ -199,10 +199,10 @@ static inline int had_chk_intrmiss(struct snd_intelhad *intelhaddata, int i, intr_count = 0; enum intel_had_aud_buf_type buff_done; u32 buf_size, buf_addr; - struct had_pvt_data *had_stream; + struct had_stream_data *had_stream; unsigned long flag_irqs; - had_stream = intelhaddata->private_data; + had_stream = &intelhaddata->stream_data; buff_done = buf_id; @@ -244,12 +244,12 @@ int had_process_buffer_done(struct snd_intelhad *intelhaddata) enum intel_had_aud_buf_type buff_done; struct pcm_stream_info *stream; u32 buf_size; - struct had_pvt_data *had_stream; + struct had_stream_data *had_stream; int intr_count; enum had_status_stream stream_type; unsigned long flag_irqs; - had_stream = intelhaddata->private_data; + had_stream = &intelhaddata->stream_data; stream = &intelhaddata->stream_info; intr_count = 1; @@ -331,12 +331,12 @@ int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) { enum intel_had_aud_buf_type buf_id; struct pcm_stream_info *stream; - struct had_pvt_data *had_stream; + struct had_stream_data *had_stream; enum had_status_stream stream_type; unsigned long flag_irqs; int drv_status; - had_stream = intelhaddata->private_data; + had_stream = &intelhaddata->stream_data; stream = &intelhaddata->stream_info; spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); @@ -372,13 +372,13 @@ int had_process_hot_plug(struct snd_intelhad *intelhaddata) { enum intel_had_aud_buf_type buf_id; struct snd_pcm_substream *substream; - struct had_pvt_data *had_stream; + struct had_stream_data *had_stream; unsigned long flag_irqs; pr_debug("Enter:%s\n", __func__); substream = intelhaddata->stream_info.had_substream; - had_stream = intelhaddata->private_data; + had_stream = &intelhaddata->stream_data; spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); if (intelhaddata->drv_status == HAD_DRV_CONNECTED) { @@ -413,12 +413,12 @@ int had_process_hot_unplug(struct snd_intelhad *intelhaddata) { int caps, retval = 0; enum intel_had_aud_buf_type buf_id; - struct had_pvt_data *had_stream; + struct had_stream_data *had_stream; unsigned long flag_irqs; pr_debug("Enter:%s\n", __func__); - had_stream = intelhaddata->private_data; + had_stream = &intelhaddata->stream_data; buf_id = intelhaddata->curr_buf; spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); @@ -476,11 +476,11 @@ int had_event_handler(enum had_event_type event_type, void *data) struct snd_intelhad *intelhaddata = data; enum intel_had_aud_buf_type buf_id; struct snd_pcm_substream *substream; - struct had_pvt_data *had_stream; + struct had_stream_data *had_stream; unsigned long flag_irqs; buf_id = intelhaddata->curr_buf; - had_stream = intelhaddata->private_data; + had_stream = &intelhaddata->stream_data; /* Switching to a function can drop atomicity even in INTR context. * Thus, a big lock is acquired to maintain atomicity. -- cgit v1.2.3 From c415022e487fbba19926b56b981c5474474c0465 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 08:42:50 +0100 Subject: ALSA: x86: Drop superfluous CHT PCI ID check Since the config base offset is now set per pipe id, we don't have to check Cherry Trail PCI IDs any longer. Currently it's used only for debug prints. Let's drop it. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_lpe_audio.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c index 6f823d4278bb..b84f7d92ed24 100644 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ b/sound/x86/intel_hdmi_lpe_audio.c @@ -306,13 +306,6 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) void __iomem *mmio_start; int ret = 0; unsigned long flag_irq; - static const struct pci_device_id cherryview_ids[] = { - {PCI_DEVICE(0x8086, 0x22b0)}, - {PCI_DEVICE(0x8086, 0x22b1)}, - {PCI_DEVICE(0x8086, 0x22b2)}, - {PCI_DEVICE(0x8086, 0x22b3)}, - {} - }; dev_dbg(&pdev->dev, "Enter %s\n", __func__); dev_dbg(&pdev->dev, "dma_mask: %p\n", pdev->dev.dma_mask); @@ -356,13 +349,6 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) INIT_WORK(&ctx->hdmi_audio_wq, _had_wq); ctx->state = hdmi_connector_status_disconnected; - if (pci_dev_present(cherryview_ids)) - dev_dbg(&pdev->dev, "%s: Cherrytrail LPE - Detected\n", - __func__); - else - dev_dbg(&pdev->dev, "%s: Baytrail LPE - Assume\n", - __func__); - /* assume pipe A as default */ ctx->had_config_offset = AUDIO_HDMI_CONFIG_A; -- cgit v1.2.3 From 301cf8a9559bb372ab64da3781d3d93d1ce38213 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 08:44:23 +0100 Subject: ALSA: x86: Check platform_data earlier Just a minor optimization; check the presence of platform_data earlier in the probe function before actually starting allocation, which makes the error path easier. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_lpe_audio.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c index b84f7d92ed24..8789f55724da 100644 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ b/sound/x86/intel_hdmi_lpe_audio.c @@ -310,6 +310,12 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "Enter %s\n", __func__); dev_dbg(&pdev->dev, "dma_mask: %p\n", pdev->dev.dma_mask); + pdata = pdev->dev.platform_data; + if (!pdata) { + dev_err(&pdev->dev, "%s: quit: pdata not allocated by i915!!\n", __func__); + return -EINVAL; + } + /* get resources */ irq = platform_get_irq(pdev, 0); if (irq < 0) { @@ -352,14 +358,6 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) /* assume pipe A as default */ ctx->had_config_offset = AUDIO_HDMI_CONFIG_A; - pdata = pdev->dev.platform_data; - - if (pdata == NULL) { - dev_err(&pdev->dev, "%s: quit: pdata not allocated by i915!!\n", __func__); - ret = -ENOMEM; - goto error_irq; - } - platform_set_drvdata(pdev, ctx); /* setup interrupt handler */ -- cgit v1.2.3 From 36ec0d99bbd7bb392bf64059cbda1818ee2be5a2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 08:47:05 +0100 Subject: ALSA: x86: Call snd_card_register() at the end The card registration should be done at the last stage of the probe procedure. Otherwise user-space may access to the device before the whole initialization is done. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index dfc4452afee1..82f42a6c363c 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1586,6 +1586,7 @@ int hdmi_audio_probe(struct platform_device *devptr, pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", __func__, __LINE__); + intelhaddata->dev = &devptr->dev; intelhaddata->card = card; intelhaddata->card_id = hdmi_card_id; intelhaddata->card_index = card->number; @@ -1617,10 +1618,6 @@ int hdmi_audio_probe(struct platform_device *devptr, if (retval) goto err; - retval = snd_card_register(card); - if (retval) - goto err; - /* IEC958 controls */ retval = snd_ctl_add(card, snd_ctl_new1(&had_control_iec958_mask, intelhaddata)); @@ -1638,7 +1635,10 @@ int hdmi_audio_probe(struct platform_device *devptr, if (retval < 0) goto err; - intelhaddata->dev = &devptr->dev; + retval = snd_card_register(card); + if (retval) + goto err; + pm_runtime_set_active(intelhaddata->dev); pm_runtime_enable(intelhaddata->dev); -- cgit v1.2.3 From eeb756c5bf7566fd79312798a32f59e594688b79 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 11:06:34 +0100 Subject: ALSA: x86: Drop unused hdmi_audio_query() It's used nowhere. Kill it. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.h | 1 - sound/x86/intel_hdmi_audio_if.c | 54 ----------------------------------------- 2 files changed, 55 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 98a004499f3c..8415f93e40dc 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -146,7 +146,6 @@ struct snd_intelhad { int had_event_handler(enum had_event_type event_type, void *data); -int hdmi_audio_query(void *drv_data, struct hdmi_audio_event event); int hdmi_audio_suspend(void *drv_data); int hdmi_audio_resume(void *drv_data); int hdmi_audio_mode_change(struct snd_pcm_substream *substream); diff --git a/sound/x86/intel_hdmi_audio_if.c b/sound/x86/intel_hdmi_audio_if.c index caf982e55ec6..57acefaf930e 100644 --- a/sound/x86/intel_hdmi_audio_if.c +++ b/sound/x86/intel_hdmi_audio_if.c @@ -33,60 +33,6 @@ #include "intel_hdmi_audio.h" #include "intel_hdmi_lpe_audio.h" -/** - * hdmi_audio_query - hdmi audio query function - * - *@haddata: pointer to HAD private data - *@event: audio event for which this method is invoked - * - * This function is called by client driver to query the - * hdmi audio. - */ -int hdmi_audio_query(void *haddata, struct hdmi_audio_event event) -{ - struct snd_pcm_substream *substream = NULL; - struct had_stream_data *had_stream; - unsigned long flag_irqs; - struct snd_intelhad *intelhaddata = (struct snd_intelhad *)haddata; - - if (intelhaddata->stream_info.had_substream) - substream = intelhaddata->stream_info.had_substream; - had_stream = &intelhaddata->stream_data; - switch (event.type) { - case HAD_EVENT_QUERY_IS_AUDIO_BUSY: - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); - - if ((had_stream->stream_type == HAD_RUNNING_STREAM) || - substream) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, - flag_irqs); - pr_debug("Audio stream active\n"); - return -EBUSY; - } - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - break; - - case HAD_EVENT_QUERY_IS_AUDIO_SUSPENDED: - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); - if (intelhaddata->drv_status == HAD_DRV_SUSPENDED) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, - flag_irqs); - pr_debug("Audio is suspended\n"); - return 1; - } - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - break; - - default: - pr_debug("error un-handled event !!\n"); - return -EINVAL; - break; - - } - - return 0; -} - /** * hdmi_audio_suspend - power management suspend function * -- cgit v1.2.3 From da8648097497505d05d8cff6892351f99c029791 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 13:52:22 +0100 Subject: ALSA: x86: Flatten two abstraction layers This is the final stage for a big clean-up series. Here we flatten the two layers into one. Formerly, the implementation was split to HDMI "shell" that talks with the platform device, and HDMI audio part that communicates via caps and other event handlers. All these would be good if there were multiple instantiations or if there were data protection. But neither are true in our case. That said, it'll be easier to have a flat driver structure in the end. In this patch, the former struct hdmi_lpe_audio_ctx is forged into the existing struct snd_intelhad. The latter has already a few members that are basically the copy from the former. Only a few new members for the lowlevel I/O are added by this change. Then, the had_get_caps() and had_set_caps() are simply replaced with the direct calls to copy the data in the struct fields. Also, the had_event_handler() calls are replaced with the direct call for each event as well. Signed-off-by: Takashi Iwai --- sound/x86/Makefile | 3 +- sound/x86/intel_hdmi_audio.c | 476 ++++++++++++++++++++++++++------------- sound/x86/intel_hdmi_audio.h | 37 +-- sound/x86/intel_hdmi_audio_if.c | 128 ++--------- sound/x86/intel_hdmi_lpe_audio.c | 462 ------------------------------------- sound/x86/intel_hdmi_lpe_audio.h | 23 +- 6 files changed, 358 insertions(+), 771 deletions(-) delete mode 100644 sound/x86/intel_hdmi_lpe_audio.c diff --git a/sound/x86/Makefile b/sound/x86/Makefile index 85ea22a2cf28..3c0bf63333e6 100644 --- a/sound/x86/Makefile +++ b/sound/x86/Makefile @@ -1,6 +1,5 @@ snd-hdmi-lpe-audio-objs += \ intel_hdmi_audio.o \ - intel_hdmi_audio_if.o \ - intel_hdmi_lpe_audio.o + intel_hdmi_audio_if.o obj-$(CONFIG_HDMI_LPE_AUDIO) += snd-hdmi-lpe-audio.o diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 82f42a6c363c..1594f826cf31 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,7 @@ #include #include #include +#include #include "intel_hdmi_audio.h" /*standard module options for ALSA. This module supports only one card*/ @@ -168,72 +170,75 @@ int had_get_hwstate(struct snd_intelhad *intelhaddata) return 0; } -int had_get_caps(struct snd_intelhad *intelhaddata, - enum had_caps_list query, void *caps) +static inline void +mid_hdmi_audio_read(struct snd_intelhad *ctx, u32 reg, u32 *val) { - struct platform_device *pdev = to_platform_device(intelhaddata->dev); - int retval; - - retval = had_get_hwstate(intelhaddata); - if (!retval) - retval = mid_hdmi_audio_get_caps(pdev, query, caps); - - return retval; + *val = ioread32(ctx->mmio_start + ctx->had_config_offset + reg); } -int had_set_caps(struct snd_intelhad *intelhaddata, - enum had_caps_list set_element, void *caps) +static inline void +mid_hdmi_audio_write(struct snd_intelhad *ctx, u32 reg, u32 val) { - struct platform_device *pdev = to_platform_device(intelhaddata->dev); - int retval; - - retval = had_get_hwstate(intelhaddata); - if (!retval) - retval = mid_hdmi_audio_set_caps(pdev, set_element, caps); - - return retval; + iowrite32(val, ctx->mmio_start + ctx->had_config_offset + reg); } int had_read_register(struct snd_intelhad *intelhaddata, u32 offset, u32 *data) { - struct platform_device *pdev = to_platform_device(intelhaddata->dev); int retval; retval = had_get_hwstate(intelhaddata); - if (!retval) - retval = mid_hdmi_audio_read(pdev, offset, data); + if (retval) + return retval; - return retval; + mid_hdmi_audio_read(intelhaddata, offset, data); + return 0; +} + +static void fixup_dp_config(struct snd_intelhad *intelhaddata, + u32 offset, u32 *data) +{ + if (intelhaddata->dp_output) { + if (offset == AUD_CONFIG && (*data & AUD_CONFIG_VALID_BIT)) + *data |= AUD_CONFIG_DP_MODE | AUD_CONFIG_BLOCK_BIT; + } } int had_write_register(struct snd_intelhad *intelhaddata, u32 offset, u32 data) { - struct platform_device *pdev = to_platform_device(intelhaddata->dev); int retval; retval = had_get_hwstate(intelhaddata); - if (!retval) - retval = mid_hdmi_audio_write(pdev, offset, data); + if (retval) + return retval; - return retval; + fixup_dp_config(intelhaddata, offset, &data); + mid_hdmi_audio_write(intelhaddata, offset, data); + return 0; } int had_read_modify(struct snd_intelhad *intelhaddata, u32 offset, u32 data, u32 mask) { - struct platform_device *pdev = to_platform_device(intelhaddata->dev); + u32 val_tmp; int retval; retval = had_get_hwstate(intelhaddata); - if (!retval) - retval = mid_hdmi_audio_rmw(pdev, offset, data, mask); + if (retval) + return retval; - return retval; + mid_hdmi_audio_read(intelhaddata, offset, &val_tmp); + val_tmp &= ~mask; + val_tmp |= (data & mask); + + fixup_dp_config(intelhaddata, offset, &val_tmp); + mid_hdmi_audio_write(intelhaddata, offset, val_tmp); + return 0; } -/** - * function to read-modify - * AUD_CONFIG register on VLV2.The had_read_modify() function should not - * directly be used on VLV2 for updating AUD_CONFIG register. + +/* + * function to read-modify AUD_CONFIG register on VLV2. + * The had_read_modify() function should not directly be used on VLV2 for + * updating AUD_CONFIG register. * This is because: * Bit6 of AUD_CONFIG register is writeonly due to a silicon bug on VLV2 * HDMI IP. As a result a read-modify of AUD_CONFIG regiter will always @@ -249,10 +254,10 @@ int had_read_modify(struct snd_intelhad *intelhaddata, u32 offset, * @mask : mask * */ -static int had_read_modify_aud_config_v2(struct snd_pcm_substream *substream, +static int had_read_modify_aud_config_v2(struct snd_intelhad *intelhaddata, u32 data, u32 mask) { - struct snd_intelhad *intelhaddata = snd_pcm_substream_chip(substream); + struct snd_pcm_substream *substream; union aud_cfg cfg_val = {.cfg_regval = 0}; u8 channels; @@ -260,7 +265,8 @@ static int had_read_modify_aud_config_v2(struct snd_pcm_substream *substream, * If substream is NULL, there is no active stream. * In this case just set channels to 2 */ - if (substream) + substream = intelhaddata->stream_info.had_substream; + if (substream && substream->runtime) channels = substream->runtime->channels; else channels = 2; @@ -274,9 +280,23 @@ static int had_read_modify_aud_config_v2(struct snd_pcm_substream *substream, return had_read_modify(intelhaddata, AUD_CONFIG, data, mask); } -void snd_intelhad_enable_audio(struct snd_pcm_substream *substream, u8 enable) +void snd_intelhad_enable_audio_int(struct snd_intelhad *ctx, bool enable) +{ + u32 status_reg; + + if (enable) { + mid_hdmi_audio_read(ctx, AUD_HDMI_STATUS_v2, &status_reg); + status_reg |= HDMI_AUDIO_BUFFER_DONE | HDMI_AUDIO_UNDERRUN; + mid_hdmi_audio_write(ctx, AUD_HDMI_STATUS_v2, status_reg); + mid_hdmi_audio_read(ctx, AUD_HDMI_STATUS_v2, &status_reg); + } +} + +void snd_intelhad_enable_audio(struct snd_intelhad *intelhaddata, + bool enable) { - had_read_modify_aud_config_v2(substream, enable, BIT(0)); + had_read_modify_aud_config_v2(intelhaddata, enable ? BIT(0) : 0, + BIT(0)); } static void snd_intelhad_reset_audio(struct snd_intelhad *intelhaddata, @@ -437,7 +457,7 @@ static int snd_intelhad_channel_allocation(struct snd_intelhad *intelhaddata, */ for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) { - if (intelhaddata->eeld.speaker_allocation_block & (1 << i)) + if (intelhaddata->eld.speaker_allocation_block & (1 << i)) spk_mask |= eld_speaker_allocation_bits[i]; } @@ -482,11 +502,8 @@ void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata) return; } - had_get_caps(intelhaddata, HAD_GET_ELD, &intelhaddata->eeld); - had_get_caps(intelhaddata, HAD_GET_DP_OUTPUT, &intelhaddata->dp_output); - - pr_debug("eeld.speaker_allocation_block = %x\n", - intelhaddata->eeld.speaker_allocation_block); + pr_debug("eld.speaker_allocation_block = %x\n", + intelhaddata->eld.speaker_allocation_block); /* WA: Fix the max channel supported to 8 */ @@ -497,14 +514,14 @@ void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata) */ /* if 0x2F < eld < 0x4F fall back to 0x2f, else fall back to 0x4F */ - eld_high = intelhaddata->eeld.speaker_allocation_block & eld_high_mask; + eld_high = intelhaddata->eld.speaker_allocation_block & eld_high_mask; if ((eld_high & (eld_high-1)) && (eld_high > 0x1F)) { /* eld_high & (eld_high-1): if more than 1 bit set */ /* 0x1F: 7 channels */ for (i = 1; i < 4; i++) { high_msb = eld_high & (0x80 >> i); if (high_msb) { - intelhaddata->eeld.speaker_allocation_block &= + intelhaddata->eld.speaker_allocation_block &= high_msb | 0xF; break; } @@ -512,7 +529,7 @@ void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata) } for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) { - if (intelhaddata->eeld.speaker_allocation_block & (1 << i)) + if (intelhaddata->eld.speaker_allocation_block & (1 << i)) spk_mask |= eld_speaker_allocation_bits[i]; } @@ -1176,7 +1193,7 @@ static int snd_intelhad_hw_free(struct snd_pcm_substream *substream) static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { - int caps, retval = 0; + int retval = 0; unsigned long flag_irq; struct snd_intelhad *intelhaddata; struct had_stream_pvt *stream; @@ -1203,15 +1220,8 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, had_stream->stream_type = HAD_RUNNING_STREAM; /* Enable Audio */ - /* - * ToDo: Need to enable UNDERRUN interrupts as well - * caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE; - */ - caps = HDMI_AUDIO_BUFFER_DONE; - retval = had_set_caps(intelhaddata, HAD_SET_ENABLE_AUDIO_INT, - &caps); - retval = had_set_caps(intelhaddata, HAD_SET_ENABLE_AUDIO, NULL); - snd_intelhad_enable_audio(substream, 1); + snd_intelhad_enable_audio_int(intelhaddata, true); + snd_intelhad_enable_audio(intelhaddata, true); pr_debug("Processed _Start\n"); @@ -1228,18 +1238,13 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, had_stream->stream_type = HAD_INIT; spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irq); /* Disable Audio */ - /* - * ToDo: Need to disable UNDERRUN interrupts as well - * caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE; - */ - caps = HDMI_AUDIO_BUFFER_DONE; - had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO_INT, &caps); - snd_intelhad_enable_audio(substream, 0); + snd_intelhad_enable_audio_int(intelhaddata, false); + snd_intelhad_enable_audio(intelhaddata, false); /* Reset buffer pointers */ snd_intelhad_reset_audio(intelhaddata, 1); snd_intelhad_reset_audio(intelhaddata, 0); stream->stream_status = STREAM_DROPPED; - had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO, NULL); + snd_intelhad_enable_audio_int(intelhaddata, false); break; default: @@ -1297,15 +1302,7 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) /* Get N value in KHz */ - retval = had_get_caps(intelhaddata, HAD_GET_DISPLAY_RATE, - &disp_samp_freq); - if (retval) { - pr_err("querying display sampling freq failed %#x\n", retval); - goto prep_end; - } - - had_get_caps(intelhaddata, HAD_GET_ELD, &intelhaddata->eeld); - had_get_caps(intelhaddata, HAD_GET_DP_OUTPUT, &intelhaddata->dp_output); + disp_samp_freq = intelhaddata->tmds_clock_speed; retval = snd_intelhad_prog_n(substream->runtime->rate, &n_param, intelhaddata); @@ -1315,8 +1312,7 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) } if (intelhaddata->dp_output) - had_get_caps(intelhaddata, HAD_GET_LINK_RATE, &link_rate); - + link_rate = intelhaddata->link_rate; snd_intelhad_prog_cts(substream->runtime->rate, disp_samp_freq, link_rate, @@ -1425,25 +1421,22 @@ static int snd_intelhad_pcm_mmap(struct snd_pcm_substream *substream, vma->vm_end - vma->vm_start, vma->vm_page_prot); } -int hdmi_audio_mode_change(struct snd_pcm_substream *substream) +static int hdmi_audio_mode_change(struct snd_intelhad *intelhaddata) { + struct snd_pcm_substream *substream; int retval = 0; u32 disp_samp_freq, n_param; u32 link_rate = 0; - struct snd_intelhad *intelhaddata; - intelhaddata = snd_pcm_substream_chip(substream); + substream = intelhaddata->stream_info.had_substream; + if (!substream || !substream->runtime) + return 0; /* Disable Audio */ - snd_intelhad_enable_audio(substream, 0); + snd_intelhad_enable_audio(intelhaddata, false); /* Update CTS value */ - retval = had_get_caps(intelhaddata, HAD_GET_DISPLAY_RATE, - &disp_samp_freq); - if (retval) { - pr_err("querying display sampling freq failed %#x\n", retval); - goto out; - } + disp_samp_freq = intelhaddata->tmds_clock_speed; retval = snd_intelhad_prog_n(substream->runtime->rate, &n_param, intelhaddata); @@ -1453,14 +1446,14 @@ int hdmi_audio_mode_change(struct snd_pcm_substream *substream) } if (intelhaddata->dp_output) - had_get_caps(intelhaddata, HAD_GET_LINK_RATE, &link_rate); + link_rate = intelhaddata->link_rate; snd_intelhad_prog_cts(substream->runtime->rate, disp_samp_freq, link_rate, n_param, intelhaddata); /* Enable Audio */ - snd_intelhad_enable_audio(substream, 1); + snd_intelhad_enable_audio(intelhaddata, true); out: return retval; @@ -1555,129 +1548,290 @@ static struct snd_kcontrol_new had_control_iec958 = { .put = had_iec958_put }; +static void _had_wq(struct work_struct *work) +{ + struct snd_intelhad *ctx = + container_of(work, struct snd_intelhad, hdmi_audio_wq); + + had_process_hot_plug(ctx); +} + +static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id) +{ + struct snd_intelhad *ctx = dev_id; + u32 audio_stat, audio_reg; + + audio_reg = AUD_HDMI_STATUS_v2; + mid_hdmi_audio_read(ctx, audio_reg, &audio_stat); + + if (audio_stat & HDMI_AUDIO_UNDERRUN) { + mid_hdmi_audio_write(ctx, audio_reg, HDMI_AUDIO_UNDERRUN); + had_process_buffer_underrun(ctx); + } + + if (audio_stat & HDMI_AUDIO_BUFFER_DONE) { + mid_hdmi_audio_write(ctx, audio_reg, HDMI_AUDIO_BUFFER_DONE); + had_process_buffer_done(ctx); + } + + return IRQ_HANDLED; +} + +static void notify_audio_lpe(struct platform_device *pdev) +{ + struct snd_intelhad *ctx = platform_get_drvdata(pdev); + struct intel_hdmi_lpe_audio_pdata *pdata = pdev->dev.platform_data; + + if (pdata->hdmi_connected != true) { + + dev_dbg(&pdev->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG\n", + __func__); + + if (ctx->state == hdmi_connector_status_connected) { + + ctx->state = hdmi_connector_status_disconnected; + + had_process_hot_unplug(ctx); + } else + dev_dbg(&pdev->dev, "%s: Already Unplugged!\n", + __func__); + + } else { + struct intel_hdmi_lpe_audio_eld *eld = &pdata->eld; + + switch (eld->pipe_id) { + case 0: + ctx->had_config_offset = AUDIO_HDMI_CONFIG_A; + break; + case 1: + ctx->had_config_offset = AUDIO_HDMI_CONFIG_B; + break; + case 2: + ctx->had_config_offset = AUDIO_HDMI_CONFIG_C; + break; + default: + dev_dbg(&pdev->dev, "Invalid pipe %d\n", + eld->pipe_id); + break; + } + + memcpy(&ctx->eld, eld->eld_data, sizeof(ctx->eld)); + + had_process_hot_plug(ctx); + + ctx->state = hdmi_connector_status_connected; + + dev_dbg(&pdev->dev, "%s: HAD_NOTIFY_ELD : port = %d, tmds = %d\n", + __func__, eld->port_id, pdata->tmds_clock_speed); + + if (pdata->tmds_clock_speed) { + ctx->tmds_clock_speed = pdata->tmds_clock_speed; + ctx->dp_output = pdata->dp_output; + ctx->link_rate = pdata->link_rate; + + /* Process mode change if stream is active */ + if (ctx->stream_data.stream_type == HAD_RUNNING_STREAM) + hdmi_audio_mode_change(ctx); + } + } +} + +/* release resources */ +static void hdmi_lpe_audio_free(struct snd_card *card) +{ + struct snd_intelhad *ctx = card->private_data; + + if (ctx->mmio_start) + iounmap(ctx->mmio_start); + if (ctx->irq >= 0) + free_irq(ctx->irq, ctx); +} + /* - * hdmi_audio_probe - to create sound card instance for HDMI audio playabck - * - * @devptr: platform device - * @had_ret: pointer to store the created snd_intelhad object + * hdmi_lpe_audio_probe - start bridge with i915 * - * This function is called when the platform device is probed. This function - * creates and registers the sound card with ALSA + * This function is called when the i915 driver creates the + * hdmi-lpe-audio platform device. Card creation is deferred until a + * hot plug event is received */ -int hdmi_audio_probe(struct platform_device *devptr, - struct snd_intelhad **had_ret) +static int hdmi_lpe_audio_probe(struct platform_device *pdev) { - int retval; - struct snd_pcm *pcm; struct snd_card *card; - struct snd_intelhad *intelhaddata; + struct snd_intelhad *ctx; + struct snd_pcm *pcm; + struct intel_hdmi_lpe_audio_pdata *pdata; + int irq; + struct resource *res_mmio; + int ret; + unsigned long flags; + + dev_dbg(&pdev->dev, "Enter %s\n", __func__); + dev_dbg(&pdev->dev, "dma_mask: %p\n", pdev->dev.dma_mask); + + pdata = pdev->dev.platform_data; + if (!pdata) { + dev_err(&pdev->dev, "%s: quit: pdata not allocated by i915!!\n", __func__); + return -EINVAL; + } - pr_debug("Enter %s\n", __func__); + /* get resources */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "Could not get irq resource\n"); + return -ENODEV; + } + + res_mmio = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res_mmio) { + dev_err(&pdev->dev, "Could not get IO_MEM resources\n"); + return -ENXIO; + } /* create a card instance with ALSA framework */ - retval = snd_card_new(&devptr->dev, hdmi_card_index, hdmi_card_id, - THIS_MODULE, sizeof(*intelhaddata), &card); - if (retval) - return retval; + ret = snd_card_new(&pdev->dev, hdmi_card_index, hdmi_card_id, + THIS_MODULE, sizeof(*ctx), &card); + if (ret) + return ret; + + ctx = card->private_data; + spin_lock_init(&ctx->had_spinlock); + ctx->drv_status = HAD_DRV_DISCONNECTED; + ctx->dev = &pdev->dev; + ctx->card = card; + ctx->card_id = hdmi_card_id; + ctx->card_index = card->number; + ctx->flag_underrun = 0; + ctx->aes_bits = SNDRV_PCM_DEFAULT_CON_SPDIF; + strcpy(card->driver, INTEL_HAD); + strcpy(card->shortname, INTEL_HAD); + + ctx->irq = -1; + ctx->tmds_clock_speed = DIS_SAMPLE_RATE_148_5; + INIT_WORK(&ctx->hdmi_audio_wq, _had_wq); + ctx->state = hdmi_connector_status_disconnected; + + card->private_free = hdmi_lpe_audio_free; + + /* assume pipe A as default */ + ctx->had_config_offset = AUDIO_HDMI_CONFIG_A; + + platform_set_drvdata(pdev, ctx); + + dev_dbg(&pdev->dev, "%s: mmio_start = 0x%x, mmio_end = 0x%x\n", + __func__, (unsigned int)res_mmio->start, + (unsigned int)res_mmio->end); + + ctx->mmio_start = ioremap_nocache(res_mmio->start, + (size_t)(resource_size(res_mmio))); + if (!ctx->mmio_start) { + dev_err(&pdev->dev, "Could not get ioremap\n"); + ret = -EACCES; + goto err; + } - intelhaddata = card->private_data; - spin_lock_init(&intelhaddata->had_spinlock); - intelhaddata->drv_status = HAD_DRV_DISCONNECTED; - pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", - __func__, __LINE__); + /* setup interrupt handler */ + ret = request_irq(irq, display_pipe_interrupt_handler, 0, + pdev->name, ctx); + if (ret < 0) { + dev_err(&pdev->dev, "request_irq failed\n"); + goto err; + } - intelhaddata->dev = &devptr->dev; - intelhaddata->card = card; - intelhaddata->card_id = hdmi_card_id; - intelhaddata->card_index = card->number; - intelhaddata->flag_underrun = 0; - intelhaddata->aes_bits = SNDRV_PCM_DEFAULT_CON_SPDIF; - strncpy(card->driver, INTEL_HAD, strlen(INTEL_HAD)); - strncpy(card->shortname, INTEL_HAD, strlen(INTEL_HAD)); - - retval = snd_pcm_new(card, INTEL_HAD, PCM_INDEX, MAX_PB_STREAMS, - MAX_CAP_STREAMS, &pcm); - if (retval) + ctx->irq = irq; + + ret = snd_pcm_new(card, INTEL_HAD, PCM_INDEX, MAX_PB_STREAMS, + MAX_CAP_STREAMS, &pcm); + if (ret) goto err; /* setup private data which can be retrieved when required */ - pcm->private_data = intelhaddata; + pcm->private_data = ctx; pcm->private_free = snd_intelhad_pcm_free; pcm->info_flags = 0; strncpy(pcm->name, card->shortname, strlen(card->shortname)); - /* setup the ops for palyabck */ + /* setup the ops for playabck */ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_intelhad_playback_ops); /* allocate dma pages for ALSA stream operations * memory allocated is based on size, not max value * thus using same argument for max & size */ - retval = snd_pcm_lib_preallocate_pages_for_all(pcm, + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, NULL, HAD_MAX_BUFFER, HAD_MAX_BUFFER); - if (retval) - goto err; /* IEC958 controls */ - retval = snd_ctl_add(card, snd_ctl_new1(&had_control_iec958_mask, - intelhaddata)); - if (retval < 0) + ret = snd_ctl_add(card, snd_ctl_new1(&had_control_iec958_mask, ctx)); + if (ret < 0) goto err; - retval = snd_ctl_add(card, snd_ctl_new1(&had_control_iec958, - intelhaddata)); - if (retval < 0) + ret = snd_ctl_add(card, snd_ctl_new1(&had_control_iec958, ctx)); + if (ret < 0) goto err; init_channel_allocations(); /* Register channel map controls */ - retval = had_register_chmap_ctls(intelhaddata, pcm); - if (retval < 0) + ret = had_register_chmap_ctls(ctx, pcm); + if (ret < 0) goto err; - retval = snd_card_register(card); - if (retval) + ret = snd_card_register(card); + if (ret) goto err; - pm_runtime_set_active(intelhaddata->dev); - pm_runtime_enable(intelhaddata->dev); + spin_lock_irqsave(&pdata->lpe_audio_slock, flags); + pdata->notify_audio_lpe = notify_audio_lpe; + if (pdata->notify_pending) { - *had_ret = intelhaddata; + dev_dbg(&pdev->dev, "%s: handle pending notification\n", __func__); + notify_audio_lpe(pdev); + pdata->notify_pending = false; + } + spin_unlock_irqrestore(&pdata->lpe_audio_slock, flags); + + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + schedule_work(&ctx->hdmi_audio_wq); return 0; err: snd_card_free(card); - pr_err("Error returned from %s api %#x\n", __func__, retval); - return retval; + return ret; } /* - * hdmi_audio_remove - removes the alsa card + * hdmi_lpe_audio_remove - stop bridge with i915 * - *@haddata: pointer to HAD private data - * - * This function is called when the hdmi cable is un-plugged. This function - * free the sound card. + * This function is called when the platform device is destroyed. The sound + * card should have been removed on hot plug event. */ -int hdmi_audio_remove(struct snd_intelhad *intelhaddata) +static int hdmi_lpe_audio_remove(struct platform_device *pdev) { - int caps; - - pr_debug("Enter %s\n", __func__); + struct snd_intelhad *ctx = platform_get_drvdata(pdev); - if (!intelhaddata) - return 0; + dev_dbg(&pdev->dev, "Enter %s\n", __func__); - if (intelhaddata->drv_status != HAD_DRV_DISCONNECTED) { - caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE; - had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO_INT, &caps); - had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO, NULL); - } - snd_card_free(intelhaddata->card); + if (ctx->drv_status != HAD_DRV_DISCONNECTED) + snd_intelhad_enable_audio_int(ctx, false); + snd_card_free(ctx->card); return 0; } +static struct platform_driver hdmi_lpe_audio_driver = { + .driver = { + .name = "hdmi-lpe-audio", + }, + .probe = hdmi_lpe_audio_probe, + .remove = hdmi_lpe_audio_remove, + .suspend = hdmi_lpe_audio_suspend, + .resume = hdmi_lpe_audio_resume +}; + +module_platform_driver(hdmi_lpe_audio_driver); +MODULE_ALIAS("platform:hdmi_lpe_audio"); + MODULE_AUTHOR("Sailaja Bandarupalli "); MODULE_AUTHOR("Ramesh Babu K V "); MODULE_AUTHOR("Vaibhav Agarwal "); diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 8415f93e40dc..6efa846f98c9 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -108,7 +108,7 @@ struct had_stream_data { * @drv_status: driver status * @buf_info: ring buffer info * @stream_info: stream information - * @eeld: holds EELD info + * @eld: holds ELD info * @curr_buf: pointer to hold current active ring buf * @valid_buf_cnt: ring buffer count for stream * @had_spinlock: driver lock @@ -127,7 +127,7 @@ struct snd_intelhad { enum had_drv_status drv_status; struct ring_buf_info buf_info[HAD_NUM_OF_RING_BUFS]; struct pcm_stream_info stream_info; - union otm_hdmi_eld_t eeld; + union otm_hdmi_eld_t eld; bool dp_output; enum intel_had_aud_buf_type curr_buf; int valid_buf_cnt; @@ -142,15 +142,27 @@ struct snd_intelhad { unsigned int *audio_reg_base; unsigned int audio_cfg_offset; int underrun_count; + enum hdmi_connector_status state; + int tmds_clock_speed; + int link_rate; + + /* internal stuff */ + int irq; + void __iomem *mmio_start; + unsigned int had_config_offset; + int hdmi_audio_interrupt_mask; + struct work_struct hdmi_audio_wq; }; -int had_event_handler(enum had_event_type event_type, void *data); - -int hdmi_audio_suspend(void *drv_data); -int hdmi_audio_resume(void *drv_data); -int hdmi_audio_mode_change(struct snd_pcm_substream *substream); +int hdmi_lpe_audio_suspend(struct platform_device *pdev, pm_message_t state); +int hdmi_lpe_audio_resume(struct platform_device *pdev); extern struct snd_pcm_ops snd_intelhad_playback_ops; +int had_process_buffer_done(struct snd_intelhad *intelhaddata); +int had_process_buffer_underrun(struct snd_intelhad *intelhaddata); +int had_process_hot_plug(struct snd_intelhad *intelhaddata); +int had_process_hot_unplug(struct snd_intelhad *intelhaddata); + int snd_intelhad_init_audio_ctrl(struct snd_pcm_substream *substream, struct snd_intelhad *intelhaddata, int flag_silence); @@ -160,15 +172,12 @@ int snd_intelhad_invd_buffer(int start, int end); int snd_intelhad_read_len(struct snd_intelhad *intelhaddata); void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata); -void snd_intelhad_enable_audio(struct snd_pcm_substream *substream, u8 enable); +void snd_intelhad_enable_audio_int(struct snd_intelhad *ctx, bool enable); +void snd_intelhad_enable_audio(struct snd_intelhad *ctx, bool enable); void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata); /* Register access functions */ int had_get_hwstate(struct snd_intelhad *intelhaddata); -int had_get_caps(struct snd_intelhad *intelhaddata, - enum had_caps_list query_element, void *capabilties); -int had_set_caps(struct snd_intelhad *intelhaddata, - enum had_caps_list set_element, void *capabilties); int had_read_register(struct snd_intelhad *intelhaddata, u32 reg_addr, u32 *data); int had_write_register(struct snd_intelhad *intelhaddata, @@ -176,8 +185,4 @@ int had_write_register(struct snd_intelhad *intelhaddata, int had_read_modify(struct snd_intelhad *intelhaddata, u32 reg_addr, u32 data, u32 mask); -int hdmi_audio_probe(struct platform_device *devptr, - struct snd_intelhad **had_ret); -int hdmi_audio_remove(struct snd_intelhad *intelhaddata); - #endif /* _INTEL_HDMI_AUDIO_ */ diff --git a/sound/x86/intel_hdmi_audio_if.c b/sound/x86/intel_hdmi_audio_if.c index 57acefaf930e..327650dd1723 100644 --- a/sound/x86/intel_hdmi_audio_if.c +++ b/sound/x86/intel_hdmi_audio_if.c @@ -33,21 +33,20 @@ #include "intel_hdmi_audio.h" #include "intel_hdmi_lpe_audio.h" -/** - * hdmi_audio_suspend - power management suspend function +/* + * hdmi_lpe_audio_suspend - power management suspend function * - *@haddata: pointer to HAD private data + * @pdev: platform device * * This function is called by client driver to suspend the * hdmi audio. */ -int hdmi_audio_suspend(void *haddata) +int hdmi_lpe_audio_suspend(struct platform_device *pdev, pm_message_t state) { - int caps, retval = 0; struct had_stream_data *had_stream; unsigned long flag_irqs; struct snd_pcm_substream *substream; - struct snd_intelhad *intelhaddata = (struct snd_intelhad *)haddata; + struct snd_intelhad *intelhaddata = platform_get_drvdata(pdev); pr_debug("Enter:%s\n", __func__); @@ -64,13 +63,13 @@ int hdmi_audio_suspend(void *haddata) if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); pr_debug("had not connected\n"); - return retval; + return 0; } if (intelhaddata->drv_status == HAD_DRV_SUSPENDED) { spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); pr_debug("had already suspended\n"); - return retval; + return 0; } intelhaddata->drv_status = HAD_DRV_SUSPENDED; @@ -78,29 +77,22 @@ int hdmi_audio_suspend(void *haddata) __func__, __LINE__); spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - /* - * ToDo: Need to disable UNDERRUN interrupts as well - * caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE; - */ - caps = HDMI_AUDIO_BUFFER_DONE; - had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO_INT, &caps); - had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO, NULL); + snd_intelhad_enable_audio_int(intelhaddata, false); pr_debug("Exit:%s", __func__); - return retval; + return 0; } -/** - * hdmi_audio_resume - power management resume function +/* + * hdmi_lpe_audio_resume - power management resume function * - *@haddata: pointer to HAD private data + *@pdev: platform device * * This function is called by client driver to resume the * hdmi audio. */ -int hdmi_audio_resume(void *haddata) +int hdmi_lpe_audio_resume(struct platform_device *pdev) { - int caps, retval = 0; - struct snd_intelhad *intelhaddata = (struct snd_intelhad *)haddata; + struct snd_intelhad *intelhaddata = platform_get_drvdata(pdev); unsigned long flag_irqs; pr_debug("Enter:%s\n", __func__); @@ -128,15 +120,9 @@ int hdmi_audio_resume(void *haddata) pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", __func__, __LINE__); spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - /* - * ToDo: Need to enable UNDERRUN interrupts as well - * caps = HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE; - */ - caps = HDMI_AUDIO_BUFFER_DONE; - retval = had_set_caps(intelhaddata, HAD_SET_ENABLE_AUDIO_INT, &caps); - retval = had_set_caps(intelhaddata, HAD_SET_ENABLE_AUDIO, NULL); + snd_intelhad_enable_audio_int(intelhaddata, true); pr_debug("Exit:%s", __func__); - return retval; + return 0; } static inline int had_chk_intrmiss(struct snd_intelhad *intelhaddata, @@ -357,7 +343,6 @@ int had_process_hot_plug(struct snd_intelhad *intelhaddata) int had_process_hot_unplug(struct snd_intelhad *intelhaddata) { - int caps, retval = 0; enum intel_had_aud_buf_type buf_id; struct had_stream_data *had_stream; unsigned long flag_irqs; @@ -372,17 +357,12 @@ int had_process_hot_unplug(struct snd_intelhad *intelhaddata) if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { pr_debug("Device already disconnected\n"); spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - return retval; + return 0; } else { /* Disable Audio */ - caps = HDMI_AUDIO_BUFFER_DONE; - retval = had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO_INT, - &caps); - retval = had_set_caps(intelhaddata, HAD_SET_DISABLE_AUDIO, - NULL); - snd_intelhad_enable_audio( - intelhaddata->stream_info.had_substream, 0); + snd_intelhad_enable_audio_int(intelhaddata, false); + snd_intelhad_enable_audio(intelhaddata, false); } intelhaddata->drv_status = HAD_DRV_DISCONNECTED; @@ -405,74 +385,6 @@ int had_process_hot_unplug(struct snd_intelhad *intelhaddata) intelhaddata->audio_reg_base = NULL; pr_debug("%s: unlocked -> returned\n", __func__); - return retval; + return 0; } -/** - * had_event_handler - Call back function to handle events - * - * @event_type: Event type to handle - * @data: data related to the event_type - * - * This function is invoked to handle HDMI events from client driver. - */ -int had_event_handler(enum had_event_type event_type, void *data) -{ - int retval = 0; - struct snd_intelhad *intelhaddata = data; - enum intel_had_aud_buf_type buf_id; - struct snd_pcm_substream *substream; - struct had_stream_data *had_stream; - unsigned long flag_irqs; - - buf_id = intelhaddata->curr_buf; - had_stream = &intelhaddata->stream_data; - - /* Switching to a function can drop atomicity even in INTR context. - * Thus, a big lock is acquired to maintain atomicity. - * This can be optimized later. - * Currently, only buffer_done/_underrun executes in INTR context. - * Also, locking is implemented separately to avoid real contention - * of data(struct intelhaddata) between IRQ/SOFT_IRQ/PROCESS context. - */ - substream = intelhaddata->stream_info.had_substream; - switch (event_type) { - case HAD_EVENT_AUDIO_BUFFER_DONE: - retval = had_process_buffer_done(intelhaddata); - break; - - case HAD_EVENT_AUDIO_BUFFER_UNDERRUN: - retval = had_process_buffer_underrun(intelhaddata); - break; - - case HAD_EVENT_HOT_PLUG: - retval = had_process_hot_plug(intelhaddata); - break; - - case HAD_EVENT_HOT_UNPLUG: - retval = had_process_hot_unplug(intelhaddata); - break; - - case HAD_EVENT_MODE_CHANGING: - pr_debug(" called _event_handler with _MODE_CHANGE event\n"); - /* Process only if stream is active & cable Plugged-in */ - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); - if (intelhaddata->drv_status >= HAD_DRV_DISCONNECTED) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, - flag_irqs); - break; - } - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - if ((had_stream->stream_type == HAD_RUNNING_STREAM) - && substream) - retval = hdmi_audio_mode_change(substream); - break; - - default: - pr_debug("error un-handled event !!\n"); - retval = -EINVAL; - break; - - } - return retval; -} diff --git a/sound/x86/intel_hdmi_lpe_audio.c b/sound/x86/intel_hdmi_lpe_audio.c deleted file mode 100644 index 8789f55724da..000000000000 --- a/sound/x86/intel_hdmi_lpe_audio.c +++ /dev/null @@ -1,462 +0,0 @@ -/* - * intel_hdmi_lpe_audio.c - Intel HDMI LPE audio driver for Atom platforms - * - * Copyright (C) 2016 Intel Corp - * Authors: - * Jerome Anand - * Aravind Siddappaji - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "intel_hdmi_lpe_audio.h" -#include "intel_hdmi_audio.h" - -struct hdmi_lpe_audio_ctx { - struct platform_device *pdev; - int irq; - void __iomem *mmio_start; - struct snd_intelhad *had; - int tmds_clock_speed; - bool dp_output; - int link_rate; - unsigned int had_config_offset; - int hdmi_audio_interrupt_mask; - struct work_struct hdmi_audio_wq; - int state; /* connection state */ - union otm_hdmi_eld_t eld; /* ELD copy */ -}; - -static void mid_hdmi_audio_signal_event(struct platform_device *pdev, - enum had_event_type event) -{ - struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); - - dev_dbg(&pdev->dev, "%s: Enter\n", __func__); - - /* The handler is protected in the respective - * event handlers to avoid races - */ - had_event_handler(event, ctx->had); -} - -/* - * used to write into display controller HDMI audio registers. - */ -int mid_hdmi_audio_write(struct platform_device *pdev, u32 reg, u32 val) -{ - struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); - - dev_dbg(&pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, reg, val); - - if (ctx->dp_output) { - if (reg == AUD_CONFIG && (val & AUD_CONFIG_VALID_BIT)) - val |= AUD_CONFIG_DP_MODE | AUD_CONFIG_BLOCK_BIT; - } - iowrite32(val, ctx->mmio_start + ctx->had_config_offset + reg); - - return 0; -} - -/* - * used to get the register value read from - * display controller HDMI audio registers. - */ -int mid_hdmi_audio_read(struct platform_device *pdev, u32 reg, u32 *val) -{ - struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); - - *val = ioread32(ctx->mmio_start + ctx->had_config_offset + reg); - dev_dbg(&pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, reg, *val); - return 0; -} - -/* - * used to update the masked bits in display controller HDMI - * audio registers. - */ -int mid_hdmi_audio_rmw(struct platform_device *pdev, - u32 reg, u32 val, u32 mask) -{ - struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); - u32 val_tmp = 0; - - val_tmp = ioread32(ctx->mmio_start + ctx->had_config_offset + reg); - val_tmp &= ~mask; - val_tmp |= (val & mask); - - if (ctx->dp_output) { - if (reg == AUD_CONFIG && (val_tmp & AUD_CONFIG_VALID_BIT)) - val_tmp |= AUD_CONFIG_DP_MODE | AUD_CONFIG_BLOCK_BIT; - } - - iowrite32(val_tmp, ctx->mmio_start + ctx->had_config_offset + reg); - dev_dbg(&pdev->dev, "%s: reg[0x%x] = 0x%x\n", __func__, - reg, val_tmp); - - return 0; -} - -/* - * used to return the HDMI audio capabilities. - * e.g. resolution, frame rate. - */ -int mid_hdmi_audio_get_caps(struct platform_device *pdev, - enum had_caps_list get_element, - void *capabilities) -{ - struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); - int ret = 0; - - dev_dbg(&pdev->dev, "%s: Enter\n", __func__); - - switch (get_element) { - case HAD_GET_ELD: - memcpy(capabilities, &ctx->eld, sizeof(ctx->eld)); - print_hex_dump_bytes("eld: ", DUMP_PREFIX_NONE, - (u8 *)&ctx->eld, sizeof(ctx->eld)); - break; - case HAD_GET_DISPLAY_RATE: - /* ToDo: Verify if sampling freq logic is correct */ - *(u32 *)capabilities = ctx->tmds_clock_speed; - dev_dbg(&pdev->dev, "%s: tmds_clock_speed = 0x%x\n", - __func__, ctx->tmds_clock_speed); - break; - case HAD_GET_LINK_RATE: - /* ToDo: Verify if sampling freq logic is correct */ - *(u32 *)capabilities = ctx->link_rate; - dev_dbg(&pdev->dev, "%s: link rate = 0x%x\n", - __func__, ctx->link_rate); - break; - case HAD_GET_DP_OUTPUT: - *(u32 *)capabilities = ctx->dp_output; - dev_dbg(&pdev->dev, "%s: dp_output = %d\n", - __func__, ctx->dp_output); - break; - default: - break; - } - - return ret; -} - -/* - * used to set the HDMI audio capabilities. - * e.g. Audio INT. - */ -int mid_hdmi_audio_set_caps(struct platform_device *pdev, - enum had_caps_list set_element, - void *capabilties) -{ - dev_dbg(&pdev->dev, "%s: cap_id = 0x%x\n", __func__, set_element); - - switch (set_element) { - case HAD_SET_ENABLE_AUDIO_INT: - { - u32 status_reg; - - mid_hdmi_audio_read(pdev, AUD_HDMI_STATUS_v2, - &status_reg); - status_reg |= - HDMI_AUDIO_BUFFER_DONE | HDMI_AUDIO_UNDERRUN; - mid_hdmi_audio_write(pdev, AUD_HDMI_STATUS_v2, - status_reg); - mid_hdmi_audio_read(pdev, AUD_HDMI_STATUS_v2, - &status_reg); - } - break; - default: - break; - } - - return 0; -} - -static void _had_wq(struct work_struct *work) -{ - struct hdmi_lpe_audio_ctx *ctx = - container_of(work, struct hdmi_lpe_audio_ctx, hdmi_audio_wq); - - mid_hdmi_audio_signal_event(ctx->pdev, HAD_EVENT_HOT_PLUG); -} - -static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id) -{ - struct platform_device *pdev = dev_id; - u32 audio_stat, audio_reg; - struct hdmi_lpe_audio_ctx *ctx; - - dev_dbg(&pdev->dev, "%s: Enter\n", __func__); - - ctx = platform_get_drvdata(pdev); - - audio_reg = AUD_HDMI_STATUS_v2; - mid_hdmi_audio_read(pdev, audio_reg, &audio_stat); - - if (audio_stat & HDMI_AUDIO_UNDERRUN) { - mid_hdmi_audio_write(pdev, audio_reg, HDMI_AUDIO_UNDERRUN); - mid_hdmi_audio_signal_event(pdev, - HAD_EVENT_AUDIO_BUFFER_UNDERRUN); - } - - if (audio_stat & HDMI_AUDIO_BUFFER_DONE) { - mid_hdmi_audio_write(pdev, audio_reg, HDMI_AUDIO_BUFFER_DONE); - mid_hdmi_audio_signal_event(pdev, - HAD_EVENT_AUDIO_BUFFER_DONE); - } - - return IRQ_HANDLED; -} - -static void notify_audio_lpe(struct platform_device *pdev) -{ - struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); - struct intel_hdmi_lpe_audio_pdata *pdata = pdev->dev.platform_data; - - if (pdata->hdmi_connected != true) { - - dev_dbg(&pdev->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG\n", - __func__); - - if (ctx->state == hdmi_connector_status_connected) { - - ctx->state = hdmi_connector_status_disconnected; - - mid_hdmi_audio_signal_event(pdev, - HAD_EVENT_HOT_UNPLUG); - } else - dev_dbg(&pdev->dev, "%s: Already Unplugged!\n", - __func__); - - } else { - struct intel_hdmi_lpe_audio_eld *eld = &pdata->eld; - - switch (eld->pipe_id) { - case 0: - ctx->had_config_offset = AUDIO_HDMI_CONFIG_A; - break; - case 1: - ctx->had_config_offset = AUDIO_HDMI_CONFIG_B; - break; - case 2: - ctx->had_config_offset = AUDIO_HDMI_CONFIG_C; - break; - default: - dev_dbg(&pdev->dev, "Invalid pipe %d\n", - eld->pipe_id); - break; - } - - memcpy(&ctx->eld, eld->eld_data, sizeof(ctx->eld)); - - mid_hdmi_audio_signal_event(pdev, HAD_EVENT_HOT_PLUG); - - ctx->state = hdmi_connector_status_connected; - - dev_dbg(&pdev->dev, "%s: HAD_NOTIFY_ELD : port = %d, tmds = %d\n", - __func__, eld->port_id, pdata->tmds_clock_speed); - - if (pdata->tmds_clock_speed) { - ctx->tmds_clock_speed = pdata->tmds_clock_speed; - ctx->dp_output = pdata->dp_output; - ctx->link_rate = pdata->link_rate; - mid_hdmi_audio_signal_event(pdev, - HAD_EVENT_MODE_CHANGING); - } - } -} - -/** - * hdmi_lpe_audio_probe - start bridge with i915 - * - * This function is called when the i915 driver creates the - * hdmi-lpe-audio platform device. Card creation is deferred until a - * hot plug event is received - */ -static int hdmi_lpe_audio_probe(struct platform_device *pdev) -{ - struct hdmi_lpe_audio_ctx *ctx; - struct intel_hdmi_lpe_audio_pdata *pdata; - int irq; - struct resource *res_mmio; - void __iomem *mmio_start; - int ret = 0; - unsigned long flag_irq; - - dev_dbg(&pdev->dev, "Enter %s\n", __func__); - dev_dbg(&pdev->dev, "dma_mask: %p\n", pdev->dev.dma_mask); - - pdata = pdev->dev.platform_data; - if (!pdata) { - dev_err(&pdev->dev, "%s: quit: pdata not allocated by i915!!\n", __func__); - return -EINVAL; - } - - /* get resources */ - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "Could not get irq resource\n"); - return -ENODEV; - } - - res_mmio = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res_mmio) { - dev_err(&pdev->dev, "Could not get IO_MEM resources\n"); - return -ENXIO; - } - - dev_dbg(&pdev->dev, "%s: mmio_start = 0x%x, mmio_end = 0x%x\n", - __func__, (unsigned int)res_mmio->start, - (unsigned int)res_mmio->end); - - mmio_start = ioremap_nocache(res_mmio->start, - (size_t)(resource_size(res_mmio))); - if (!mmio_start) { - dev_err(&pdev->dev, "Could not get ioremap\n"); - return -EACCES; - } - - /* alloc and save context */ - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if (ctx == NULL) { - ret = -ENOMEM; - goto error_ctx; - } - - ctx->pdev = pdev; - ctx->irq = irq; - dev_dbg(&pdev->dev, "hdmi lpe audio: irq num = %d\n", irq); - ctx->mmio_start = mmio_start; - ctx->tmds_clock_speed = DIS_SAMPLE_RATE_148_5; - INIT_WORK(&ctx->hdmi_audio_wq, _had_wq); - ctx->state = hdmi_connector_status_disconnected; - - /* assume pipe A as default */ - ctx->had_config_offset = AUDIO_HDMI_CONFIG_A; - - platform_set_drvdata(pdev, ctx); - - /* setup interrupt handler */ - ret = request_irq(irq, display_pipe_interrupt_handler, 0, - pdev->name, pdev); - - if (ret < 0) { - dev_err(&pdev->dev, "request_irq failed\n"); - goto error_irq; - } - - ret = hdmi_audio_probe(pdev, &ctx->had); - if (ret < 0) - goto error_probe; - - dev_dbg(&pdev->dev, "hdmi lpe audio: setting pin eld notify callback\n"); - - /* The Audio driver is loading now and we need to notify - * it if there is an HDMI device attached - */ - dev_dbg(&pdev->dev, "%s: Scheduling HDMI audio work queue\n", - __func__); - schedule_work(&ctx->hdmi_audio_wq); - - spin_lock_irqsave(&pdata->lpe_audio_slock, flag_irq); - pdata->notify_audio_lpe = notify_audio_lpe; - if (pdata->notify_pending) { - - dev_dbg(&pdev->dev, "%s: handle pending notification\n", __func__); - notify_audio_lpe(pdev); - pdata->notify_pending = false; - } - spin_unlock_irqrestore(&pdata->lpe_audio_slock, flag_irq); - - return ret; - - error_probe: - free_irq(irq, pdev); - error_irq: - kfree(ctx); - error_ctx: - iounmap(mmio_start); - return ret; -} - -/** - * hdmi_lpe_audio_remove - stop bridge with i915 - * - * This function is called when the platform device is destroyed. The sound - * card should have been removed on hot plug event. - */ -static int hdmi_lpe_audio_remove(struct platform_device *pdev) -{ - struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); - - dev_dbg(&pdev->dev, "Enter %s\n", __func__); - - hdmi_audio_remove(ctx->had); - - /* release resources */ - iounmap(ctx->mmio_start); - free_irq(ctx->irq, pdev); - kfree(ctx); - return 0; -} - -static int hdmi_lpe_audio_suspend(struct platform_device *pdev, - pm_message_t state) -{ - struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); - - dev_dbg(&pdev->dev, "%s: state %d", __func__, ctx->state); - /* HDMI is not connected, assuming audio device is suspended already */ - if (ctx->state != hdmi_connector_status_disconnected) - hdmi_audio_suspend(ctx->had); - return 0; -} - -static int hdmi_lpe_audio_resume(struct platform_device *pdev) -{ - struct hdmi_lpe_audio_ctx *ctx = platform_get_drvdata(pdev); - - dev_dbg(&pdev->dev, "%s: state %d", __func__, ctx->state); - /* HDMI is not connected, there is no need to resume audio device */ - if (ctx->state != hdmi_connector_status_disconnected) - hdmi_audio_resume(ctx->had); - return 0; -} - -static struct platform_driver hdmi_lpe_audio_driver = { - .driver = { - .name = "hdmi-lpe-audio", - }, - .probe = hdmi_lpe_audio_probe, - .remove = hdmi_lpe_audio_remove, - .suspend = hdmi_lpe_audio_suspend, - .resume = hdmi_lpe_audio_resume -}; - -module_platform_driver(hdmi_lpe_audio_driver); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:hdmi_lpe_audio"); diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index a9d51b7c5bae..8f320b4aa3b7 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -27,12 +27,11 @@ #include #include #include +#include #include #include #include -struct platform_device; - #define AUD_CONFIG_VALID_BIT (1<<9) #define AUD_CONFIG_DP_MODE (1<<15) #define AUD_CONFIG_BLOCK_BIT (1<<7) @@ -636,24 +635,4 @@ enum had_event_type { HAD_EVENT_QUERY_IS_AUDIO_SUSPENDED, }; -/* - * HDMI Display Controller Audio Interface - * - */ -struct hdmi_audio_event { - int type; -}; - -int mid_hdmi_audio_read(struct platform_device *pdev, u32 reg, u32 *val); -int mid_hdmi_audio_write(struct platform_device *pdev, u32 reg, u32 val); -int mid_hdmi_audio_rmw(struct platform_device *pdev, - u32 reg, u32 val, u32 mask); - -int mid_hdmi_audio_get_caps(struct platform_device *pdev, - enum had_caps_list get_element, - void *capabilities); -int mid_hdmi_audio_set_caps(struct platform_device *pdev, - enum had_caps_list set_element, - void *capabilties); - #endif -- cgit v1.2.3 From 372d855f87b535005e392094afff9927bc000cf9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 13:57:58 +0100 Subject: ALSA: x86: Fold intel_hdmi_audio_if.c into main file As the very last step, we fold intel_hdmi_audio_if.c into the main file, intel_hdmi_audio.c. This is merely a cleanup, and no functional change. By this move, we can mark all functions and variables as static, which allows the compiler more optimizations. Signed-off-by: Takashi Iwai --- sound/x86/Makefile | 3 +- sound/x86/intel_hdmi_audio.c | 391 ++++++++++++++++++++++++++++++++++++++-- sound/x86/intel_hdmi_audio.h | 31 ---- sound/x86/intel_hdmi_audio_if.c | 390 --------------------------------------- 4 files changed, 376 insertions(+), 439 deletions(-) delete mode 100644 sound/x86/intel_hdmi_audio_if.c diff --git a/sound/x86/Makefile b/sound/x86/Makefile index 3c0bf63333e6..7ff919808320 100644 --- a/sound/x86/Makefile +++ b/sound/x86/Makefile @@ -1,5 +1,4 @@ snd-hdmi-lpe-audio-objs += \ - intel_hdmi_audio.o \ - intel_hdmi_audio_if.o + intel_hdmi_audio.o obj-$(CONFIG_HDMI_LPE_AUDIO) += snd-hdmi-lpe-audio.o diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 1594f826cf31..effe93b58273 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -157,8 +157,7 @@ static const struct snd_pcm_hardware snd_intel_hadstream = { }; /* Register access functions */ - -int had_get_hwstate(struct snd_intelhad *intelhaddata) +static int had_get_hwstate(struct snd_intelhad *intelhaddata) { /* Check for device presence -SW state */ if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { @@ -182,7 +181,8 @@ mid_hdmi_audio_write(struct snd_intelhad *ctx, u32 reg, u32 val) iowrite32(val, ctx->mmio_start + ctx->had_config_offset + reg); } -int had_read_register(struct snd_intelhad *intelhaddata, u32 offset, u32 *data) +static int had_read_register(struct snd_intelhad *intelhaddata, + u32 offset, u32 *data) { int retval; @@ -203,7 +203,8 @@ static void fixup_dp_config(struct snd_intelhad *intelhaddata, } } -int had_write_register(struct snd_intelhad *intelhaddata, u32 offset, u32 data) +static int had_write_register(struct snd_intelhad *intelhaddata, + u32 offset, u32 data) { int retval; @@ -216,8 +217,8 @@ int had_write_register(struct snd_intelhad *intelhaddata, u32 offset, u32 data) return 0; } -int had_read_modify(struct snd_intelhad *intelhaddata, u32 offset, - u32 data, u32 mask) +static int had_read_modify(struct snd_intelhad *intelhaddata, u32 offset, + u32 data, u32 mask) { u32 val_tmp; int retval; @@ -280,7 +281,7 @@ static int had_read_modify_aud_config_v2(struct snd_intelhad *intelhaddata, return had_read_modify(intelhaddata, AUD_CONFIG, data, mask); } -void snd_intelhad_enable_audio_int(struct snd_intelhad *ctx, bool enable) +static void snd_intelhad_enable_audio_int(struct snd_intelhad *ctx, bool enable) { u32 status_reg; @@ -292,8 +293,8 @@ void snd_intelhad_enable_audio_int(struct snd_intelhad *ctx, bool enable) } } -void snd_intelhad_enable_audio(struct snd_intelhad *intelhaddata, - bool enable) +static void snd_intelhad_enable_audio(struct snd_intelhad *intelhaddata, + bool enable) { had_read_modify_aud_config_v2(intelhaddata, enable ? BIT(0) : 0, BIT(0)); @@ -488,7 +489,7 @@ static int spk_to_chmap(int spk) return 0; } -void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata) +static void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata) { int i = 0, c = 0; int spk_mask = 0; @@ -675,7 +676,7 @@ static void snd_intelhad_prog_dip(struct snd_pcm_substream *substream, * * This function programs ring buffer address and length into registers. */ -int snd_intelhad_prog_buffer(struct snd_intelhad *intelhaddata, +static int snd_intelhad_prog_buffer(struct snd_intelhad *intelhaddata, int start, int end) { u32 ring_buf_addr, ring_buf_size, period_bytes; @@ -732,7 +733,7 @@ int snd_intelhad_prog_buffer(struct snd_intelhad *intelhaddata, return 0; } -int snd_intelhad_read_len(struct snd_intelhad *intelhaddata) +static int snd_intelhad_read_len(struct snd_intelhad *intelhaddata) { int i, retval = 0; u32 len[4]; @@ -939,7 +940,7 @@ static int snd_intelhad_prog_n(u32 aud_samp_freq, u32 *n_param, return 0; } -void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata) +static void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata) { u32 hdmi_status, i = 0; @@ -1459,8 +1460,364 @@ out: return retval; } -/*PCM operations structure and the calls back for the same */ -struct snd_pcm_ops snd_intelhad_playback_ops = { +/* + * hdmi_lpe_audio_suspend - power management suspend function + * + * @pdev: platform device + * + * This function is called by client driver to suspend the + * hdmi audio. + */ +static int hdmi_lpe_audio_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct had_stream_data *had_stream; + unsigned long flag_irqs; + struct snd_pcm_substream *substream; + struct snd_intelhad *intelhaddata = platform_get_drvdata(pdev); + + pr_debug("Enter:%s\n", __func__); + + had_stream = &intelhaddata->stream_data; + substream = intelhaddata->stream_info.had_substream; + + if (intelhaddata->dev->power.runtime_status != RPM_SUSPENDED) { + pr_err("audio stream is active\n"); + return -EAGAIN; + } + + + spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + pr_debug("had not connected\n"); + return 0; + } + + if (intelhaddata->drv_status == HAD_DRV_SUSPENDED) { + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + pr_debug("had already suspended\n"); + return 0; + } + + intelhaddata->drv_status = HAD_DRV_SUSPENDED; + pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_SUSPENDED\n", + __func__, __LINE__); + + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + snd_intelhad_enable_audio_int(intelhaddata, false); + pr_debug("Exit:%s", __func__); + return 0; +} + +/* + * hdmi_lpe_audio_resume - power management resume function + * + *@pdev: platform device + * + * This function is called by client driver to resume the + * hdmi audio. + */ +static int hdmi_lpe_audio_resume(struct platform_device *pdev) +{ + struct snd_intelhad *intelhaddata = platform_get_drvdata(pdev); + unsigned long flag_irqs; + + pr_debug("Enter:%s\n", __func__); + + spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + pr_debug("had not connected\n"); + return 0; + } + + if (intelhaddata->drv_status != HAD_DRV_SUSPENDED) { + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + pr_err("had is not in suspended state\n"); + return 0; + } + + if (had_get_hwstate(intelhaddata)) { + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + pr_err("Failed to resume. Device not accessible\n"); + return -ENODEV; + } + + intelhaddata->drv_status = HAD_DRV_CONNECTED; + pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", + __func__, __LINE__); + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + snd_intelhad_enable_audio_int(intelhaddata, true); + pr_debug("Exit:%s", __func__); + return 0; +} + +static inline int had_chk_intrmiss(struct snd_intelhad *intelhaddata, + enum intel_had_aud_buf_type buf_id) +{ + int i, intr_count = 0; + enum intel_had_aud_buf_type buff_done; + u32 buf_size, buf_addr; + struct had_stream_data *had_stream; + unsigned long flag_irqs; + + had_stream = &intelhaddata->stream_data; + + buff_done = buf_id; + + intr_count = snd_intelhad_read_len(intelhaddata); + if (intr_count > 1) { + /* In case of active playback */ + pr_err("Driver detected %d missed buffer done interrupt(s)!!!!\n", + (intr_count - 1)); + if (intr_count > 3) + return intr_count; + + buf_id += (intr_count - 1); + /* Reprogram registers*/ + for (i = buff_done; i < buf_id; i++) { + int j = i % 4; + + buf_size = intelhaddata->buf_info[j].buf_size; + buf_addr = intelhaddata->buf_info[j].buf_addr; + had_write_register(intelhaddata, + AUD_BUF_A_LENGTH + + (j * HAD_REG_WIDTH), buf_size); + had_write_register(intelhaddata, + AUD_BUF_A_ADDR+(j * HAD_REG_WIDTH), + (buf_addr | BIT(0) | BIT(1))); + } + buf_id = buf_id % 4; + spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + intelhaddata->buff_done = buf_id; + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + } + + return intr_count; +} + +static int had_process_buffer_done(struct snd_intelhad *intelhaddata) +{ + u32 len = 1; + enum intel_had_aud_buf_type buf_id; + enum intel_had_aud_buf_type buff_done; + struct pcm_stream_info *stream; + u32 buf_size; + struct had_stream_data *had_stream; + int intr_count; + enum had_status_stream stream_type; + unsigned long flag_irqs; + + had_stream = &intelhaddata->stream_data; + stream = &intelhaddata->stream_info; + intr_count = 1; + + spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + pr_err("%s:Device already disconnected\n", __func__); + return 0; + } + buf_id = intelhaddata->curr_buf; + intelhaddata->buff_done = buf_id; + buff_done = intelhaddata->buff_done; + buf_size = intelhaddata->buf_info[buf_id].buf_size; + stream_type = had_stream->stream_type; + + pr_debug("Enter:%s buf_id=%d\n", __func__, buf_id); + + /* Every debug statement has an implication + * of ~5msec. Thus, avoid having >3 debug statements + * for each buffer_done handling. + */ + + /* Check for any intr_miss in case of active playback */ + if (had_stream->stream_type == HAD_RUNNING_STREAM) { + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + intr_count = had_chk_intrmiss(intelhaddata, buf_id); + if (!intr_count || (intr_count > 3)) { + pr_err("HAD SW state in non-recoverable!!! mode\n"); + pr_err("Already played stale data\n"); + return 0; + } + buf_id += (intr_count - 1); + buf_id = buf_id % 4; + spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + } + + intelhaddata->buf_info[buf_id].is_valid = true; + if (intelhaddata->valid_buf_cnt-1 == buf_id) { + if (had_stream->stream_type >= HAD_RUNNING_STREAM) + intelhaddata->curr_buf = HAD_BUF_TYPE_A; + } else + intelhaddata->curr_buf = buf_id + 1; + + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + + if (had_get_hwstate(intelhaddata)) { + pr_err("HDMI cable plugged-out\n"); + return 0; + } + + /*Reprogram the registers with addr and length*/ + had_write_register(intelhaddata, + AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH), + buf_size); + had_write_register(intelhaddata, + AUD_BUF_A_ADDR + (buf_id * HAD_REG_WIDTH), + intelhaddata->buf_info[buf_id].buf_addr | + BIT(0) | BIT(1)); + + had_read_register(intelhaddata, + AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH), + &len); + pr_debug("%s:Enabled buf[%d]\n", __func__, buf_id); + + /* In case of actual data, + * report buffer_done to above ALSA layer + */ + buf_size = intelhaddata->buf_info[buf_id].buf_size; + if (stream_type >= HAD_RUNNING_STREAM) { + intelhaddata->stream_info.buffer_rendered += + (intr_count * buf_size); + stream->period_elapsed(stream->had_substream); + } + + return 0; +} + +static int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) +{ + enum intel_had_aud_buf_type buf_id; + struct pcm_stream_info *stream; + struct had_stream_data *had_stream; + enum had_status_stream stream_type; + unsigned long flag_irqs; + int drv_status; + + had_stream = &intelhaddata->stream_data; + stream = &intelhaddata->stream_info; + + spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + buf_id = intelhaddata->curr_buf; + stream_type = had_stream->stream_type; + intelhaddata->buff_done = buf_id; + drv_status = intelhaddata->drv_status; + if (stream_type == HAD_RUNNING_STREAM) + intelhaddata->curr_buf = HAD_BUF_TYPE_A; + + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + + pr_debug("Enter:%s buf_id=%d, stream_type=%d\n", + __func__, buf_id, stream_type); + + snd_intelhad_handle_underrun(intelhaddata); + + if (drv_status == HAD_DRV_DISCONNECTED) { + pr_err("%s:Device already disconnected\n", __func__); + return 0; + } + + if (stream_type == HAD_RUNNING_STREAM) { + /* Report UNDERRUN error to above layers */ + intelhaddata->flag_underrun = 1; + stream->period_elapsed(stream->had_substream); + } + + return 0; +} + +static int had_process_hot_plug(struct snd_intelhad *intelhaddata) +{ + enum intel_had_aud_buf_type buf_id; + struct snd_pcm_substream *substream; + struct had_stream_data *had_stream; + unsigned long flag_irqs; + + pr_debug("Enter:%s\n", __func__); + + substream = intelhaddata->stream_info.had_substream; + had_stream = &intelhaddata->stream_data; + + spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + if (intelhaddata->drv_status == HAD_DRV_CONNECTED) { + pr_debug("Device already connected\n"); + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + return 0; + } + buf_id = intelhaddata->curr_buf; + intelhaddata->buff_done = buf_id; + intelhaddata->drv_status = HAD_DRV_CONNECTED; + pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_CONNECTED\n", + __func__, __LINE__); + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + + pr_debug("Processing HOT_PLUG, buf_id = %d\n", buf_id); + + /* Safety check */ + if (substream) { + pr_debug("There should not be active PB from ALSA\n"); + pr_debug("Signifies, cable is plugged-in even before\n"); + pr_debug("processing snd_pcm_disconnect\n"); + /* Set runtime->state to hw_params done */ + snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); + } + + had_build_channel_allocation_map(intelhaddata); + + return 0; +} + +static int had_process_hot_unplug(struct snd_intelhad *intelhaddata) +{ + enum intel_had_aud_buf_type buf_id; + struct had_stream_data *had_stream; + unsigned long flag_irqs; + + pr_debug("Enter:%s\n", __func__); + + had_stream = &intelhaddata->stream_data; + buf_id = intelhaddata->curr_buf; + + spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + + if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { + pr_debug("Device already disconnected\n"); + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + return 0; + + } else { + /* Disable Audio */ + snd_intelhad_enable_audio_int(intelhaddata, false); + snd_intelhad_enable_audio(intelhaddata, false); + } + + intelhaddata->drv_status = HAD_DRV_DISCONNECTED; + pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", + __func__, __LINE__); + + /* Report to above ALSA layer */ + if (intelhaddata->stream_info.had_substream != NULL) { + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + pr_debug("%s: unlock -> sending pcm_stop -> lock\n", __func__); + snd_pcm_stop(intelhaddata->stream_info.had_substream, + SNDRV_PCM_STATE_SETUP); + spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + } + + had_stream->stream_type = HAD_INIT; + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + kfree(intelhaddata->chmap->chmap); + intelhaddata->chmap->chmap = NULL; + intelhaddata->audio_reg_base = NULL; + pr_debug("%s: unlocked -> returned\n", __func__); + + return 0; +} + +/* PCM operations structure and the calls back for the same */ +static struct snd_pcm_ops snd_intelhad_playback_ops = { .open = snd_intelhad_open, .close = snd_intelhad_close, .ioctl = snd_pcm_lib_ioctl, @@ -1472,7 +1829,7 @@ struct snd_pcm_ops snd_intelhad_playback_ops = { .mmap = snd_intelhad_pcm_mmap, }; -/** +/* * snd_intelhad_pcm_free - to free the memory allocated * * @pcm: pointer to pcm instance @@ -1505,6 +1862,7 @@ static int had_iec958_get(struct snd_kcontrol *kcontrol, (intelhaddata->aes_bits >> 24) & 0xff; return 0; } + static int had_iec958_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1514,6 +1872,7 @@ static int had_iec958_mask_get(struct snd_kcontrol *kcontrol, ucontrol->value.iec958.status[3] = 0xff; return 0; } + static int had_iec958_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 6efa846f98c9..d301c3021375 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -154,35 +154,4 @@ struct snd_intelhad { struct work_struct hdmi_audio_wq; }; -int hdmi_lpe_audio_suspend(struct platform_device *pdev, pm_message_t state); -int hdmi_lpe_audio_resume(struct platform_device *pdev); -extern struct snd_pcm_ops snd_intelhad_playback_ops; - -int had_process_buffer_done(struct snd_intelhad *intelhaddata); -int had_process_buffer_underrun(struct snd_intelhad *intelhaddata); -int had_process_hot_plug(struct snd_intelhad *intelhaddata); -int had_process_hot_unplug(struct snd_intelhad *intelhaddata); - -int snd_intelhad_init_audio_ctrl(struct snd_pcm_substream *substream, - struct snd_intelhad *intelhaddata, - int flag_silence); -int snd_intelhad_prog_buffer(struct snd_intelhad *intelhaddata, - int start, int end); -int snd_intelhad_invd_buffer(int start, int end); -int snd_intelhad_read_len(struct snd_intelhad *intelhaddata); -void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata); - -void snd_intelhad_enable_audio_int(struct snd_intelhad *ctx, bool enable); -void snd_intelhad_enable_audio(struct snd_intelhad *ctx, bool enable); -void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata); - -/* Register access functions */ -int had_get_hwstate(struct snd_intelhad *intelhaddata); -int had_read_register(struct snd_intelhad *intelhaddata, - u32 reg_addr, u32 *data); -int had_write_register(struct snd_intelhad *intelhaddata, - u32 reg_addr, u32 data); -int had_read_modify(struct snd_intelhad *intelhaddata, - u32 reg_addr, u32 data, u32 mask); - #endif /* _INTEL_HDMI_AUDIO_ */ diff --git a/sound/x86/intel_hdmi_audio_if.c b/sound/x86/intel_hdmi_audio_if.c deleted file mode 100644 index 327650dd1723..000000000000 --- a/sound/x86/intel_hdmi_audio_if.c +++ /dev/null @@ -1,390 +0,0 @@ -/* - * intel_hdmi_audio_if.c - Intel HDMI audio driver for MID - * - * Copyright (C) 2016 Intel Corp - * Authors: Sailaja Bandarupalli - * Ramesh Babu K V - * Vaibhav Agarwal - * Jerome Anand - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * ALSA driver for Intel MID HDMI audio controller. This file contains - * interface functions exposed to HDMI Display driver and code to register - * with ALSA framework.. - */ - -#define pr_fmt(fmt) "had: " fmt - -#include -#include -#include -#include -#include -#include "intel_hdmi_audio.h" -#include "intel_hdmi_lpe_audio.h" - -/* - * hdmi_lpe_audio_suspend - power management suspend function - * - * @pdev: platform device - * - * This function is called by client driver to suspend the - * hdmi audio. - */ -int hdmi_lpe_audio_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct had_stream_data *had_stream; - unsigned long flag_irqs; - struct snd_pcm_substream *substream; - struct snd_intelhad *intelhaddata = platform_get_drvdata(pdev); - - pr_debug("Enter:%s\n", __func__); - - had_stream = &intelhaddata->stream_data; - substream = intelhaddata->stream_info.had_substream; - - if (intelhaddata->dev->power.runtime_status != RPM_SUSPENDED) { - pr_err("audio stream is active\n"); - return -EAGAIN; - } - - - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - pr_debug("had not connected\n"); - return 0; - } - - if (intelhaddata->drv_status == HAD_DRV_SUSPENDED) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - pr_debug("had already suspended\n"); - return 0; - } - - intelhaddata->drv_status = HAD_DRV_SUSPENDED; - pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_SUSPENDED\n", - __func__, __LINE__); - - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - snd_intelhad_enable_audio_int(intelhaddata, false); - pr_debug("Exit:%s", __func__); - return 0; -} - -/* - * hdmi_lpe_audio_resume - power management resume function - * - *@pdev: platform device - * - * This function is called by client driver to resume the - * hdmi audio. - */ -int hdmi_lpe_audio_resume(struct platform_device *pdev) -{ - struct snd_intelhad *intelhaddata = platform_get_drvdata(pdev); - unsigned long flag_irqs; - - pr_debug("Enter:%s\n", __func__); - - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - pr_debug("had not connected\n"); - return 0; - } - - if (intelhaddata->drv_status != HAD_DRV_SUSPENDED) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - pr_err("had is not in suspended state\n"); - return 0; - } - - if (had_get_hwstate(intelhaddata)) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - pr_err("Failed to resume. Device not accessible\n"); - return -ENODEV; - } - - intelhaddata->drv_status = HAD_DRV_CONNECTED; - pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", - __func__, __LINE__); - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - snd_intelhad_enable_audio_int(intelhaddata, true); - pr_debug("Exit:%s", __func__); - return 0; -} - -static inline int had_chk_intrmiss(struct snd_intelhad *intelhaddata, - enum intel_had_aud_buf_type buf_id) -{ - int i, intr_count = 0; - enum intel_had_aud_buf_type buff_done; - u32 buf_size, buf_addr; - struct had_stream_data *had_stream; - unsigned long flag_irqs; - - had_stream = &intelhaddata->stream_data; - - buff_done = buf_id; - - intr_count = snd_intelhad_read_len(intelhaddata); - if (intr_count > 1) { - /* In case of active playback */ - pr_err("Driver detected %d missed buffer done interrupt(s)!!!!\n", - (intr_count - 1)); - if (intr_count > 3) - return intr_count; - - buf_id += (intr_count - 1); - /* Reprogram registers*/ - for (i = buff_done; i < buf_id; i++) { - int j = i % 4; - - buf_size = intelhaddata->buf_info[j].buf_size; - buf_addr = intelhaddata->buf_info[j].buf_addr; - had_write_register(intelhaddata, - AUD_BUF_A_LENGTH + - (j * HAD_REG_WIDTH), buf_size); - had_write_register(intelhaddata, - AUD_BUF_A_ADDR+(j * HAD_REG_WIDTH), - (buf_addr | BIT(0) | BIT(1))); - } - buf_id = buf_id % 4; - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); - intelhaddata->buff_done = buf_id; - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - } - - return intr_count; -} - -int had_process_buffer_done(struct snd_intelhad *intelhaddata) -{ - u32 len = 1; - enum intel_had_aud_buf_type buf_id; - enum intel_had_aud_buf_type buff_done; - struct pcm_stream_info *stream; - u32 buf_size; - struct had_stream_data *had_stream; - int intr_count; - enum had_status_stream stream_type; - unsigned long flag_irqs; - - had_stream = &intelhaddata->stream_data; - stream = &intelhaddata->stream_info; - intr_count = 1; - - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - pr_err("%s:Device already disconnected\n", __func__); - return 0; - } - buf_id = intelhaddata->curr_buf; - intelhaddata->buff_done = buf_id; - buff_done = intelhaddata->buff_done; - buf_size = intelhaddata->buf_info[buf_id].buf_size; - stream_type = had_stream->stream_type; - - pr_debug("Enter:%s buf_id=%d\n", __func__, buf_id); - - /* Every debug statement has an implication - * of ~5msec. Thus, avoid having >3 debug statements - * for each buffer_done handling. - */ - - /* Check for any intr_miss in case of active playback */ - if (had_stream->stream_type == HAD_RUNNING_STREAM) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - intr_count = had_chk_intrmiss(intelhaddata, buf_id); - if (!intr_count || (intr_count > 3)) { - pr_err("HAD SW state in non-recoverable!!! mode\n"); - pr_err("Already played stale data\n"); - return 0; - } - buf_id += (intr_count - 1); - buf_id = buf_id % 4; - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); - } - - intelhaddata->buf_info[buf_id].is_valid = true; - if (intelhaddata->valid_buf_cnt-1 == buf_id) { - if (had_stream->stream_type >= HAD_RUNNING_STREAM) - intelhaddata->curr_buf = HAD_BUF_TYPE_A; - } else - intelhaddata->curr_buf = buf_id + 1; - - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - - if (had_get_hwstate(intelhaddata)) { - pr_err("HDMI cable plugged-out\n"); - return 0; - } - - /*Reprogram the registers with addr and length*/ - had_write_register(intelhaddata, - AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH), - buf_size); - had_write_register(intelhaddata, - AUD_BUF_A_ADDR + (buf_id * HAD_REG_WIDTH), - intelhaddata->buf_info[buf_id].buf_addr | - BIT(0) | BIT(1)); - - had_read_register(intelhaddata, - AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH), - &len); - pr_debug("%s:Enabled buf[%d]\n", __func__, buf_id); - - /* In case of actual data, - * report buffer_done to above ALSA layer - */ - buf_size = intelhaddata->buf_info[buf_id].buf_size; - if (stream_type >= HAD_RUNNING_STREAM) { - intelhaddata->stream_info.buffer_rendered += - (intr_count * buf_size); - stream->period_elapsed(stream->had_substream); - } - - return 0; -} - -int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) -{ - enum intel_had_aud_buf_type buf_id; - struct pcm_stream_info *stream; - struct had_stream_data *had_stream; - enum had_status_stream stream_type; - unsigned long flag_irqs; - int drv_status; - - had_stream = &intelhaddata->stream_data; - stream = &intelhaddata->stream_info; - - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); - buf_id = intelhaddata->curr_buf; - stream_type = had_stream->stream_type; - intelhaddata->buff_done = buf_id; - drv_status = intelhaddata->drv_status; - if (stream_type == HAD_RUNNING_STREAM) - intelhaddata->curr_buf = HAD_BUF_TYPE_A; - - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - - pr_debug("Enter:%s buf_id=%d, stream_type=%d\n", - __func__, buf_id, stream_type); - - snd_intelhad_handle_underrun(intelhaddata); - - if (drv_status == HAD_DRV_DISCONNECTED) { - pr_err("%s:Device already disconnected\n", __func__); - return 0; - } - - if (stream_type == HAD_RUNNING_STREAM) { - /* Report UNDERRUN error to above layers */ - intelhaddata->flag_underrun = 1; - stream->period_elapsed(stream->had_substream); - } - - return 0; -} - -int had_process_hot_plug(struct snd_intelhad *intelhaddata) -{ - enum intel_had_aud_buf_type buf_id; - struct snd_pcm_substream *substream; - struct had_stream_data *had_stream; - unsigned long flag_irqs; - - pr_debug("Enter:%s\n", __func__); - - substream = intelhaddata->stream_info.had_substream; - had_stream = &intelhaddata->stream_data; - - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); - if (intelhaddata->drv_status == HAD_DRV_CONNECTED) { - pr_debug("Device already connected\n"); - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - return 0; - } - buf_id = intelhaddata->curr_buf; - intelhaddata->buff_done = buf_id; - intelhaddata->drv_status = HAD_DRV_CONNECTED; - pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_CONNECTED\n", - __func__, __LINE__); - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - - pr_debug("Processing HOT_PLUG, buf_id = %d\n", buf_id); - - /* Safety check */ - if (substream) { - pr_debug("There should not be active PB from ALSA\n"); - pr_debug("Signifies, cable is plugged-in even before\n"); - pr_debug("processing snd_pcm_disconnect\n"); - /* Set runtime->state to hw_params done */ - snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); - } - - had_build_channel_allocation_map(intelhaddata); - - return 0; -} - -int had_process_hot_unplug(struct snd_intelhad *intelhaddata) -{ - enum intel_had_aud_buf_type buf_id; - struct had_stream_data *had_stream; - unsigned long flag_irqs; - - pr_debug("Enter:%s\n", __func__); - - had_stream = &intelhaddata->stream_data; - buf_id = intelhaddata->curr_buf; - - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); - - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { - pr_debug("Device already disconnected\n"); - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - return 0; - - } else { - /* Disable Audio */ - snd_intelhad_enable_audio_int(intelhaddata, false); - snd_intelhad_enable_audio(intelhaddata, false); - } - - intelhaddata->drv_status = HAD_DRV_DISCONNECTED; - pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", - __func__, __LINE__); - - /* Report to above ALSA layer */ - if (intelhaddata->stream_info.had_substream != NULL) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - pr_debug("%s: unlock -> sending pcm_stop -> lock\n", __func__); - snd_pcm_stop(intelhaddata->stream_info.had_substream, - SNDRV_PCM_STATE_SETUP); - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); - } - - had_stream->stream_type = HAD_INIT; - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - kfree(intelhaddata->chmap->chmap); - intelhaddata->chmap->chmap = NULL; - intelhaddata->audio_reg_base = NULL; - pr_debug("%s: unlocked -> returned\n", __func__); - - return 0; -} - -- cgit v1.2.3 From c75b0476245ad01306e4ea510bb3f7591767079f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 15:49:15 +0100 Subject: ALSA: x86: Replace pr_xxx() with dev_xxx() dev_xxx() helpers give a tidier output in general. While we're at it, remove many useless debug prints (e.g. the ones at each function entry), replace some too verbose errors with debugs, and use WARN_ON() for some serious errors. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 205 ++++++++++++++++++------------------------- 1 file changed, 84 insertions(+), 121 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index effe93b58273..41105092c114 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -21,8 +21,6 @@ * ALSA driver for Intel HDMI audio */ -#define pr_fmt(fmt) "had: " fmt - #include #include #include @@ -160,11 +158,8 @@ static const struct snd_pcm_hardware snd_intel_hadstream = { static int had_get_hwstate(struct snd_intelhad *intelhaddata) { /* Check for device presence -SW state */ - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { - pr_debug("%s:Device not connected:%d\n", __func__, - intelhaddata->drv_status); + if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) return -ENODEV; - } return 0; } @@ -276,7 +271,8 @@ static int had_read_modify_aud_config_v2(struct snd_intelhad *intelhaddata, data = data | cfg_val.cfg_regval; mask = mask | AUD_CONFIG_CH_MASK_V2; - pr_debug("%s : data = %x, mask =%x\n", __func__, data, mask); + dev_dbg(intelhaddata->dev, "%s : data = %x, mask =%x\n", + __func__, data, mask); return had_read_modify(intelhaddata, AUD_CONFIG, data, mask); } @@ -318,8 +314,6 @@ static int had_prog_status_reg(struct snd_pcm_substream *substream, union aud_ch_status_1 ch_stat1 = {.status_1_regval = 0}; int format; - pr_debug("Entry %s\n", __func__); - ch_stat0.status_0_regx.lpcm_id = (intelhaddata->aes_bits & IEC958_AES0_NONAUDIO)>>1; ch_stat0.status_0_regx.clk_acc = (intelhaddata->aes_bits & @@ -415,8 +409,6 @@ static void init_channel_allocations(void) int i, j; struct cea_channel_speaker_allocation *p; - pr_debug("%s: Enter\n", __func__); - for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { p = channel_allocations + i; p->channels = 0; @@ -472,7 +464,7 @@ static int snd_intelhad_channel_allocation(struct snd_intelhad *intelhaddata, } } - pr_debug("HDMI: select CA 0x%x for %d\n", ca, channels); + dev_dbg(intelhaddata->dev, "select CA 0x%x for %d\n", ca, channels); return ca; } @@ -503,7 +495,7 @@ static void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata) return; } - pr_debug("eld.speaker_allocation_block = %x\n", + dev_dbg(intelhaddata->dev, "eld.speaker_allocation_block = %x\n", intelhaddata->eld.speaker_allocation_block); /* WA: Fix the max channel supported to 8 */ @@ -583,10 +575,8 @@ static int had_chmap_ctl_get(struct snd_kcontrol *kcontrol, if (intelhaddata->chmap->chmap == NULL) return -ENODATA; chmap = intelhaddata->chmap->chmap; - for (i = 0; i < chmap->channels; i++) { + for (i = 0; i < chmap->channels; i++) ucontrol->value.integer.value[i] = chmap->map[i]; - pr_debug("chmap->map[%d] = %d\n", i, chmap->map[i]); - } return 0; } @@ -684,11 +674,8 @@ static int snd_intelhad_prog_buffer(struct snd_intelhad *intelhaddata, struct snd_pcm_substream *substream; substream = intelhaddata->stream_info.had_substream; - if (!substream) { - pr_err("substream is NULL\n"); - dump_stack(); + if (WARN_ON(!substream)) return 0; - } ring_buf_addr = substream->runtime->dma_addr; ring_buf_size = snd_pcm_lib_buffer_bytes(substream); @@ -726,9 +713,10 @@ static int snd_intelhad_prog_buffer(struct snd_intelhad *intelhaddata, period_bytes); intelhaddata->buf_info[i].is_valid = true; } - pr_debug("%s:buf[%d-%d] addr=%#x and size=%d\n", __func__, start, end, - intelhaddata->buf_info[start].buf_addr, - intelhaddata->buf_info[start].buf_size); + dev_dbg(intelhaddata->dev, "%s:buf[%d-%d] addr=%#x and size=%d\n", + __func__, start, end, + intelhaddata->buf_info[start].buf_addr, + intelhaddata->buf_info[start].buf_size); intelhaddata->valid_buf_cnt = num_periods; return 0; } @@ -747,7 +735,8 @@ static int snd_intelhad_read_len(struct snd_intelhad *intelhaddata) } if (retval != 1) { for (i = 0; i < 4 ; i++) - pr_debug("buf[%d] size=%d\n", i, len[i]); + dev_dbg(intelhaddata->dev, "buf[%d] size=%d\n", + i, len[i]); } return retval; @@ -858,7 +847,7 @@ static void snd_intelhad_prog_cts(u32 aud_samp_freq, u32 tmds, divisor = 128 * aud_samp_freq; cts_val = div64_u64(dividend, divisor); } - pr_debug("TMDS value=%d, N value=%d, CTS Value=%d\n", + dev_dbg(intelhaddata->dev, "TMDS value=%d, N value=%d, CTS Value=%d\n", tmds, n_param, cts_val); had_write_register(intelhaddata, AUD_HDMI_CTS, (BIT(24) | cts_val)); } @@ -956,7 +945,7 @@ static void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata) do { /* clear bit30, 31 AUD_HDMI_STATUS */ had_read_register(intelhaddata, AUD_HDMI_STATUS_v2, &hdmi_status); - pr_debug("HDMI status =0x%x\n", hdmi_status); + dev_dbg(intelhaddata->dev, "HDMI status =0x%x\n", hdmi_status); if (hdmi_status & AUD_CONFIG_MASK_UNDERRUN) { i++; had_write_register(intelhaddata, @@ -965,7 +954,7 @@ static void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata) break; } while (i < MAX_CNT); if (i >= MAX_CNT) - pr_err("Unable to clear UNDERRUN bits\n"); + dev_err(intelhaddata->dev, "Unable to clear UNDERRUN bits\n"); } /** @@ -982,7 +971,6 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) struct had_stream_data *had_stream; int retval; - pr_debug("snd_intelhad_open called\n"); intelhaddata = snd_pcm_substream_chip(substream); had_stream = &intelhaddata->stream_data; runtime = substream->runtime; @@ -991,14 +979,15 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) pm_runtime_get(intelhaddata->dev); if (had_get_hwstate(intelhaddata)) { - pr_err("%s: HDMI cable plugged-out\n", __func__); + dev_dbg(intelhaddata->dev, "%s: HDMI cable plugged-out\n", + __func__); retval = -ENODEV; goto exit_put_handle; } /* Check, if device already in use */ if (runtime->private_data) { - pr_err("Device already in use\n"); + dev_dbg(intelhaddata->dev, "Device already in use\n"); retval = -EBUSY; goto exit_put_handle; } @@ -1025,7 +1014,8 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) retval = snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64); if (retval < 0) { - pr_err("%s:step_size=64 failed,err=%d\n", __func__, retval); + dev_dbg(intelhaddata->dev, "%s:step_size=64 failed,err=%d\n", + __func__, retval); goto exit_err; } @@ -1048,8 +1038,6 @@ static void had_period_elapsed(void *had_substream) struct snd_pcm_substream *substream = had_substream; struct had_stream_pvt *stream; - /* pr_debug("had_period_elapsed called\n"); */ - if (!substream || !substream->runtime) return; stream = substream->runtime->private_data; @@ -1070,9 +1058,6 @@ static int snd_intelhad_init_stream(struct snd_pcm_substream *substream) { struct snd_intelhad *intelhaddata = snd_pcm_substream_chip(substream); - pr_debug("snd_intelhad_init_stream called\n"); - - pr_debug("setting buffer ptr param\n"); intelhaddata->stream_info.period_elapsed = had_period_elapsed; intelhaddata->stream_info.had_substream = substream; intelhaddata->stream_info.buffer_ptr = 0; @@ -1093,15 +1078,11 @@ static int snd_intelhad_close(struct snd_pcm_substream *substream) struct snd_intelhad *intelhaddata; struct snd_pcm_runtime *runtime; - pr_debug("snd_intelhad_close called\n"); - intelhaddata = snd_pcm_substream_chip(substream); runtime = substream->runtime; - if (!runtime->private_data) { - pr_debug("close() might have called after failed open"); + if (WARN_ON(!runtime->private_data)) return 0; - } intelhaddata->stream_info.buffer_rendered = 0; intelhaddata->stream_info.buffer_ptr = 0; @@ -1111,7 +1092,8 @@ static int snd_intelhad_close(struct snd_pcm_substream *substream) /* Check if following drv_status modification is required - VA */ if (intelhaddata->drv_status != HAD_DRV_DISCONNECTED) { intelhaddata->drv_status = HAD_DRV_CONNECTED; - pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_CONNECTED\n", + dev_dbg(intelhaddata->dev, + "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_CONNECTED\n", __func__, __LINE__); } kfree(runtime->private_data); @@ -1132,25 +1114,27 @@ static int snd_intelhad_close(struct snd_pcm_substream *substream) static int snd_intelhad_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { + struct snd_intelhad *intelhaddata; unsigned long addr; int pages, buf_size, retval; - pr_debug("snd_intelhad_hw_params called\n"); - if (!hw_params) return -EINVAL; + intelhaddata = snd_pcm_substream_chip(substream); buf_size = params_buffer_bytes(hw_params); retval = snd_pcm_lib_malloc_pages(substream, buf_size); if (retval < 0) return retval; - pr_debug("%s:allocated memory = %d\n", __func__, buf_size); + dev_dbg(intelhaddata->dev, "%s:allocated memory = %d\n", + __func__, buf_size); /* mark the pages as uncached region */ addr = (unsigned long) substream->runtime->dma_area; pages = (substream->runtime->dma_bytes + PAGE_SIZE - 1) / PAGE_SIZE; retval = set_memory_uc(addr, pages); if (retval) { - pr_err("set_memory_uc failed.Error:%d\n", retval); + dev_err(intelhaddata->dev, "set_memory_uc failed.Error:%d\n", + retval); return retval; } memset(substream->runtime->dma_area, 0, buf_size); @@ -1172,8 +1156,6 @@ static int snd_intelhad_hw_free(struct snd_pcm_substream *substream) unsigned long addr; u32 pages; - pr_debug("snd_intelhad_hw_free called\n"); - /* mark back the pages as cached/writeback region before the free */ if (substream->runtime->dma_area != NULL) { addr = (unsigned long) substream->runtime->dma_area; @@ -1200,19 +1182,16 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, struct had_stream_pvt *stream; struct had_stream_data *had_stream; - pr_debug("snd_intelhad_pcm_trigger called\n"); - intelhaddata = snd_pcm_substream_chip(substream); stream = substream->runtime->private_data; had_stream = &intelhaddata->stream_data; switch (cmd) { case SNDRV_PCM_TRIGGER_START: - pr_debug("Trigger Start\n"); - /* Disable local INTRs till register prgmng is done */ if (had_get_hwstate(intelhaddata)) { - pr_err("_START: HDMI cable plugged-out\n"); + dev_dbg(intelhaddata->dev, + "_START: HDMI cable plugged-out\n"); retval = -ENODEV; break; } @@ -1223,18 +1202,14 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, /* Enable Audio */ snd_intelhad_enable_audio_int(intelhaddata, true); snd_intelhad_enable_audio(intelhaddata, true); - - pr_debug("Processed _Start\n"); - break; case SNDRV_PCM_TRIGGER_STOP: - pr_debug("Trigger Stop\n"); spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irq); intelhaddata->stream_info.str_id = 0; intelhaddata->curr_buf = 0; - /* Stop reporting BUFFER_DONE/UNDERRUN to above layers*/ + /* Stop reporting BUFFER_DONE/UNDERRUN to above layers */ had_stream->stream_type = HAD_INIT; spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irq); @@ -1270,27 +1245,28 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime; struct had_stream_data *had_stream; - pr_debug("snd_intelhad_pcm_prepare called\n"); - intelhaddata = snd_pcm_substream_chip(substream); runtime = substream->runtime; had_stream = &intelhaddata->stream_data; if (had_get_hwstate(intelhaddata)) { - pr_err("%s: HDMI cable plugged-out\n", __func__); + dev_dbg(intelhaddata->dev, "%s: HDMI cable plugged-out\n", + __func__); retval = -ENODEV; goto prep_end; } - pr_debug("period_size=%d\n", + dev_dbg(intelhaddata->dev, "period_size=%d\n", (int)frames_to_bytes(runtime, runtime->period_size)); - pr_debug("periods=%d\n", runtime->periods); - pr_debug("buffer_size=%d\n", (int)snd_pcm_lib_buffer_bytes(substream)); - pr_debug("rate=%d\n", runtime->rate); - pr_debug("channels=%d\n", runtime->channels); + dev_dbg(intelhaddata->dev, "periods=%d\n", runtime->periods); + dev_dbg(intelhaddata->dev, "buffer_size=%d\n", + (int)snd_pcm_lib_buffer_bytes(substream)); + dev_dbg(intelhaddata->dev, "rate=%d\n", runtime->rate); + dev_dbg(intelhaddata->dev, "channels=%d\n", runtime->channels); if (intelhaddata->stream_info.str_id) { - pr_debug("_prepare is called for existing str_id#%d\n", + dev_dbg(intelhaddata->dev, + "_prepare is called for existing str_id#%d\n", intelhaddata->stream_info.str_id); retval = snd_intelhad_pcm_trigger(substream, SNDRV_PCM_TRIGGER_STOP); @@ -1308,7 +1284,8 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) retval = snd_intelhad_prog_n(substream->runtime->rate, &n_param, intelhaddata); if (retval) { - pr_err("programming N value failed %#x\n", retval); + dev_err(intelhaddata->dev, + "programming N value failed %#x\n", retval); goto prep_end; } @@ -1354,8 +1331,6 @@ static snd_pcm_uframes_t snd_intelhad_pcm_pointer( u32 t; int buf_id; - /* pr_debug("snd_intelhad_pcm_pointer called\n"); */ - intelhaddata = snd_pcm_substream_chip(substream); if (intelhaddata->flag_underrun) { @@ -1373,11 +1348,13 @@ static snd_pcm_uframes_t snd_intelhad_pcm_pointer( if ((t == 0) || (t == ((u32)-1L))) { intelhaddata->underrun_count++; - pr_debug("discovered buffer done for buf %d, count = %d\n", + dev_dbg(intelhaddata->dev, + "discovered buffer done for buf %d, count = %d\n", buf_id, intelhaddata->underrun_count); if (intelhaddata->underrun_count > (HAD_MIN_PERIODS/2)) { - pr_debug("assume audio_codec_reset, underrun = %d - do xrun\n", + dev_dbg(intelhaddata->dev, + "assume audio_codec_reset, underrun = %d - do xrun\n", intelhaddata->underrun_count); intelhaddata->underrun_count = 0; return SNDRV_PCM_POS_XRUN; @@ -1412,10 +1389,6 @@ static snd_pcm_uframes_t snd_intelhad_pcm_pointer( static int snd_intelhad_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) { - - pr_debug("snd_intelhad_pcm_mmap called\n"); - - pr_debug("entry with prot:%s\n", __func__); vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); return remap_pfn_range(vma, vma->vm_start, substream->dma_buffer.addr >> PAGE_SHIFT, @@ -1442,7 +1415,8 @@ static int hdmi_audio_mode_change(struct snd_intelhad *intelhaddata) retval = snd_intelhad_prog_n(substream->runtime->rate, &n_param, intelhaddata); if (retval) { - pr_err("programming N value failed %#x\n", retval); + dev_err(intelhaddata->dev, + "programming N value failed %#x\n", retval); goto out; } @@ -1476,13 +1450,11 @@ static int hdmi_lpe_audio_suspend(struct platform_device *pdev, struct snd_pcm_substream *substream; struct snd_intelhad *intelhaddata = platform_get_drvdata(pdev); - pr_debug("Enter:%s\n", __func__); - had_stream = &intelhaddata->stream_data; substream = intelhaddata->stream_info.had_substream; if (intelhaddata->dev->power.runtime_status != RPM_SUSPENDED) { - pr_err("audio stream is active\n"); + dev_err(intelhaddata->dev, "audio stream is active\n"); return -EAGAIN; } @@ -1490,23 +1462,23 @@ static int hdmi_lpe_audio_suspend(struct platform_device *pdev, spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - pr_debug("had not connected\n"); + dev_dbg(intelhaddata->dev, "had not connected\n"); return 0; } if (intelhaddata->drv_status == HAD_DRV_SUSPENDED) { spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - pr_debug("had already suspended\n"); + dev_dbg(intelhaddata->dev, "had already suspended\n"); return 0; } intelhaddata->drv_status = HAD_DRV_SUSPENDED; - pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_SUSPENDED\n", + dev_dbg(intelhaddata->dev, + "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_SUSPENDED\n", __func__, __LINE__); spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); snd_intelhad_enable_audio_int(intelhaddata, false); - pr_debug("Exit:%s", __func__); return 0; } @@ -1523,33 +1495,32 @@ static int hdmi_lpe_audio_resume(struct platform_device *pdev) struct snd_intelhad *intelhaddata = platform_get_drvdata(pdev); unsigned long flag_irqs; - pr_debug("Enter:%s\n", __func__); - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - pr_debug("had not connected\n"); + dev_dbg(intelhaddata->dev, "had not connected\n"); return 0; } if (intelhaddata->drv_status != HAD_DRV_SUSPENDED) { spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - pr_err("had is not in suspended state\n"); + dev_err(intelhaddata->dev, "had is not in suspended state\n"); return 0; } if (had_get_hwstate(intelhaddata)) { spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - pr_err("Failed to resume. Device not accessible\n"); + dev_err(intelhaddata->dev, + "Failed to resume. Device not accessible\n"); return -ENODEV; } intelhaddata->drv_status = HAD_DRV_CONNECTED; - pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", + dev_dbg(intelhaddata->dev, + "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", __func__, __LINE__); spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); snd_intelhad_enable_audio_int(intelhaddata, true); - pr_debug("Exit:%s", __func__); return 0; } @@ -1569,8 +1540,9 @@ static inline int had_chk_intrmiss(struct snd_intelhad *intelhaddata, intr_count = snd_intelhad_read_len(intelhaddata); if (intr_count > 1) { /* In case of active playback */ - pr_err("Driver detected %d missed buffer done interrupt(s)!!!!\n", - (intr_count - 1)); + dev_err(intelhaddata->dev, + "Driver detected %d missed buffer done interrupt(s)\n", + (intr_count - 1)); if (intr_count > 3) return intr_count; @@ -1616,7 +1588,8 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - pr_err("%s:Device already disconnected\n", __func__); + dev_dbg(intelhaddata->dev, + "%s:Device already disconnected\n", __func__); return 0; } buf_id = intelhaddata->curr_buf; @@ -1625,8 +1598,6 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) buf_size = intelhaddata->buf_info[buf_id].buf_size; stream_type = had_stream->stream_type; - pr_debug("Enter:%s buf_id=%d\n", __func__, buf_id); - /* Every debug statement has an implication * of ~5msec. Thus, avoid having >3 debug statements * for each buffer_done handling. @@ -1637,8 +1608,8 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); intr_count = had_chk_intrmiss(intelhaddata, buf_id); if (!intr_count || (intr_count > 3)) { - pr_err("HAD SW state in non-recoverable!!! mode\n"); - pr_err("Already played stale data\n"); + dev_err(intelhaddata->dev, + "HAD SW state in non-recoverable mode\n"); return 0; } buf_id += (intr_count - 1); @@ -1656,7 +1627,7 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); if (had_get_hwstate(intelhaddata)) { - pr_err("HDMI cable plugged-out\n"); + dev_dbg(intelhaddata->dev, "HDMI cable plugged-out\n"); return 0; } @@ -1672,7 +1643,7 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) had_read_register(intelhaddata, AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH), &len); - pr_debug("%s:Enabled buf[%d]\n", __func__, buf_id); + dev_dbg(intelhaddata->dev, "%s:Enabled buf[%d]\n", __func__, buf_id); /* In case of actual data, * report buffer_done to above ALSA layer @@ -1709,13 +1680,14 @@ static int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - pr_debug("Enter:%s buf_id=%d, stream_type=%d\n", + dev_dbg(intelhaddata->dev, "Enter:%s buf_id=%d, stream_type=%d\n", __func__, buf_id, stream_type); snd_intelhad_handle_underrun(intelhaddata); if (drv_status == HAD_DRV_DISCONNECTED) { - pr_err("%s:Device already disconnected\n", __func__); + dev_dbg(intelhaddata->dev, + "%s:Device already disconnected\n", __func__); return 0; } @@ -1735,31 +1707,30 @@ static int had_process_hot_plug(struct snd_intelhad *intelhaddata) struct had_stream_data *had_stream; unsigned long flag_irqs; - pr_debug("Enter:%s\n", __func__); - substream = intelhaddata->stream_info.had_substream; had_stream = &intelhaddata->stream_data; spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); if (intelhaddata->drv_status == HAD_DRV_CONNECTED) { - pr_debug("Device already connected\n"); + dev_dbg(intelhaddata->dev, "Device already connected\n"); spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); return 0; } buf_id = intelhaddata->curr_buf; intelhaddata->buff_done = buf_id; intelhaddata->drv_status = HAD_DRV_CONNECTED; - pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_CONNECTED\n", + dev_dbg(intelhaddata->dev, + "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_CONNECTED\n", __func__, __LINE__); spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - pr_debug("Processing HOT_PLUG, buf_id = %d\n", buf_id); + dev_dbg(intelhaddata->dev, "Processing HOT_PLUG, buf_id = %d\n", + buf_id); /* Safety check */ if (substream) { - pr_debug("There should not be active PB from ALSA\n"); - pr_debug("Signifies, cable is plugged-in even before\n"); - pr_debug("processing snd_pcm_disconnect\n"); + dev_dbg(intelhaddata->dev, + "Force to stop the active stream by disconnection\n"); /* Set runtime->state to hw_params done */ snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); } @@ -1775,15 +1746,13 @@ static int had_process_hot_unplug(struct snd_intelhad *intelhaddata) struct had_stream_data *had_stream; unsigned long flag_irqs; - pr_debug("Enter:%s\n", __func__); - had_stream = &intelhaddata->stream_data; buf_id = intelhaddata->curr_buf; spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { - pr_debug("Device already disconnected\n"); + dev_dbg(intelhaddata->dev, "Device already disconnected\n"); spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); return 0; @@ -1794,13 +1763,13 @@ static int had_process_hot_unplug(struct snd_intelhad *intelhaddata) } intelhaddata->drv_status = HAD_DRV_DISCONNECTED; - pr_debug("%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", + dev_dbg(intelhaddata->dev, + "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", __func__, __LINE__); /* Report to above ALSA layer */ if (intelhaddata->stream_info.had_substream != NULL) { spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - pr_debug("%s: unlock -> sending pcm_stop -> lock\n", __func__); snd_pcm_stop(intelhaddata->stream_info.had_substream, SNDRV_PCM_STATE_SETUP); spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); @@ -1811,7 +1780,6 @@ static int had_process_hot_unplug(struct snd_intelhad *intelhaddata) kfree(intelhaddata->chmap->chmap); intelhaddata->chmap->chmap = NULL; intelhaddata->audio_reg_base = NULL; - pr_debug("%s: unlocked -> returned\n", __func__); return 0; } @@ -1837,7 +1805,6 @@ static struct snd_pcm_ops snd_intelhad_playback_ops = { */ static void snd_intelhad_pcm_free(struct snd_pcm *pcm) { - pr_debug("Freeing PCM preallocated pages\n"); snd_pcm_lib_preallocate_free_for_all(pcm); } @@ -1879,7 +1846,6 @@ static int had_iec958_put(struct snd_kcontrol *kcontrol, unsigned int val; struct snd_intelhad *intelhaddata = snd_kcontrol_chip(kcontrol); - pr_debug("entered had_iec958_put\n"); val = (ucontrol->value.iec958.status[0] << 0) | (ucontrol->value.iec958.status[1] << 8) | (ucontrol->value.iec958.status[2] << 16) | @@ -2024,7 +1990,6 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) int ret; unsigned long flags; - dev_dbg(&pdev->dev, "Enter %s\n", __func__); dev_dbg(&pdev->dev, "dma_mask: %p\n", pdev->dev.dma_mask); pdata = pdev->dev.platform_data; @@ -2170,8 +2135,6 @@ static int hdmi_lpe_audio_remove(struct platform_device *pdev) { struct snd_intelhad *ctx = platform_get_drvdata(pdev); - dev_dbg(&pdev->dev, "Enter %s\n", __func__); - if (ctx->drv_status != HAD_DRV_DISCONNECTED) snd_intelhad_enable_audio_int(ctx, false); snd_card_free(ctx->card); -- cgit v1.2.3 From e29c0f967261b0f6a95e05a224341be8f59df2d5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 1 Feb 2017 17:27:48 +0100 Subject: ALSA: x86: Fix for CONFIG_PM=n The direct access to power.runtime_status is taboo, let's use a helper macro to avoid the compile error with CONFIG_PM=n. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 41105092c114..fbfbf5e2b5ad 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1453,7 +1453,7 @@ static int hdmi_lpe_audio_suspend(struct platform_device *pdev, had_stream = &intelhaddata->stream_data; substream = intelhaddata->stream_info.had_substream; - if (intelhaddata->dev->power.runtime_status != RPM_SUSPENDED) { + if (!pm_runtime_status_suspended(intelhaddata->dev)) { dev_err(intelhaddata->dev, "audio stream is active\n"); return -EAGAIN; } -- cgit v1.2.3 From df76df12f178642cac616b86a762d2ee749fe402 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 16:04:10 +0100 Subject: ALSA: x86: Remove indirect call of snd_pcm_period_elapsed() Again another indirect call... Let's straighten it up. Also define the had_stream field with a proper type instead of a void pointer. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 15 ++++++--------- sound/x86/intel_hdmi_audio.h | 3 +-- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index fbfbf5e2b5ad..8b25687601ac 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1028,14 +1028,12 @@ exit_put_handle: return retval; } -/** +/* * had_period_elapsed - updates the hardware pointer status - * @had_substream:substream for which the stream function is called - * + * @had_substream: substream for which the stream function is called */ -static void had_period_elapsed(void *had_substream) +static void had_period_elapsed(struct snd_pcm_substream *substream) { - struct snd_pcm_substream *substream = had_substream; struct had_stream_pvt *stream; if (!substream || !substream->runtime) @@ -1058,7 +1056,6 @@ static int snd_intelhad_init_stream(struct snd_pcm_substream *substream) { struct snd_intelhad *intelhaddata = snd_pcm_substream_chip(substream); - intelhaddata->stream_info.period_elapsed = had_period_elapsed; intelhaddata->stream_info.had_substream = substream; intelhaddata->stream_info.buffer_ptr = 0; intelhaddata->stream_info.buffer_rendered = 0; @@ -1648,11 +1645,11 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) /* In case of actual data, * report buffer_done to above ALSA layer */ - buf_size = intelhaddata->buf_info[buf_id].buf_size; + buf_size = intelhaddata->buf_info[buf_id].buf_size; if (stream_type >= HAD_RUNNING_STREAM) { intelhaddata->stream_info.buffer_rendered += (intr_count * buf_size); - stream->period_elapsed(stream->had_substream); + had_period_elapsed(stream->had_substream); } return 0; @@ -1694,7 +1691,7 @@ static int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) if (stream_type == HAD_RUNNING_STREAM) { /* Report UNDERRUN error to above layers */ intelhaddata->flag_underrun = 1; - stream->period_elapsed(stream->had_substream); + had_period_elapsed(stream->had_substream); } return 0; diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index d301c3021375..bcbb4b262fff 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -75,8 +75,7 @@ struct platform_device; struct pcm_stream_info { int str_id; - void *had_substream; - void (*period_elapsed)(void *had_substream); + struct snd_pcm_substream *had_substream; u32 buffer_ptr; u64 buffer_rendered; u32 ring_buf_size; -- cgit v1.2.3 From e9d65abfa63fad3da372a3852dcade88b5506f4c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 16:11:27 +0100 Subject: ALSA: x86: Drop unused fields from snd_intelhad struct Also change the flag_underrun to bool to be clearer. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 14 +++++--------- sound/x86/intel_hdmi_audio.h | 14 +------------- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 8b25687601ac..0a14f5dacb00 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -593,9 +593,8 @@ static int had_register_chmap_ctls(struct snd_intelhad *intelhaddata, return err; intelhaddata->chmap->private_data = intelhaddata; - intelhaddata->kctl = intelhaddata->chmap->kctl; - intelhaddata->kctl->info = had_chmap_ctl_info; - intelhaddata->kctl->get = had_chmap_ctl_get; + intelhaddata->chmap->kctl->info = had_chmap_ctl_info; + intelhaddata->chmap->kctl->get = had_chmap_ctl_get; intelhaddata->chmap->chmap = NULL; return 0; } @@ -1331,7 +1330,7 @@ static snd_pcm_uframes_t snd_intelhad_pcm_pointer( intelhaddata = snd_pcm_substream_chip(substream); if (intelhaddata->flag_underrun) { - intelhaddata->flag_underrun = 0; + intelhaddata->flag_underrun = false; return SNDRV_PCM_POS_XRUN; } @@ -1690,7 +1689,7 @@ static int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) if (stream_type == HAD_RUNNING_STREAM) { /* Report UNDERRUN error to above layers */ - intelhaddata->flag_underrun = 1; + intelhaddata->flag_underrun = true; had_period_elapsed(stream->had_substream); } @@ -1776,7 +1775,6 @@ static int had_process_hot_unplug(struct snd_intelhad *intelhaddata) spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); kfree(intelhaddata->chmap->chmap); intelhaddata->chmap->chmap = NULL; - intelhaddata->audio_reg_base = NULL; return 0; } @@ -2019,9 +2017,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) ctx->drv_status = HAD_DRV_DISCONNECTED; ctx->dev = &pdev->dev; ctx->card = card; - ctx->card_id = hdmi_card_id; - ctx->card_index = card->number; - ctx->flag_underrun = 0; + ctx->flag_underrun = false; ctx->aes_bits = SNDRV_PCM_DEFAULT_CON_SPDIF; strcpy(card->driver, INTEL_HAD); strcpy(card->shortname, INTEL_HAD); diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index bcbb4b262fff..4549c4d9d650 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -39,8 +39,6 @@ #include #include "intel_hdmi_lpe_audio.h" -struct platform_device; - #define PCM_INDEX 0 #define MAX_PB_STREAMS 1 #define MAX_CAP_STREAMS 0 @@ -102,8 +100,6 @@ struct had_stream_data { * struct snd_intelhad - intelhad driver structure * * @card: ptr to hold card details - * @card_index: sound card index - * @card_id: detected sound card id * @drv_status: driver status * @buf_info: ring buffer info * @stream_info: stream information @@ -114,15 +110,11 @@ struct had_stream_data { * @aes_bits: IEC958 status bits * @buff_done: id of current buffer done intr * @dev: platoform device handle - * @kctl: holds kctl ptrs used for channel map * @chmap: holds channel map info - * @audio_reg_base: hdmi audio register base offset * @underrun_count: PCM stream underrun counter */ struct snd_intelhad { struct snd_card *card; - int card_index; - char *card_id; enum had_drv_status drv_status; struct ring_buf_info buf_info[HAD_NUM_OF_RING_BUFS]; struct pcm_stream_info stream_info; @@ -131,15 +123,12 @@ struct snd_intelhad { enum intel_had_aud_buf_type curr_buf; int valid_buf_cnt; unsigned int aes_bits; - int flag_underrun; + bool flag_underrun; struct had_stream_data stream_data; spinlock_t had_spinlock; enum intel_had_aud_buf_type buff_done; struct device *dev; - struct snd_kcontrol *kctl; struct snd_pcm_chmap *chmap; - unsigned int *audio_reg_base; - unsigned int audio_cfg_offset; int underrun_count; enum hdmi_connector_status state; int tmds_clock_speed; @@ -149,7 +138,6 @@ struct snd_intelhad { int irq; void __iomem *mmio_start; unsigned int had_config_offset; - int hdmi_audio_interrupt_mask; struct work_struct hdmi_audio_wq; }; -- cgit v1.2.3 From f6a82a0c01e51dd494b6eb68861473368355e58b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 16:17:14 +0100 Subject: ALSA: x86: Drop superfluous PCM private_free snd_pcm_lib_preallocate_free_for_all() doesn't have to be called from each driver as it's called in the PCM core. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 0a14f5dacb00..28eb980d2d2e 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1792,17 +1792,6 @@ static struct snd_pcm_ops snd_intelhad_playback_ops = { .mmap = snd_intelhad_pcm_mmap, }; -/* - * snd_intelhad_pcm_free - to free the memory allocated - * - * @pcm: pointer to pcm instance - * This function is called when the device is removed - */ -static void snd_intelhad_pcm_free(struct snd_pcm *pcm) -{ - snd_pcm_lib_preallocate_free_for_all(pcm); -} - static int had_iec958_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -2063,7 +2052,6 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) /* setup private data which can be retrieved when required */ pcm->private_data = ctx; - pcm->private_free = snd_intelhad_pcm_free; pcm->info_flags = 0; strncpy(pcm->name, card->shortname, strlen(card->shortname)); /* setup the ops for playabck */ -- cgit v1.2.3 From 99b2ab9d3aa08824dfefd7d9ad9f2b4c19555d05 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 16:26:10 +0100 Subject: ALSA: x86: Fix sleep-in-atomic via i915 notification i915 notification is executed in a spinlock, thus it must not sleep; i.e. we can't use kmalloc with GFP_KERNEL or such. For making it working properly, move the notification handler in a work, and handle it gracefully. We have already such a work, and it was used just at the start. This can be re-used in a more generic hotplug handling. Also, the patch adds the proper call of cancel_work_sync() to the destructor. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 51 +++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 28eb980d2d2e..ab199b5deaa5 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1857,14 +1857,6 @@ static struct snd_kcontrol_new had_control_iec958 = { .put = had_iec958_put }; -static void _had_wq(struct work_struct *work) -{ - struct snd_intelhad *ctx = - container_of(work, struct snd_intelhad, hdmi_audio_wq); - - had_process_hot_plug(ctx); -} - static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id) { struct snd_intelhad *ctx = dev_id; @@ -1889,21 +1881,28 @@ static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id) static void notify_audio_lpe(struct platform_device *pdev) { struct snd_intelhad *ctx = platform_get_drvdata(pdev); - struct intel_hdmi_lpe_audio_pdata *pdata = pdev->dev.platform_data; - - if (pdata->hdmi_connected != true) { - dev_dbg(&pdev->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG\n", - __func__); + schedule_work(&ctx->hdmi_audio_wq); +} - if (ctx->state == hdmi_connector_status_connected) { +static void had_audio_wq(struct work_struct *work) +{ + struct snd_intelhad *ctx = + container_of(work, struct snd_intelhad, hdmi_audio_wq); + struct intel_hdmi_lpe_audio_pdata *pdata = ctx->dev->platform_data; - ctx->state = hdmi_connector_status_disconnected; + if (!pdata->hdmi_connected) { + dev_dbg(ctx->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG\n", + __func__); - had_process_hot_unplug(ctx); - } else - dev_dbg(&pdev->dev, "%s: Already Unplugged!\n", + if (ctx->state != hdmi_connector_status_connected) { + dev_dbg(ctx->dev, "%s: Already Unplugged!\n", __func__); + return; + } + + ctx->state = hdmi_connector_status_disconnected; + had_process_hot_unplug(ctx); } else { struct intel_hdmi_lpe_audio_eld *eld = &pdata->eld; @@ -1919,7 +1918,7 @@ static void notify_audio_lpe(struct platform_device *pdev) ctx->had_config_offset = AUDIO_HDMI_CONFIG_C; break; default: - dev_dbg(&pdev->dev, "Invalid pipe %d\n", + dev_dbg(ctx->dev, "Invalid pipe %d\n", eld->pipe_id); break; } @@ -1930,7 +1929,7 @@ static void notify_audio_lpe(struct platform_device *pdev) ctx->state = hdmi_connector_status_connected; - dev_dbg(&pdev->dev, "%s: HAD_NOTIFY_ELD : port = %d, tmds = %d\n", + dev_dbg(ctx->dev, "%s: HAD_NOTIFY_ELD : port = %d, tmds = %d\n", __func__, eld->port_id, pdata->tmds_clock_speed); if (pdata->tmds_clock_speed) { @@ -1950,6 +1949,8 @@ static void hdmi_lpe_audio_free(struct snd_card *card) { struct snd_intelhad *ctx = card->private_data; + cancel_work_sync(&ctx->hdmi_audio_wq); + if (ctx->mmio_start) iounmap(ctx->mmio_start); if (ctx->irq >= 0) @@ -2013,7 +2014,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) ctx->irq = -1; ctx->tmds_clock_speed = DIS_SAMPLE_RATE_148_5; - INIT_WORK(&ctx->hdmi_audio_wq, _had_wq); + INIT_WORK(&ctx->hdmi_audio_wq, had_audio_wq); ctx->state = hdmi_connector_status_disconnected; card->private_free = hdmi_lpe_audio_free; @@ -2086,17 +2087,13 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) spin_lock_irqsave(&pdata->lpe_audio_slock, flags); pdata->notify_audio_lpe = notify_audio_lpe; - if (pdata->notify_pending) { - - dev_dbg(&pdev->dev, "%s: handle pending notification\n", __func__); - notify_audio_lpe(pdev); - pdata->notify_pending = false; - } + pdata->notify_pending = false; spin_unlock_irqrestore(&pdata->lpe_audio_slock, flags); pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); + dev_dbg(&pdev->dev, "%s: handle pending notification\n", __func__); schedule_work(&ctx->hdmi_audio_wq); return 0; -- cgit v1.2.3 From caa2a61a702a2a391b2fb695fc245ca5b8a4ffd8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 16:38:22 +0100 Subject: ALSA: x86: Remove superfluous check at resume The had_get_hwstate() is identical with drv_status==DISCONECTED, which was already checked before the call. And, returning an error at resume is simply bad. That is, we should just kill this check. Also, spewing an error at resume for drv_status!=SUSPENDED is also annoying, as this is the normal case when the suspend was called without the monitor connection. Make it debug, too. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index ab199b5deaa5..835e0f2c4f0b 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1454,7 +1454,6 @@ static int hdmi_lpe_audio_suspend(struct platform_device *pdev, return -EAGAIN; } - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); @@ -1500,17 +1499,10 @@ static int hdmi_lpe_audio_resume(struct platform_device *pdev) if (intelhaddata->drv_status != HAD_DRV_SUSPENDED) { spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - dev_err(intelhaddata->dev, "had is not in suspended state\n"); + dev_dbg(intelhaddata->dev, "had is not in suspended state\n"); return 0; } - if (had_get_hwstate(intelhaddata)) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - dev_err(intelhaddata->dev, - "Failed to resume. Device not accessible\n"); - return -ENODEV; - } - intelhaddata->drv_status = HAD_DRV_CONNECTED; dev_dbg(intelhaddata->dev, "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", -- cgit v1.2.3 From 79f439ea4007b94beeb8ba1e00e71f9d128b0f90 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 16:46:44 +0100 Subject: ALSA: x86: Drop had_get_hwstate() The helper function isn't clearer than the plain condition check "if (drv_status == HDA_DRV_DISCONNECTED)". By expanding this, the compiler could even catch the possible uninitialized cases, so we could fix them, too. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 42 ++++++++++++++---------------------------- 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 835e0f2c4f0b..7c6549a10c1c 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -155,15 +155,6 @@ static const struct snd_pcm_hardware snd_intel_hadstream = { }; /* Register access functions */ -static int had_get_hwstate(struct snd_intelhad *intelhaddata) -{ - /* Check for device presence -SW state */ - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) - return -ENODEV; - - return 0; -} - static inline void mid_hdmi_audio_read(struct snd_intelhad *ctx, u32 reg, u32 *val) { @@ -179,11 +170,8 @@ mid_hdmi_audio_write(struct snd_intelhad *ctx, u32 reg, u32 val) static int had_read_register(struct snd_intelhad *intelhaddata, u32 offset, u32 *data) { - int retval; - - retval = had_get_hwstate(intelhaddata); - if (retval) - return retval; + if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) + return -ENODEV; mid_hdmi_audio_read(intelhaddata, offset, data); return 0; @@ -201,11 +189,8 @@ static void fixup_dp_config(struct snd_intelhad *intelhaddata, static int had_write_register(struct snd_intelhad *intelhaddata, u32 offset, u32 data) { - int retval; - - retval = had_get_hwstate(intelhaddata); - if (retval) - return retval; + if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) + return -ENODEV; fixup_dp_config(intelhaddata, offset, &data); mid_hdmi_audio_write(intelhaddata, offset, data); @@ -216,11 +201,9 @@ static int had_read_modify(struct snd_intelhad *intelhaddata, u32 offset, u32 data, u32 mask) { u32 val_tmp; - int retval; - retval = had_get_hwstate(intelhaddata); - if (retval) - return retval; + if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) + return -ENODEV; mid_hdmi_audio_read(intelhaddata, offset, &val_tmp); val_tmp &= ~mask; @@ -930,7 +913,7 @@ static int snd_intelhad_prog_n(u32 aud_samp_freq, u32 *n_param, static void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata) { - u32 hdmi_status, i = 0; + u32 hdmi_status = 0, i = 0; /* Handle Underrun interrupt within Audio Unit */ had_write_register(intelhaddata, AUD_CONFIG, 0); @@ -977,7 +960,7 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) pm_runtime_get(intelhaddata->dev); - if (had_get_hwstate(intelhaddata)) { + if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { dev_dbg(intelhaddata->dev, "%s: HDMI cable plugged-out\n", __func__); retval = -ENODEV; @@ -1185,7 +1168,7 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, switch (cmd) { case SNDRV_PCM_TRIGGER_START: /* Disable local INTRs till register prgmng is done */ - if (had_get_hwstate(intelhaddata)) { + if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { dev_dbg(intelhaddata->dev, "_START: HDMI cable plugged-out\n"); retval = -ENODEV; @@ -1245,7 +1228,7 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) runtime = substream->runtime; had_stream = &intelhaddata->stream_data; - if (had_get_hwstate(intelhaddata)) { + if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { dev_dbg(intelhaddata->dev, "%s: HDMI cable plugged-out\n", __func__); retval = -ENODEV; @@ -1329,6 +1312,9 @@ static snd_pcm_uframes_t snd_intelhad_pcm_pointer( intelhaddata = snd_pcm_substream_chip(substream); + if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) + return SNDRV_PCM_POS_XRUN; + if (intelhaddata->flag_underrun) { intelhaddata->flag_underrun = false; return SNDRV_PCM_POS_XRUN; @@ -1614,7 +1600,7 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); - if (had_get_hwstate(intelhaddata)) { + if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { dev_dbg(intelhaddata->dev, "HDMI cable plugged-out\n"); return 0; } -- cgit v1.2.3 From 2e52f5e518fb79aca459fcd25c3b8f185aa4bcf7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 17:09:13 +0100 Subject: ALSA: x86: Tidy up codes Clean up codes, fix indentations, correct comments, etc. No functional change. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 148 +++++++++++++++++-------------------------- 1 file changed, 59 insertions(+), 89 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 7c6549a10c1c..46db4883f0b5 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -285,7 +285,7 @@ static void snd_intelhad_reset_audio(struct snd_intelhad *intelhaddata, had_write_register(intelhaddata, AUD_HDMI_STATUS_v2, reset); } -/** +/* * initialize audio channel status registers * This function is called in the prepare callback */ @@ -298,9 +298,9 @@ static int had_prog_status_reg(struct snd_pcm_substream *substream, int format; ch_stat0.status_0_regx.lpcm_id = (intelhaddata->aes_bits & - IEC958_AES0_NONAUDIO)>>1; + IEC958_AES0_NONAUDIO) >> 1; ch_stat0.status_0_regx.clk_acc = (intelhaddata->aes_bits & - IEC958_AES3_CON_CLOCK)>>4; + IEC958_AES3_CON_CLOCK) >> 4; cfg_val.cfg_regx_v2.val_bit = ch_stat0.status_0_regx.lpcm_id; switch (substream->runtime->rate) { @@ -330,9 +330,8 @@ static int had_prog_status_reg(struct snd_pcm_substream *substream, default: /* control should never come here */ return -EINVAL; - break; - } + had_write_register(intelhaddata, AUD_CH_STATUS_0, ch_stat0.status_0_regval); @@ -348,6 +347,7 @@ static int had_prog_status_reg(struct snd_pcm_substream *substream, ch_stat1.status_1_regx.max_wrd_len = 0; ch_stat1.status_1_regx.wrd_len = 0; } + had_write_register(intelhaddata, AUD_CH_STATUS_1, ch_stat1.status_1_regval); return 0; @@ -466,14 +466,14 @@ static int spk_to_chmap(int spk) static void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata) { - int i = 0, c = 0; + int i, c; int spk_mask = 0; struct snd_pcm_chmap_elem *chmap; u8 eld_high, eld_high_mask = 0xF0; u8 high_msb; chmap = kzalloc(sizeof(*chmap), GFP_KERNEL); - if (chmap == NULL) { + if (!chmap) { intelhaddata->chmap->chmap = NULL; return; } @@ -514,7 +514,7 @@ static void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata) for (c = 0; c < channel_allocations[i].channels; c++) { chmap->map[c] = spk_to_chmap( channel_allocations[i].speakers[ - (MAX_SPEAKERS - 1)-c]); + (MAX_SPEAKERS - 1) - c]); } chmap->channels = channel_allocations[i].channels; intelhaddata->chmap->chmap = chmap; @@ -550,12 +550,12 @@ static int had_chmap_ctl_get(struct snd_kcontrol *kcontrol, { struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); struct snd_intelhad *intelhaddata = info->private_data; - int i = 0; + int i; const struct snd_pcm_chmap_elem *chmap; if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) return -ENODEV; - if (intelhaddata->chmap->chmap == NULL) + if (!intelhaddata->chmap->chmap) return -ENODATA; chmap = intelhaddata->chmap->chmap; for (i = 0; i < chmap->channels; i++) @@ -567,7 +567,7 @@ static int had_chmap_ctl_get(struct snd_kcontrol *kcontrol, static int had_register_chmap_ctls(struct snd_intelhad *intelhaddata, struct snd_pcm *pcm) { - int err = 0; + int err; err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, NULL, 0, (unsigned long)intelhaddata, @@ -615,7 +615,7 @@ static void snd_intelhad_prog_dip(struct snd_pcm_substream *substream, frame3.fr3_regx.chnl_alloc = snd_intelhad_channel_allocation( intelhaddata, channels); - /*Calculte the byte wide checksum for all valid DIP words*/ + /* Calculte the byte wide checksum for all valid DIP words */ for (i = 0; i < BYTES_PER_WORD; i++) checksum += (info_frame >> i*BITS_PER_BYTE) & MASK_BYTE0; for (i = 0; i < BYTES_PER_WORD; i++) @@ -639,10 +639,8 @@ static void snd_intelhad_prog_dip(struct snd_pcm_substream *substream, had_write_register(intelhaddata, AUD_CNTL_ST, ctrl_state.ctrl_val); } -/** - * snd_intelhad_prog_buffer - programs buffer - * address and length registers - * +/* + * snd_intelhad_prog_buffer - programs buffer address and length registers * @substream:substream for which the prepare function is called * @intelhaddata:substream private data * @@ -684,7 +682,7 @@ static int snd_intelhad_prog_buffer(struct snd_intelhad *intelhaddata, intelhaddata->buf_info[i].buf_size = period_bytes; else intelhaddata->buf_info[i].buf_size = ring_buf_size - - (period_bytes*i); + (i * period_bytes); had_write_register(intelhaddata, AUD_BUF_A_ADDR + (i * HAD_REG_WIDTH), @@ -728,7 +726,7 @@ static int had_calculate_maud_value(u32 aud_samp_freq, u32 link_rate) { u32 maud_val; - /* Select maud according to DP 1.2 spec*/ + /* Select maud according to DP 1.2 spec */ if (link_rate == DP_2_7_GHZ) { switch (aud_samp_freq) { case AUD_SAMPLE_RATE_32: @@ -836,41 +834,41 @@ static void snd_intelhad_prog_cts(u32 aud_samp_freq, u32 tmds, static int had_calculate_n_value(u32 aud_samp_freq) { - s32 n_val; + int n_val; /* Select N according to HDMI 1.3a spec*/ switch (aud_samp_freq) { case AUD_SAMPLE_RATE_32: n_val = 4096; - break; + break; case AUD_SAMPLE_RATE_44_1: n_val = 6272; - break; + break; case AUD_SAMPLE_RATE_48: n_val = 6144; - break; + break; case AUD_SAMPLE_RATE_88_2: n_val = 12544; - break; + break; case AUD_SAMPLE_RATE_96: n_val = 12288; - break; + break; case AUD_SAMPLE_RATE_176_4: n_val = 25088; - break; + break; case HAD_MAX_RATE: n_val = 24576; - break; + break; default: n_val = -EINVAL; - break; + break; } return n_val; } @@ -888,7 +886,7 @@ static int had_calculate_n_value(u32 aud_samp_freq) static int snd_intelhad_prog_n(u32 aud_samp_freq, u32 *n_param, struct snd_intelhad *intelhaddata) { - s32 n_val; + int n_val; if (intelhaddata->dp_output) { /* @@ -920,7 +918,7 @@ static void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata) /* Reset buffer pointers */ had_write_register(intelhaddata, AUD_HDMI_STATUS_v2, 1); had_write_register(intelhaddata, AUD_HDMI_STATUS_v2, 0); - /** + /* * The interrupt status 'sticky' bits might not be cleared by * setting '1' to that bit once... */ @@ -939,7 +937,7 @@ static void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata) dev_err(intelhaddata->dev, "Unable to clear UNDERRUN bits\n"); } -/** +/* * snd_intelhad_open - stream initializations are done here * @substream:substream for which the stream function is called * @@ -1029,25 +1027,8 @@ static void had_period_elapsed(struct snd_pcm_substream *substream) snd_pcm_period_elapsed(substream); } -/** - * snd_intelhad_init_stream - internal function to initialize stream info - * @substream:substream for which the stream function is called - * - */ -static int snd_intelhad_init_stream(struct snd_pcm_substream *substream) -{ - struct snd_intelhad *intelhaddata = snd_pcm_substream_chip(substream); - - intelhaddata->stream_info.had_substream = substream; - intelhaddata->stream_info.buffer_ptr = 0; - intelhaddata->stream_info.buffer_rendered = 0; - intelhaddata->stream_info.sfreq = substream->runtime->rate; - return 0; -} - -/** - * snd_intelhad_close- to free parameteres when stream is stopped - * +/* + * snd_intelhad_close - to free parameteres when stream is stopped * @substream: substream for which the function is called * * This function is called by ALSA framework when stream is stopped @@ -1081,11 +1062,10 @@ static int snd_intelhad_close(struct snd_pcm_substream *substream) return 0; } -/** - * snd_intelhad_hw_params- to setup the hardware parameters - * like allocating the buffers - * - * @substream: substream for which the function is called +/* + * snd_intelhad_hw_params - to setup the hardware parameters + * like allocating the buffers + * @substream: substream for which the function is called * @hw_params: hardware parameters * * This function is called by ALSA framework when hardware params are set @@ -1121,14 +1101,12 @@ static int snd_intelhad_hw_params(struct snd_pcm_substream *substream, return retval; } -/** - * snd_intelhad_hw_free- to release the resources allocated during - * hardware params setup - * +/* + * snd_intelhad_hw_free - to release the resources allocated during + * hardware params setup * @substream: substream for which the function is called * * This function is called by ALSA framework before close callback. - * */ static int snd_intelhad_hw_free(struct snd_pcm_substream *substream) { @@ -1146,10 +1124,11 @@ static int snd_intelhad_hw_free(struct snd_pcm_substream *substream) return 0; } -/** +/* * snd_intelhad_pcm_trigger - stream activities are handled here - * @substream:substream for which the stream function is called - * @cmd:the stream commamd thats requested from upper layer + * @substream: substream for which the stream function is called + * @cmd: the stream commamd thats requested from upper layer + * * This function is called whenever an a stream activity is invoked */ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, @@ -1208,10 +1187,9 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, return retval; } -/** - * snd_intelhad_pcm_prepare- internal preparation before starting a stream - * - * @substream: substream for which the function is called +/* + * snd_intelhad_pcm_prepare - internal preparation before starting a stream + * @substream: substream for which the function is called * * This function is called when a stream is started for internal preparation. */ @@ -1252,10 +1230,10 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) return retval; } - retval = snd_intelhad_init_stream(substream); - if (retval) - goto prep_end; - + intelhaddata->stream_info.had_substream = substream; + intelhaddata->stream_info.buffer_ptr = 0; + intelhaddata->stream_info.buffer_rendered = 0; + intelhaddata->stream_info.sfreq = substream->runtime->rate; /* Get N value in KHz */ disp_samp_freq = intelhaddata->tmds_clock_speed; @@ -1294,10 +1272,9 @@ prep_end: return retval; } -/** +/* * snd_intelhad_pcm_pointer- to send the current buffer pointerprocessed by hw - * - * @substream: substream for which the function is called + * @substream: substream for which the function is called * * This function is called by ALSA framework to get the current hw buffer ptr * when a period is elapsed @@ -1359,11 +1336,10 @@ static snd_pcm_uframes_t snd_intelhad_pcm_pointer( return intelhaddata->stream_info.buffer_ptr; } -/** +/* * snd_intelhad_pcm_mmap- mmaps a kernel buffer to user space for copying data - * - * @substream: substream for which the function is called - * @vma: struct instance of memory VMM memory area + * @substream: substream for which the function is called + * @vma: struct instance of memory VMM memory area * * This function is called by OS when a user space component * tries to get mmap memory from driver @@ -1418,11 +1394,9 @@ out: /* * hdmi_lpe_audio_suspend - power management suspend function - * * @pdev: platform device * - * This function is called by client driver to suspend the - * hdmi audio. + * This function is called to suspend the hdmi audio. */ static int hdmi_lpe_audio_suspend(struct platform_device *pdev, pm_message_t state) @@ -1465,11 +1439,9 @@ static int hdmi_lpe_audio_suspend(struct platform_device *pdev, /* * hdmi_lpe_audio_resume - power management resume function + * @pdev: platform device * - *@pdev: platform device - * - * This function is called by client driver to resume the - * hdmi audio. + * This function is called to resume the hdmi audio. */ static int hdmi_lpe_audio_resume(struct platform_device *pdev) { @@ -1605,7 +1577,7 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) return 0; } - /*Reprogram the registers with addr and length*/ + /* Reprogram the registers with addr and length */ had_write_register(intelhaddata, AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH), buf_size); @@ -1939,8 +1911,7 @@ static void hdmi_lpe_audio_free(struct snd_card *card) * hdmi_lpe_audio_probe - start bridge with i915 * * This function is called when the i915 driver creates the - * hdmi-lpe-audio platform device. Card creation is deferred until a - * hot plug event is received + * hdmi-lpe-audio platform device. */ static int hdmi_lpe_audio_probe(struct platform_device *pdev) { @@ -2084,8 +2055,7 @@ err: /* * hdmi_lpe_audio_remove - stop bridge with i915 * - * This function is called when the platform device is destroyed. The sound - * card should have been removed on hot plug event. + * This function is called when the platform device is destroyed. */ static int hdmi_lpe_audio_remove(struct platform_device *pdev) { -- cgit v1.2.3 From 4151ee845ad8230d18ac4a0e0bf1037180c6d2d9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 31 Jan 2017 18:14:15 +0100 Subject: ALSA: x86: Remove _v[12] suffices Although we dropped the most of the obsoleted *_v1 definitions and codes, some codes still keep the _v1 or _v2 suffices. Now they are ripped off. The only thing to be done carefully here is the definition of control offsets. The original code defines enum hdmi_ctrl_reg_offset_v1 and a few new elements just for v2 on its top. After this cleanup, we remove the old AUD_HDMI_STATUS and AUD_HDMIW_INFOFR definitions and replace with the v2 values. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 46 ++++++++++++++++++++-------------------- sound/x86/intel_hdmi_audio.h | 2 +- sound/x86/intel_hdmi_lpe_audio.h | 24 ++++++--------------- 3 files changed, 31 insertions(+), 41 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 46db4883f0b5..84b374cc183f 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -249,10 +249,10 @@ static int had_read_modify_aud_config_v2(struct snd_intelhad *intelhaddata, channels = substream->runtime->channels; else channels = 2; - cfg_val.cfg_regx_v2.num_ch = channels - 2; + cfg_val.cfg_regx.num_ch = channels - 2; data = data | cfg_val.cfg_regval; - mask = mask | AUD_CONFIG_CH_MASK_V2; + mask = mask | AUD_CONFIG_CH_MASK; dev_dbg(intelhaddata->dev, "%s : data = %x, mask =%x\n", __func__, data, mask); @@ -265,10 +265,10 @@ static void snd_intelhad_enable_audio_int(struct snd_intelhad *ctx, bool enable) u32 status_reg; if (enable) { - mid_hdmi_audio_read(ctx, AUD_HDMI_STATUS_v2, &status_reg); + mid_hdmi_audio_read(ctx, AUD_HDMI_STATUS, &status_reg); status_reg |= HDMI_AUDIO_BUFFER_DONE | HDMI_AUDIO_UNDERRUN; - mid_hdmi_audio_write(ctx, AUD_HDMI_STATUS_v2, status_reg); - mid_hdmi_audio_read(ctx, AUD_HDMI_STATUS_v2, &status_reg); + mid_hdmi_audio_write(ctx, AUD_HDMI_STATUS, status_reg); + mid_hdmi_audio_read(ctx, AUD_HDMI_STATUS, &status_reg); } } @@ -282,7 +282,7 @@ static void snd_intelhad_enable_audio(struct snd_intelhad *intelhaddata, static void snd_intelhad_reset_audio(struct snd_intelhad *intelhaddata, u8 reset) { - had_write_register(intelhaddata, AUD_HDMI_STATUS_v2, reset); + had_write_register(intelhaddata, AUD_HDMI_STATUS, reset); } /* @@ -301,7 +301,7 @@ static int had_prog_status_reg(struct snd_pcm_substream *substream, IEC958_AES0_NONAUDIO) >> 1; ch_stat0.status_0_regx.clk_acc = (intelhaddata->aes_bits & IEC958_AES3_CON_CLOCK) >> 4; - cfg_val.cfg_regx_v2.val_bit = ch_stat0.status_0_regx.lpcm_id; + cfg_val.cfg_regx.val_bit = ch_stat0.status_0_regx.lpcm_id; switch (substream->runtime->rate) { case AUD_SAMPLE_RATE_32: @@ -367,19 +367,19 @@ static int snd_intelhad_audio_ctrl(struct snd_pcm_substream *substream, had_prog_status_reg(substream, intelhaddata); - buf_cfg.buf_cfg_regx_v2.audio_fifo_watermark = FIFO_THRESHOLD; - buf_cfg.buf_cfg_regx_v2.dma_fifo_watermark = DMA_FIFO_THRESHOLD; - buf_cfg.buf_cfg_regx_v2.aud_delay = 0; + buf_cfg.buf_cfg_regx.audio_fifo_watermark = FIFO_THRESHOLD; + buf_cfg.buf_cfg_regx.dma_fifo_watermark = DMA_FIFO_THRESHOLD; + buf_cfg.buf_cfg_regx.aud_delay = 0; had_write_register(intelhaddata, AUD_BUF_CONFIG, buf_cfg.buf_cfgval); channels = substream->runtime->channels; - cfg_val.cfg_regx_v2.num_ch = channels - 2; + cfg_val.cfg_regx.num_ch = channels - 2; if (channels <= 2) - cfg_val.cfg_regx_v2.layout = LAYOUT0; + cfg_val.cfg_regx.layout = LAYOUT0; else - cfg_val.cfg_regx_v2.layout = LAYOUT1; + cfg_val.cfg_regx.layout = LAYOUT1; - cfg_val.cfg_regx_v2.val_bit = 1; + cfg_val.cfg_regx.val_bit = 1; had_write_register(intelhaddata, AUD_CONFIG, cfg_val.cfg_regval); return 0; } @@ -626,13 +626,13 @@ static void snd_intelhad_prog_dip(struct snd_pcm_substream *substream, frame2.fr2_regx.chksum = -(checksum); } - had_write_register(intelhaddata, AUD_HDMIW_INFOFR_v2, info_frame); - had_write_register(intelhaddata, AUD_HDMIW_INFOFR_v2, frame2.fr2_val); - had_write_register(intelhaddata, AUD_HDMIW_INFOFR_v2, frame3.fr3_val); + had_write_register(intelhaddata, AUD_HDMIW_INFOFR, info_frame); + had_write_register(intelhaddata, AUD_HDMIW_INFOFR, frame2.fr2_val); + had_write_register(intelhaddata, AUD_HDMIW_INFOFR, frame3.fr3_val); /* program remaining DIP words with zero */ for (i = 0; i < HAD_MAX_DIP_WORDS-VALID_DIP_WORDS; i++) - had_write_register(intelhaddata, AUD_HDMIW_INFOFR_v2, 0x0); + had_write_register(intelhaddata, AUD_HDMIW_INFOFR, 0x0); ctrl_state.ctrl_regx.dip_freq = 1; ctrl_state.ctrl_regx.dip_en_sta = 1; @@ -916,20 +916,20 @@ static void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata) /* Handle Underrun interrupt within Audio Unit */ had_write_register(intelhaddata, AUD_CONFIG, 0); /* Reset buffer pointers */ - had_write_register(intelhaddata, AUD_HDMI_STATUS_v2, 1); - had_write_register(intelhaddata, AUD_HDMI_STATUS_v2, 0); + had_write_register(intelhaddata, AUD_HDMI_STATUS, 1); + had_write_register(intelhaddata, AUD_HDMI_STATUS, 0); /* * The interrupt status 'sticky' bits might not be cleared by * setting '1' to that bit once... */ do { /* clear bit30, 31 AUD_HDMI_STATUS */ - had_read_register(intelhaddata, AUD_HDMI_STATUS_v2, + had_read_register(intelhaddata, AUD_HDMI_STATUS, &hdmi_status); dev_dbg(intelhaddata->dev, "HDMI status =0x%x\n", hdmi_status); if (hdmi_status & AUD_CONFIG_MASK_UNDERRUN) { i++; had_write_register(intelhaddata, - AUD_HDMI_STATUS_v2, hdmi_status); + AUD_HDMI_STATUS, hdmi_status); } else break; } while (i < MAX_CNT); @@ -1812,7 +1812,7 @@ static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id) struct snd_intelhad *ctx = dev_id; u32 audio_stat, audio_reg; - audio_reg = AUD_HDMI_STATUS_v2; + audio_reg = AUD_HDMI_STATUS; mid_hdmi_audio_read(ctx, audio_reg, &audio_stat); if (audio_stat & HDMI_AUDIO_UNDERRUN) { diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 4549c4d9d650..8b85a5668d83 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -69,7 +69,7 @@ #define LAYOUT0 0 #define LAYOUT1 1 #define SWAP_LFE_CENTER 0x00fac4c8 -#define AUD_CONFIG_CH_MASK_V2 0x70 +#define AUD_CONFIG_CH_MASK 0x70 struct pcm_stream_info { int str_id; diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index 8f320b4aa3b7..628c578ecedf 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -277,7 +277,7 @@ enum hdmi_ctrl_reg_offset_common { AUDIO_HDMI_CONFIG_C = 0x900, }; /* HDMI controller register offsets */ -enum hdmi_ctrl_reg_offset_v1 { +enum hdmi_ctrl_reg_offset { AUD_CONFIG = 0x0, AUD_CH_STATUS_0 = 0x08, AUD_CH_STATUS_1 = 0x0C, @@ -295,18 +295,8 @@ enum hdmi_ctrl_reg_offset_v1 { AUD_BUF_D_ADDR = 0x58, AUD_BUF_D_LENGTH = 0x5c, AUD_CNTL_ST = 0x60, - AUD_HDMI_STATUS = 0x68, - AUD_HDMIW_INFOFR = 0x114, -}; - -/* - * Delta changes in HDMI controller register offsets - * compare to v1 version - */ - -enum hdmi_ctrl_reg_offset_v2 { - AUD_HDMI_STATUS_v2 = 0x64, - AUD_HDMIW_INFOFR_v2 = 0x68, + AUD_HDMI_STATUS = 0x64, /* v2 */ + AUD_HDMIW_INFOFR = 0x68, /* v2 */ }; /* @@ -374,7 +364,7 @@ union aud_cfg { u32 bogus_sample:1; u32 dp_modei:1; u32 rsvd:16; - } cfg_regx_v2; + } cfg_regx; u32 cfg_regval; }; @@ -430,7 +420,7 @@ union aud_hdmi_cts { u32 cts_val:24; u32 en_cts_prog:1; u32 rsvd:7; - } cts_regx_v2; + } cts_regx; u32 cts_regval; }; @@ -446,7 +436,7 @@ union aud_hdmi_n_enable { u32 n_val:24; u32 en_n_prog:1; u32 rsvd:7; - } n_regx_v2; + } n_regx; u32 n_regval; }; @@ -464,7 +454,7 @@ union aud_buf_config { u32 rsvd0:5; u32 aud_delay:8; u32 rsvd1:8; - } buf_cfg_regx_v2; + } buf_cfg_regx; u32 buf_cfgval; }; -- cgit v1.2.3 From 4a5ddb2cb1ef624300d1e66e9e6974cd37b7012f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 1 Feb 2017 16:45:38 +0100 Subject: ALSA: x86: Constfy tables Some tables can be defined as const. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 84b374cc183f..81b6c26a8646 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -51,7 +51,7 @@ MODULE_PARM_DESC(id, /* * ELD SA bits in the CEA Speaker Allocation data block */ -static int eld_speaker_allocation_bits[] = { +static const int eld_speaker_allocation_bits[] = { [0] = FL | FR, [1] = LFE, [2] = FC, @@ -114,7 +114,7 @@ static struct cea_channel_speaker_allocation channel_allocations[] = { { .ca_index = 0x1f, .speakers = { FRC, FLC, RR, RL, FC, LFE, FR, FL } }, }; -static struct channel_map_table map_tables[] = { +static const struct channel_map_table map_tables[] = { { SNDRV_CHMAP_FL, 0x00, FL }, { SNDRV_CHMAP_FR, 0x01, FR }, { SNDRV_CHMAP_RL, 0x04, RL }, @@ -455,7 +455,7 @@ static int snd_intelhad_channel_allocation(struct snd_intelhad *intelhaddata, /* from speaker bit mask to ALSA API channel position */ static int spk_to_chmap(int spk) { - struct channel_map_table *t = map_tables; + const struct channel_map_table *t = map_tables; for (; t->map; t++) { if (t->spk_mask == spk) -- cgit v1.2.3 From bcce775ca8d66a5222ac2d28e5388b5a6c2d9ad6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 1 Feb 2017 17:18:20 +0100 Subject: ALSA: x86: Remove superfluous irqsave flags We don't need to use irqsave/irqrestore versions for each spin lock, but judge the context properly and use the simpler versions. Also add some (still simplistic) comments to functions. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 71 ++++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 38 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 81b6c26a8646..046af2367fba 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1135,7 +1135,6 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { int retval = 0; - unsigned long flag_irq; struct snd_intelhad *intelhaddata; struct had_stream_pvt *stream; struct had_stream_data *had_stream; @@ -1163,14 +1162,14 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, break; case SNDRV_PCM_TRIGGER_STOP: - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irq); + spin_lock(&intelhaddata->had_spinlock); intelhaddata->stream_info.str_id = 0; intelhaddata->curr_buf = 0; /* Stop reporting BUFFER_DONE/UNDERRUN to above layers */ had_stream->stream_type = HAD_INIT; - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irq); + spin_unlock(&intelhaddata->had_spinlock); /* Disable Audio */ snd_intelhad_enable_audio_int(intelhaddata, false); snd_intelhad_enable_audio(intelhaddata, false); @@ -1402,7 +1401,6 @@ static int hdmi_lpe_audio_suspend(struct platform_device *pdev, pm_message_t state) { struct had_stream_data *had_stream; - unsigned long flag_irqs; struct snd_pcm_substream *substream; struct snd_intelhad *intelhaddata = platform_get_drvdata(pdev); @@ -1414,15 +1412,15 @@ static int hdmi_lpe_audio_suspend(struct platform_device *pdev, return -EAGAIN; } - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + spin_lock_irq(&intelhaddata->had_spinlock); if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + spin_unlock_irq(&intelhaddata->had_spinlock); dev_dbg(intelhaddata->dev, "had not connected\n"); return 0; } if (intelhaddata->drv_status == HAD_DRV_SUSPENDED) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + spin_unlock_irq(&intelhaddata->had_spinlock); dev_dbg(intelhaddata->dev, "had already suspended\n"); return 0; } @@ -1432,7 +1430,7 @@ static int hdmi_lpe_audio_suspend(struct platform_device *pdev, "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_SUSPENDED\n", __func__, __LINE__); - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + spin_unlock_irq(&intelhaddata->had_spinlock); snd_intelhad_enable_audio_int(intelhaddata, false); return 0; } @@ -1446,17 +1444,16 @@ static int hdmi_lpe_audio_suspend(struct platform_device *pdev, static int hdmi_lpe_audio_resume(struct platform_device *pdev) { struct snd_intelhad *intelhaddata = platform_get_drvdata(pdev); - unsigned long flag_irqs; - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + spin_lock_irq(&intelhaddata->had_spinlock); if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + spin_unlock_irq(&intelhaddata->had_spinlock); dev_dbg(intelhaddata->dev, "had not connected\n"); return 0; } if (intelhaddata->drv_status != HAD_DRV_SUSPENDED) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + spin_unlock_irq(&intelhaddata->had_spinlock); dev_dbg(intelhaddata->dev, "had is not in suspended state\n"); return 0; } @@ -1465,7 +1462,7 @@ static int hdmi_lpe_audio_resume(struct platform_device *pdev) dev_dbg(intelhaddata->dev, "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", __func__, __LINE__); - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + spin_unlock_irq(&intelhaddata->had_spinlock); snd_intelhad_enable_audio_int(intelhaddata, true); return 0; } @@ -1477,7 +1474,6 @@ static inline int had_chk_intrmiss(struct snd_intelhad *intelhaddata, enum intel_had_aud_buf_type buff_done; u32 buf_size, buf_addr; struct had_stream_data *had_stream; - unsigned long flag_irqs; had_stream = &intelhaddata->stream_data; @@ -1507,14 +1503,13 @@ static inline int had_chk_intrmiss(struct snd_intelhad *intelhaddata, (buf_addr | BIT(0) | BIT(1))); } buf_id = buf_id % 4; - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); intelhaddata->buff_done = buf_id; - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); } return intr_count; } +/* called from irq handler */ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) { u32 len = 1; @@ -1525,15 +1520,15 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) struct had_stream_data *had_stream; int intr_count; enum had_status_stream stream_type; - unsigned long flag_irqs; + unsigned long flags; had_stream = &intelhaddata->stream_data; stream = &intelhaddata->stream_info; intr_count = 1; - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + spin_lock_irqsave(&intelhaddata->had_spinlock, flags); if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags); dev_dbg(intelhaddata->dev, "%s:Device already disconnected\n", __func__); return 0; @@ -1551,16 +1546,16 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) /* Check for any intr_miss in case of active playback */ if (had_stream->stream_type == HAD_RUNNING_STREAM) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); intr_count = had_chk_intrmiss(intelhaddata, buf_id); if (!intr_count || (intr_count > 3)) { + spin_unlock_irqrestore(&intelhaddata->had_spinlock, + flags); dev_err(intelhaddata->dev, "HAD SW state in non-recoverable mode\n"); return 0; } buf_id += (intr_count - 1); buf_id = buf_id % 4; - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); } intelhaddata->buf_info[buf_id].is_valid = true; @@ -1570,7 +1565,7 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) } else intelhaddata->curr_buf = buf_id + 1; - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags); if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { dev_dbg(intelhaddata->dev, "HDMI cable plugged-out\n"); @@ -1604,19 +1599,20 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) return 0; } +/* called from irq handler */ static int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) { enum intel_had_aud_buf_type buf_id; struct pcm_stream_info *stream; struct had_stream_data *had_stream; enum had_status_stream stream_type; - unsigned long flag_irqs; + unsigned long flags; int drv_status; had_stream = &intelhaddata->stream_data; stream = &intelhaddata->stream_info; - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + spin_lock_irqsave(&intelhaddata->had_spinlock, flags); buf_id = intelhaddata->curr_buf; stream_type = had_stream->stream_type; intelhaddata->buff_done = buf_id; @@ -1624,7 +1620,7 @@ static int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) if (stream_type == HAD_RUNNING_STREAM) intelhaddata->curr_buf = HAD_BUF_TYPE_A; - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags); dev_dbg(intelhaddata->dev, "Enter:%s buf_id=%d, stream_type=%d\n", __func__, buf_id, stream_type); @@ -1646,20 +1642,20 @@ static int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) return 0; } +/* process hot plug, called from wq */ static int had_process_hot_plug(struct snd_intelhad *intelhaddata) { enum intel_had_aud_buf_type buf_id; struct snd_pcm_substream *substream; struct had_stream_data *had_stream; - unsigned long flag_irqs; substream = intelhaddata->stream_info.had_substream; had_stream = &intelhaddata->stream_data; - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + spin_lock_irq(&intelhaddata->had_spinlock); if (intelhaddata->drv_status == HAD_DRV_CONNECTED) { dev_dbg(intelhaddata->dev, "Device already connected\n"); - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + spin_unlock_irq(&intelhaddata->had_spinlock); return 0; } buf_id = intelhaddata->curr_buf; @@ -1668,7 +1664,7 @@ static int had_process_hot_plug(struct snd_intelhad *intelhaddata) dev_dbg(intelhaddata->dev, "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_CONNECTED\n", __func__, __LINE__); - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + spin_unlock_irq(&intelhaddata->had_spinlock); dev_dbg(intelhaddata->dev, "Processing HOT_PLUG, buf_id = %d\n", buf_id); @@ -1686,20 +1682,20 @@ static int had_process_hot_plug(struct snd_intelhad *intelhaddata) return 0; } +/* process hot unplug, called from wq */ static int had_process_hot_unplug(struct snd_intelhad *intelhaddata) { enum intel_had_aud_buf_type buf_id; struct had_stream_data *had_stream; - unsigned long flag_irqs; had_stream = &intelhaddata->stream_data; buf_id = intelhaddata->curr_buf; - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + spin_lock_irq(&intelhaddata->had_spinlock); if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { dev_dbg(intelhaddata->dev, "Device already disconnected\n"); - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + spin_unlock_irq(&intelhaddata->had_spinlock); return 0; } else { @@ -1715,14 +1711,14 @@ static int had_process_hot_unplug(struct snd_intelhad *intelhaddata) /* Report to above ALSA layer */ if (intelhaddata->stream_info.had_substream != NULL) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + spin_unlock_irq(&intelhaddata->had_spinlock); snd_pcm_stop(intelhaddata->stream_info.had_substream, SNDRV_PCM_STATE_SETUP); - spin_lock_irqsave(&intelhaddata->had_spinlock, flag_irqs); + spin_lock_irq(&intelhaddata->had_spinlock); } had_stream->stream_type = HAD_INIT; - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flag_irqs); + spin_unlock_irq(&intelhaddata->had_spinlock); kfree(intelhaddata->chmap->chmap); intelhaddata->chmap->chmap = NULL; @@ -1922,7 +1918,6 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) int irq; struct resource *res_mmio; int ret; - unsigned long flags; dev_dbg(&pdev->dev, "dma_mask: %p\n", pdev->dev.dma_mask); @@ -2034,10 +2029,10 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) if (ret) goto err; - spin_lock_irqsave(&pdata->lpe_audio_slock, flags); + spin_lock_irq(&pdata->lpe_audio_slock); pdata->notify_audio_lpe = notify_audio_lpe; pdata->notify_pending = false; - spin_unlock_irqrestore(&pdata->lpe_audio_slock, flags); + spin_unlock_irq(&pdata->lpe_audio_slock); pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); -- cgit v1.2.3 From 8f8d1d7fe009c320d80ed1c7b0c1d3d48b538965 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 1 Feb 2017 17:24:02 +0100 Subject: ALSA: x86: Fix racy access to chmap The access to chmap can be racy against the hotplug process, where it recreates the chmap on the fly. For protecting against it, a mutex is introduced in this patch. It's also used for protecting the change / reference of eld and state fields, too. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 32 +++++++++++++++++++++++--------- sound/x86/intel_hdmi_audio.h | 1 + 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 046af2367fba..c0cb59e6a89b 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -555,11 +555,17 @@ static int had_chmap_ctl_get(struct snd_kcontrol *kcontrol, if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) return -ENODEV; - if (!intelhaddata->chmap->chmap) + + mutex_lock(&intelhaddata->mutex); + if (!intelhaddata->chmap->chmap) { + mutex_unlock(&intelhaddata->mutex); return -ENODATA; + } + chmap = intelhaddata->chmap->chmap; for (i = 0; i < chmap->channels; i++) ucontrol->value.integer.value[i] = chmap->map[i]; + mutex_unlock(&intelhaddata->mutex); return 0; } @@ -1352,6 +1358,7 @@ static int snd_intelhad_pcm_mmap(struct snd_pcm_substream *substream, vma->vm_end - vma->vm_start, vma->vm_page_prot); } +/* process mode change of the running stream; called in mutex */ static int hdmi_audio_mode_change(struct snd_intelhad *intelhaddata) { struct snd_pcm_substream *substream; @@ -1642,7 +1649,7 @@ static int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) return 0; } -/* process hot plug, called from wq */ +/* process hot plug, called from wq with mutex locked */ static int had_process_hot_plug(struct snd_intelhad *intelhaddata) { enum intel_had_aud_buf_type buf_id; @@ -1682,7 +1689,7 @@ static int had_process_hot_plug(struct snd_intelhad *intelhaddata) return 0; } -/* process hot unplug, called from wq */ +/* process hot unplug, called from wq with mutex locked */ static int had_process_hot_unplug(struct snd_intelhad *intelhaddata) { enum intel_had_aud_buf_type buf_id; @@ -1751,12 +1758,14 @@ static int had_iec958_get(struct snd_kcontrol *kcontrol, { struct snd_intelhad *intelhaddata = snd_kcontrol_chip(kcontrol); + mutex_lock(&intelhaddata->mutex); ucontrol->value.iec958.status[0] = (intelhaddata->aes_bits >> 0) & 0xff; ucontrol->value.iec958.status[1] = (intelhaddata->aes_bits >> 8) & 0xff; ucontrol->value.iec958.status[2] = (intelhaddata->aes_bits >> 16) & 0xff; ucontrol->value.iec958.status[3] = (intelhaddata->aes_bits >> 24) & 0xff; + mutex_unlock(&intelhaddata->mutex); return 0; } @@ -1775,16 +1784,19 @@ static int had_iec958_put(struct snd_kcontrol *kcontrol, { unsigned int val; struct snd_intelhad *intelhaddata = snd_kcontrol_chip(kcontrol); + int changed = 0; val = (ucontrol->value.iec958.status[0] << 0) | (ucontrol->value.iec958.status[1] << 8) | (ucontrol->value.iec958.status[2] << 16) | (ucontrol->value.iec958.status[3] << 24); + mutex_lock(&intelhaddata->mutex); if (intelhaddata->aes_bits != val) { intelhaddata->aes_bits = val; - return 1; + changed = 1; } - return 1; + mutex_unlock(&intelhaddata->mutex); + return changed; } static struct snd_kcontrol_new had_control_iec958_mask = { @@ -1837,6 +1849,7 @@ static void had_audio_wq(struct work_struct *work) container_of(work, struct snd_intelhad, hdmi_audio_wq); struct intel_hdmi_lpe_audio_pdata *pdata = ctx->dev->platform_data; + mutex_lock(&ctx->mutex); if (!pdata->hdmi_connected) { dev_dbg(ctx->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG\n", __func__); @@ -1844,12 +1857,11 @@ static void had_audio_wq(struct work_struct *work) if (ctx->state != hdmi_connector_status_connected) { dev_dbg(ctx->dev, "%s: Already Unplugged!\n", __func__); - return; + } else { + ctx->state = hdmi_connector_status_disconnected; + had_process_hot_unplug(ctx); } - ctx->state = hdmi_connector_status_disconnected; - had_process_hot_unplug(ctx); - } else { struct intel_hdmi_lpe_audio_eld *eld = &pdata->eld; @@ -1888,6 +1900,7 @@ static void had_audio_wq(struct work_struct *work) hdmi_audio_mode_change(ctx); } } + mutex_unlock(&ctx->mutex); } /* release resources */ @@ -1948,6 +1961,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) ctx = card->private_data; spin_lock_init(&ctx->had_spinlock); + mutex_init(&ctx->mutex); ctx->drv_status = HAD_DRV_DISCONNECTED; ctx->dev = &pdev->dev; ctx->card = card; diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 8b85a5668d83..be24682e3946 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -139,6 +139,7 @@ struct snd_intelhad { void __iomem *mmio_start; unsigned int had_config_offset; struct work_struct hdmi_audio_wq; + struct mutex mutex; /* for protecting chmap, state and eld */ }; #endif /* _INTEL_HDMI_AUDIO_ */ -- cgit v1.2.3 From d0e9b1a23ca3dbe24e88c6671218b9031e37db96 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 1 Feb 2017 17:37:36 +0100 Subject: ALSA: x86: Drop flag_underrun field The flag_underrun flag is used to indicate to escalate the XRUN reporting at the next position inquiry, but there is a much simpler method to achieve it: just call snd_pcm_stop_xrun(). Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 9 +-------- sound/x86/intel_hdmi_audio.h | 1 - 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index c0cb59e6a89b..9ecdd9ad0199 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1297,11 +1297,6 @@ static snd_pcm_uframes_t snd_intelhad_pcm_pointer( if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) return SNDRV_PCM_POS_XRUN; - if (intelhaddata->flag_underrun) { - intelhaddata->flag_underrun = false; - return SNDRV_PCM_POS_XRUN; - } - /* Use a hw register to calculate sub-period position reports. * This makes PulseAudio happier. */ @@ -1642,8 +1637,7 @@ static int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) if (stream_type == HAD_RUNNING_STREAM) { /* Report UNDERRUN error to above layers */ - intelhaddata->flag_underrun = true; - had_period_elapsed(stream->had_substream); + snd_pcm_stop_xrun(stream->had_substream); } return 0; @@ -1965,7 +1959,6 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) ctx->drv_status = HAD_DRV_DISCONNECTED; ctx->dev = &pdev->dev; ctx->card = card; - ctx->flag_underrun = false; ctx->aes_bits = SNDRV_PCM_DEFAULT_CON_SPDIF; strcpy(card->driver, INTEL_HAD); strcpy(card->shortname, INTEL_HAD); diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index be24682e3946..945f6831f1dd 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -123,7 +123,6 @@ struct snd_intelhad { enum intel_had_aud_buf_type curr_buf; int valid_buf_cnt; unsigned int aes_bits; - bool flag_underrun; struct had_stream_data stream_data; spinlock_t had_spinlock; enum intel_had_aud_buf_type buff_done; -- cgit v1.2.3 From 0e9c67d7c88ce7054288e3b61deb09bfa59f8920 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 1 Feb 2017 17:53:19 +0100 Subject: ALSA: x86: Drop superfluous state field The state field keeps the connection state and it's basically as same as drv_status field. Drop this redundancy. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 56 ++++++++++++++-------------------------- sound/x86/intel_hdmi_audio.h | 3 +-- sound/x86/intel_hdmi_lpe_audio.h | 6 ----- 3 files changed, 21 insertions(+), 44 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 9ecdd9ad0199..621be602addd 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1644,7 +1644,7 @@ static int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) } /* process hot plug, called from wq with mutex locked */ -static int had_process_hot_plug(struct snd_intelhad *intelhaddata) +static void had_process_hot_plug(struct snd_intelhad *intelhaddata) { enum intel_had_aud_buf_type buf_id; struct snd_pcm_substream *substream; @@ -1657,8 +1657,9 @@ static int had_process_hot_plug(struct snd_intelhad *intelhaddata) if (intelhaddata->drv_status == HAD_DRV_CONNECTED) { dev_dbg(intelhaddata->dev, "Device already connected\n"); spin_unlock_irq(&intelhaddata->had_spinlock); - return 0; + return; } + buf_id = intelhaddata->curr_buf; intelhaddata->buff_done = buf_id; intelhaddata->drv_status = HAD_DRV_CONNECTED; @@ -1679,12 +1680,10 @@ static int had_process_hot_plug(struct snd_intelhad *intelhaddata) } had_build_channel_allocation_map(intelhaddata); - - return 0; } /* process hot unplug, called from wq with mutex locked */ -static int had_process_hot_unplug(struct snd_intelhad *intelhaddata) +static void had_process_hot_unplug(struct snd_intelhad *intelhaddata) { enum intel_had_aud_buf_type buf_id; struct had_stream_data *had_stream; @@ -1697,14 +1696,14 @@ static int had_process_hot_unplug(struct snd_intelhad *intelhaddata) if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { dev_dbg(intelhaddata->dev, "Device already disconnected\n"); spin_unlock_irq(&intelhaddata->had_spinlock); - return 0; + return; - } else { - /* Disable Audio */ - snd_intelhad_enable_audio_int(intelhaddata, false); - snd_intelhad_enable_audio(intelhaddata, false); } + /* Disable Audio */ + snd_intelhad_enable_audio_int(intelhaddata, false); + snd_intelhad_enable_audio(intelhaddata, false); + intelhaddata->drv_status = HAD_DRV_DISCONNECTED; dev_dbg(intelhaddata->dev, "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", @@ -1722,8 +1721,6 @@ static int had_process_hot_unplug(struct snd_intelhad *intelhaddata) spin_unlock_irq(&intelhaddata->had_spinlock); kfree(intelhaddata->chmap->chmap); intelhaddata->chmap->chmap = NULL; - - return 0; } /* PCM operations structure and the calls back for the same */ @@ -1847,18 +1844,13 @@ static void had_audio_wq(struct work_struct *work) if (!pdata->hdmi_connected) { dev_dbg(ctx->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG\n", __func__); - - if (ctx->state != hdmi_connector_status_connected) { - dev_dbg(ctx->dev, "%s: Already Unplugged!\n", - __func__); - } else { - ctx->state = hdmi_connector_status_disconnected; - had_process_hot_unplug(ctx); - } - + had_process_hot_unplug(ctx); } else { struct intel_hdmi_lpe_audio_eld *eld = &pdata->eld; + dev_dbg(ctx->dev, "%s: HAD_NOTIFY_ELD : port = %d, tmds = %d\n", + __func__, eld->port_id, pdata->tmds_clock_speed); + switch (eld->pipe_id) { case 0: ctx->had_config_offset = AUDIO_HDMI_CONFIG_A; @@ -1877,22 +1869,15 @@ static void had_audio_wq(struct work_struct *work) memcpy(&ctx->eld, eld->eld_data, sizeof(ctx->eld)); - had_process_hot_plug(ctx); - - ctx->state = hdmi_connector_status_connected; + ctx->dp_output = pdata->dp_output; + ctx->tmds_clock_speed = pdata->tmds_clock_speed; + ctx->link_rate = pdata->link_rate; - dev_dbg(ctx->dev, "%s: HAD_NOTIFY_ELD : port = %d, tmds = %d\n", - __func__, eld->port_id, pdata->tmds_clock_speed); - - if (pdata->tmds_clock_speed) { - ctx->tmds_clock_speed = pdata->tmds_clock_speed; - ctx->dp_output = pdata->dp_output; - ctx->link_rate = pdata->link_rate; + had_process_hot_plug(ctx); - /* Process mode change if stream is active */ - if (ctx->stream_data.stream_type == HAD_RUNNING_STREAM) - hdmi_audio_mode_change(ctx); - } + /* Process mode change if stream is active */ + if (ctx->stream_data.stream_type == HAD_RUNNING_STREAM) + hdmi_audio_mode_change(ctx); } mutex_unlock(&ctx->mutex); } @@ -1966,7 +1951,6 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) ctx->irq = -1; ctx->tmds_clock_speed = DIS_SAMPLE_RATE_148_5; INIT_WORK(&ctx->hdmi_audio_wq, had_audio_wq); - ctx->state = hdmi_connector_status_disconnected; card->private_free = hdmi_lpe_audio_free; diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 945f6831f1dd..258396e61829 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -129,7 +129,6 @@ struct snd_intelhad { struct device *dev; struct snd_pcm_chmap *chmap; int underrun_count; - enum hdmi_connector_status state; int tmds_clock_speed; int link_rate; @@ -138,7 +137,7 @@ struct snd_intelhad { void __iomem *mmio_start; unsigned int had_config_offset; struct work_struct hdmi_audio_wq; - struct mutex mutex; /* for protecting chmap, state and eld */ + struct mutex mutex; /* for protecting chmap and eld */ }; #endif /* _INTEL_HDMI_AUDIO_ */ diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index 628c578ecedf..1bc961522d0d 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -591,12 +591,6 @@ union aud_info_frame3 { u32 fr3_val; }; -enum hdmi_connector_status { - hdmi_connector_status_connected = 1, - hdmi_connector_status_disconnected = 2, - hdmi_connector_status_unknown = 3, -}; - #define HDMI_AUDIO_UNDERRUN (1UL<<31) #define HDMI_AUDIO_BUFFER_DONE (1UL<<29) -- cgit v1.2.3 From fa5dfe6a01481a8fa00469be42ea32beb468a501 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 1 Feb 2017 22:03:26 +0100 Subject: ALSA: x86: Drop redundant had_stream_pvt The had_stream_pvt struct assigned to PCM runtime private data tracks merely the stream running status, and the very same information is carried by had_stream->stream_type. Kill it. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 46 ++++------------------------------------ sound/x86/intel_hdmi_audio.h | 6 ------ sound/x86/intel_hdmi_lpe_audio.h | 15 ------------- 3 files changed, 4 insertions(+), 63 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 621be602addd..88e9a91f28a0 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -953,7 +953,6 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) { struct snd_intelhad *intelhaddata; struct snd_pcm_runtime *runtime; - struct had_stream_pvt *stream; struct had_stream_data *had_stream; int retval; @@ -968,31 +967,16 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) dev_dbg(intelhaddata->dev, "%s: HDMI cable plugged-out\n", __func__); retval = -ENODEV; - goto exit_put_handle; - } - - /* Check, if device already in use */ - if (runtime->private_data) { - dev_dbg(intelhaddata->dev, "Device already in use\n"); - retval = -EBUSY; - goto exit_put_handle; + goto error; } /* set the runtime hw parameter with local snd_pcm_hardware struct */ runtime->hw = snd_intel_hadstream; - stream = kzalloc(sizeof(*stream), GFP_KERNEL); - if (!stream) { - retval = -ENOMEM; - goto exit_put_handle; - } - stream->stream_status = STREAM_INIT; - runtime->private_data = stream; - retval = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); if (retval < 0) - goto exit_err; + goto error; /* Make sure, that the period size is always aligned * 64byte boundary @@ -1002,15 +986,12 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) if (retval < 0) { dev_dbg(intelhaddata->dev, "%s:step_size=64 failed,err=%d\n", __func__, retval); - goto exit_err; + goto error; } return retval; -exit_err: - kfree(stream); -exit_put_handle: + error: pm_runtime_put(intelhaddata->dev); - runtime->private_data = NULL; return retval; } @@ -1020,16 +1001,8 @@ exit_put_handle: */ static void had_period_elapsed(struct snd_pcm_substream *substream) { - struct had_stream_pvt *stream; - if (!substream || !substream->runtime) return; - stream = substream->runtime->private_data; - if (!stream) - return; - - if (stream->stream_status != STREAM_RUNNING) - return; snd_pcm_period_elapsed(substream); } @@ -1042,13 +1015,8 @@ static void had_period_elapsed(struct snd_pcm_substream *substream) static int snd_intelhad_close(struct snd_pcm_substream *substream) { struct snd_intelhad *intelhaddata; - struct snd_pcm_runtime *runtime; intelhaddata = snd_pcm_substream_chip(substream); - runtime = substream->runtime; - - if (WARN_ON(!runtime->private_data)) - return 0; intelhaddata->stream_info.buffer_rendered = 0; intelhaddata->stream_info.buffer_ptr = 0; @@ -1062,8 +1030,6 @@ static int snd_intelhad_close(struct snd_pcm_substream *substream) "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_CONNECTED\n", __func__, __LINE__); } - kfree(runtime->private_data); - runtime->private_data = NULL; pm_runtime_put(intelhaddata->dev); return 0; } @@ -1142,11 +1108,9 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, { int retval = 0; struct snd_intelhad *intelhaddata; - struct had_stream_pvt *stream; struct had_stream_data *had_stream; intelhaddata = snd_pcm_substream_chip(substream); - stream = substream->runtime->private_data; had_stream = &intelhaddata->stream_data; switch (cmd) { @@ -1158,7 +1122,6 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, retval = -ENODEV; break; } - stream->stream_status = STREAM_RUNNING; had_stream->stream_type = HAD_RUNNING_STREAM; @@ -1182,7 +1145,6 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, /* Reset buffer pointers */ snd_intelhad_reset_audio(intelhaddata, 1); snd_intelhad_reset_audio(intelhaddata, 0); - stream->stream_status = STREAM_DROPPED; snd_intelhad_enable_audio_int(intelhaddata, false); break; diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 258396e61829..3bd2bb60f1f1 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -86,12 +86,6 @@ struct ring_buf_info { u8 is_valid; }; -struct had_stream_pvt { - enum had_stream_status stream_status; - int stream_ops; - ssize_t dbg_cum_bytes; -}; - struct had_stream_data { enum had_status_stream stream_type; }; diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index 1bc961522d0d..483b9feeff30 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -223,21 +223,6 @@ union otm_hdmi_eld_t { } __packed; }; -/** - * enum had_status - Audio stream states - * - * @STREAM_INIT: Stream initialized - * @STREAM_RUNNING: Stream running - * @STREAM_PAUSED: Stream paused - * @STREAM_DROPPED: Stream dropped - */ -enum had_stream_status { - STREAM_INIT = 0, - STREAM_RUNNING = 1, - STREAM_PAUSED = 2, - STREAM_DROPPED = 3 -}; - /** * enum had_status_stream - HAD stream states */ -- cgit v1.2.3 From 7d9e79869ba2a8a552f4c2cf1df44cf9a0822f02 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 1 Feb 2017 22:25:58 +0100 Subject: ALSA: x86: Drop unused fields from pcm_stream_info The struct pcm_stream_info contains a few unused or useless fields. str_id is always zero, buffer_ptr is volatile, never read, and sfreq is nowhere referred. Kill them. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 19 +------------------ sound/x86/intel_hdmi_audio.h | 3 --- 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 88e9a91f28a0..907e420cd90d 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1019,8 +1019,6 @@ static int snd_intelhad_close(struct snd_pcm_substream *substream) intelhaddata = snd_pcm_substream_chip(substream); intelhaddata->stream_info.buffer_rendered = 0; - intelhaddata->stream_info.buffer_ptr = 0; - intelhaddata->stream_info.str_id = 0; intelhaddata->stream_info.had_substream = NULL; /* Check if following drv_status modification is required - VA */ @@ -1132,7 +1130,6 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_STOP: spin_lock(&intelhaddata->had_spinlock); - intelhaddata->stream_info.str_id = 0; intelhaddata->curr_buf = 0; /* Stop reporting BUFFER_DONE/UNDERRUN to above layers */ @@ -1188,19 +1185,8 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) dev_dbg(intelhaddata->dev, "rate=%d\n", runtime->rate); dev_dbg(intelhaddata->dev, "channels=%d\n", runtime->channels); - if (intelhaddata->stream_info.str_id) { - dev_dbg(intelhaddata->dev, - "_prepare is called for existing str_id#%d\n", - intelhaddata->stream_info.str_id); - retval = snd_intelhad_pcm_trigger(substream, - SNDRV_PCM_TRIGGER_STOP); - return retval; - } - intelhaddata->stream_info.had_substream = substream; - intelhaddata->stream_info.buffer_ptr = 0; intelhaddata->stream_info.buffer_rendered = 0; - intelhaddata->stream_info.sfreq = substream->runtime->rate; /* Get N value in KHz */ disp_samp_freq = intelhaddata->tmds_clock_speed; @@ -1292,10 +1278,7 @@ static snd_pcm_uframes_t snd_intelhad_pcm_pointer( intelhaddata->stream_info.ring_buf_size, &(bytes_rendered)); - intelhaddata->stream_info.buffer_ptr = bytes_to_frames( - substream->runtime, - bytes_rendered + t); - return intelhaddata->stream_info.buffer_ptr; + return bytes_to_frames(substream->runtime, bytes_rendered + t); } /* diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 3bd2bb60f1f1..7bd273ec3275 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -72,12 +72,9 @@ #define AUD_CONFIG_CH_MASK 0x70 struct pcm_stream_info { - int str_id; struct snd_pcm_substream *had_substream; - u32 buffer_ptr; u64 buffer_rendered; u32 ring_buf_size; - int sfreq; }; struct ring_buf_info { -- cgit v1.2.3 From 313d9f28c1d5e0254ca16f2df0f1b737e30c0993 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 2 Feb 2017 13:00:12 +0100 Subject: ALSA: x86: Properly manage PCM substream lifetype The PCM substream is referred not only in the PCM callbacks but also in the irq handler and in the hotplug/unplug codes. The latter code paths don't take the PCM lock, thus the PCM may be released unexpectedly while calling PCM helper functions or accessing pcm->runtime fields. This patch implements a simple refcount to assure the PCM substream accessibility while the other codes are accessing. It needed some code refactoring in the relevant functions for avoiding the doubly spinlocks. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 169 ++++++++++++++++++++++++------------------- sound/x86/intel_hdmi_audio.h | 3 +- 2 files changed, 98 insertions(+), 74 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 907e420cd90d..c209d9498c0e 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -154,6 +154,36 @@ static const struct snd_pcm_hardware snd_intel_hadstream = { .fifo_size = HAD_FIFO_SIZE, }; +/* Get the active PCM substream; + * Call had_substream_put() for unreferecing. + * Don't call this inside had_spinlock, as it takes by itself + */ +static struct snd_pcm_substream * +had_substream_get(struct snd_intelhad *intelhaddata) +{ + struct snd_pcm_substream *substream; + unsigned long flags; + + spin_lock_irqsave(&intelhaddata->had_spinlock, flags); + substream = intelhaddata->stream_info.substream; + if (substream) + intelhaddata->stream_info.substream_refcount++; + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags); + return substream; +} + +/* Unref the active PCM substream; + * Don't call this inside had_spinlock, as it takes by itself + */ +static void had_substream_put(struct snd_intelhad *intelhaddata) +{ + unsigned long flags; + + spin_lock_irqsave(&intelhaddata->had_spinlock, flags); + intelhaddata->stream_info.substream_refcount--; + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags); +} + /* Register access functions */ static inline void mid_hdmi_audio_read(struct snd_intelhad *ctx, u32 reg, u32 *val) @@ -215,7 +245,8 @@ static int had_read_modify(struct snd_intelhad *intelhaddata, u32 offset, } /* - * function to read-modify AUD_CONFIG register on VLV2. + * enable / disable audio configuration + * * The had_read_modify() function should not directly be used on VLV2 for * updating AUD_CONFIG register. * This is because: @@ -227,39 +258,33 @@ static int had_read_modify(struct snd_intelhad *intelhaddata, u32 offset, * causes the "channels" field to be updated as 0xy binary resulting in * bad audio. The fix is to always write the AUD_CONFIG[6:4] with * appropriate value when doing read-modify of AUD_CONFIG register. - * - * @substream: the current substream or NULL if no active substream - * @data : data to be written - * @mask : mask - * */ -static int had_read_modify_aud_config_v2(struct snd_intelhad *intelhaddata, - u32 data, u32 mask) +static void snd_intelhad_enable_audio(struct snd_pcm_substream *substream, + struct snd_intelhad *intelhaddata, + bool enable) { - struct snd_pcm_substream *substream; union aud_cfg cfg_val = {.cfg_regval = 0}; - u8 channels; + u8 channels, data, mask; /* * If substream is NULL, there is no active stream. * In this case just set channels to 2 */ - substream = intelhaddata->stream_info.had_substream; - if (substream && substream->runtime) - channels = substream->runtime->channels; - else - channels = 2; + channels = substream ? substream->runtime->channels : 2; cfg_val.cfg_regx.num_ch = channels - 2; - data = data | cfg_val.cfg_regval; - mask = mask | AUD_CONFIG_CH_MASK; + data = cfg_val.cfg_regval; + if (enable) + data |= 1; + mask = AUD_CONFIG_CH_MASK | 1; dev_dbg(intelhaddata->dev, "%s : data = %x, mask =%x\n", __func__, data, mask); - return had_read_modify(intelhaddata, AUD_CONFIG, data, mask); + had_read_modify(intelhaddata, AUD_CONFIG, data, mask); } +/* enable / disable the audio interface */ static void snd_intelhad_enable_audio_int(struct snd_intelhad *ctx, bool enable) { u32 status_reg; @@ -272,13 +297,6 @@ static void snd_intelhad_enable_audio_int(struct snd_intelhad *ctx, bool enable) } } -static void snd_intelhad_enable_audio(struct snd_intelhad *intelhaddata, - bool enable) -{ - had_read_modify_aud_config_v2(intelhaddata, enable ? BIT(0) : 0, - BIT(0)); -} - static void snd_intelhad_reset_audio(struct snd_intelhad *intelhaddata, u8 reset) { @@ -647,21 +665,17 @@ static void snd_intelhad_prog_dip(struct snd_pcm_substream *substream, /* * snd_intelhad_prog_buffer - programs buffer address and length registers - * @substream:substream for which the prepare function is called - * @intelhaddata:substream private data + * @substream: substream for which the prepare function is called + * @intelhaddata: substream private data * * This function programs ring buffer address and length into registers. */ -static int snd_intelhad_prog_buffer(struct snd_intelhad *intelhaddata, - int start, int end) +static int snd_intelhad_prog_buffer(struct snd_pcm_substream *substream, + struct snd_intelhad *intelhaddata, + int start, int end) { u32 ring_buf_addr, ring_buf_size, period_bytes; u8 i, num_periods; - struct snd_pcm_substream *substream; - - substream = intelhaddata->stream_info.had_substream; - if (WARN_ON(!substream)) - return 0; ring_buf_addr = substream->runtime->dma_addr; ring_buf_size = snd_pcm_lib_buffer_bytes(substream); @@ -989,23 +1003,17 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) goto error; } + spin_lock_irq(&intelhaddata->had_spinlock); + intelhaddata->stream_info.substream = substream; + intelhaddata->stream_info.substream_refcount++; + spin_unlock_irq(&intelhaddata->had_spinlock); + return retval; error: pm_runtime_put(intelhaddata->dev); return retval; } -/* - * had_period_elapsed - updates the hardware pointer status - * @had_substream: substream for which the stream function is called - */ -static void had_period_elapsed(struct snd_pcm_substream *substream) -{ - if (!substream || !substream->runtime) - return; - snd_pcm_period_elapsed(substream); -} - /* * snd_intelhad_close - to free parameteres when stream is stopped * @substream: substream for which the function is called @@ -1019,7 +1027,15 @@ static int snd_intelhad_close(struct snd_pcm_substream *substream) intelhaddata = snd_pcm_substream_chip(substream); intelhaddata->stream_info.buffer_rendered = 0; - intelhaddata->stream_info.had_substream = NULL; + spin_lock_irq(&intelhaddata->had_spinlock); + intelhaddata->stream_info.substream = NULL; + intelhaddata->stream_info.substream_refcount--; + while (intelhaddata->stream_info.substream_refcount > 0) { + spin_unlock_irq(&intelhaddata->had_spinlock); + cpu_relax(); + spin_lock_irq(&intelhaddata->had_spinlock); + } + spin_unlock_irq(&intelhaddata->had_spinlock); /* Check if following drv_status modification is required - VA */ if (intelhaddata->drv_status != HAD_DRV_DISCONNECTED) { @@ -1125,7 +1141,7 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, /* Enable Audio */ snd_intelhad_enable_audio_int(intelhaddata, true); - snd_intelhad_enable_audio(intelhaddata, true); + snd_intelhad_enable_audio(substream, intelhaddata, true); break; case SNDRV_PCM_TRIGGER_STOP: @@ -1138,7 +1154,7 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, spin_unlock(&intelhaddata->had_spinlock); /* Disable Audio */ snd_intelhad_enable_audio_int(intelhaddata, false); - snd_intelhad_enable_audio(intelhaddata, false); + snd_intelhad_enable_audio(substream, intelhaddata, false); /* Reset buffer pointers */ snd_intelhad_reset_audio(intelhaddata, 1); snd_intelhad_reset_audio(intelhaddata, 0); @@ -1185,7 +1201,6 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) dev_dbg(intelhaddata->dev, "rate=%d\n", runtime->rate); dev_dbg(intelhaddata->dev, "channels=%d\n", runtime->channels); - intelhaddata->stream_info.had_substream = substream; intelhaddata->stream_info.buffer_rendered = 0; /* Get N value in KHz */ @@ -1211,7 +1226,7 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) retval = snd_intelhad_audio_ctrl(substream, intelhaddata); /* Prog buffer address */ - retval = snd_intelhad_prog_buffer(intelhaddata, + retval = snd_intelhad_prog_buffer(substream, intelhaddata, HAD_BUF_TYPE_A, HAD_BUF_TYPE_D); /* @@ -1306,12 +1321,12 @@ static int hdmi_audio_mode_change(struct snd_intelhad *intelhaddata) u32 disp_samp_freq, n_param; u32 link_rate = 0; - substream = intelhaddata->stream_info.had_substream; - if (!substream || !substream->runtime) + substream = had_substream_get(intelhaddata); + if (!substream) return 0; /* Disable Audio */ - snd_intelhad_enable_audio(intelhaddata, false); + snd_intelhad_enable_audio(substream, intelhaddata, false); /* Update CTS value */ disp_samp_freq = intelhaddata->tmds_clock_speed; @@ -1332,9 +1347,10 @@ static int hdmi_audio_mode_change(struct snd_intelhad *intelhaddata) n_param, intelhaddata); /* Enable Audio */ - snd_intelhad_enable_audio(intelhaddata, true); + snd_intelhad_enable_audio(substream, intelhaddata, true); out: + had_substream_put(intelhaddata); return retval; } @@ -1348,11 +1364,9 @@ static int hdmi_lpe_audio_suspend(struct platform_device *pdev, pm_message_t state) { struct had_stream_data *had_stream; - struct snd_pcm_substream *substream; struct snd_intelhad *intelhaddata = platform_get_drvdata(pdev); had_stream = &intelhaddata->stream_data; - substream = intelhaddata->stream_info.had_substream; if (!pm_runtime_status_suspended(intelhaddata->dev)) { dev_err(intelhaddata->dev, "audio stream is active\n"); @@ -1463,10 +1477,10 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) enum intel_had_aud_buf_type buf_id; enum intel_had_aud_buf_type buff_done; struct pcm_stream_info *stream; + struct snd_pcm_substream *substream; u32 buf_size; struct had_stream_data *had_stream; int intr_count; - enum had_status_stream stream_type; unsigned long flags; had_stream = &intelhaddata->stream_data; @@ -1484,7 +1498,6 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) intelhaddata->buff_done = buf_id; buff_done = intelhaddata->buff_done; buf_size = intelhaddata->buf_info[buf_id].buf_size; - stream_type = had_stream->stream_type; /* Every debug statement has an implication * of ~5msec. Thus, avoid having >3 debug statements @@ -1536,11 +1549,13 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) /* In case of actual data, * report buffer_done to above ALSA layer */ - buf_size = intelhaddata->buf_info[buf_id].buf_size; - if (stream_type >= HAD_RUNNING_STREAM) { + substream = had_substream_get(intelhaddata); + if (substream) { + buf_size = intelhaddata->buf_info[buf_id].buf_size; intelhaddata->stream_info.buffer_rendered += (intr_count * buf_size); - had_period_elapsed(stream->had_substream); + snd_pcm_period_elapsed(substream); + had_substream_put(intelhaddata); } return 0; @@ -1552,6 +1567,7 @@ static int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) enum intel_had_aud_buf_type buf_id; struct pcm_stream_info *stream; struct had_stream_data *had_stream; + struct snd_pcm_substream *substream; enum had_status_stream stream_type; unsigned long flags; int drv_status; @@ -1582,7 +1598,11 @@ static int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) if (stream_type == HAD_RUNNING_STREAM) { /* Report UNDERRUN error to above layers */ - snd_pcm_stop_xrun(stream->had_substream); + substream = had_substream_get(intelhaddata); + if (substream) { + snd_pcm_stop_xrun(substream); + had_substream_put(intelhaddata); + } } return 0; @@ -1595,7 +1615,6 @@ static void had_process_hot_plug(struct snd_intelhad *intelhaddata) struct snd_pcm_substream *substream; struct had_stream_data *had_stream; - substream = intelhaddata->stream_info.had_substream; had_stream = &intelhaddata->stream_data; spin_lock_irq(&intelhaddata->had_spinlock); @@ -1617,11 +1636,13 @@ static void had_process_hot_plug(struct snd_intelhad *intelhaddata) buf_id); /* Safety check */ + substream = had_substream_get(intelhaddata); if (substream) { dev_dbg(intelhaddata->dev, "Force to stop the active stream by disconnection\n"); /* Set runtime->state to hw_params done */ snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); + had_substream_put(intelhaddata); } had_build_channel_allocation_map(intelhaddata); @@ -1632,38 +1653,40 @@ static void had_process_hot_unplug(struct snd_intelhad *intelhaddata) { enum intel_had_aud_buf_type buf_id; struct had_stream_data *had_stream; + struct snd_pcm_substream *substream; had_stream = &intelhaddata->stream_data; buf_id = intelhaddata->curr_buf; + substream = had_substream_get(intelhaddata); + spin_lock_irq(&intelhaddata->had_spinlock); if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { dev_dbg(intelhaddata->dev, "Device already disconnected\n"); spin_unlock_irq(&intelhaddata->had_spinlock); - return; + goto out; } /* Disable Audio */ snd_intelhad_enable_audio_int(intelhaddata, false); - snd_intelhad_enable_audio(intelhaddata, false); + snd_intelhad_enable_audio(substream, intelhaddata, false); intelhaddata->drv_status = HAD_DRV_DISCONNECTED; dev_dbg(intelhaddata->dev, "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", __func__, __LINE__); + had_stream->stream_type = HAD_INIT; + spin_unlock_irq(&intelhaddata->had_spinlock); /* Report to above ALSA layer */ - if (intelhaddata->stream_info.had_substream != NULL) { - spin_unlock_irq(&intelhaddata->had_spinlock); - snd_pcm_stop(intelhaddata->stream_info.had_substream, - SNDRV_PCM_STATE_SETUP); - spin_lock_irq(&intelhaddata->had_spinlock); - } + if (substream) + snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); - had_stream->stream_type = HAD_INIT; - spin_unlock_irq(&intelhaddata->had_spinlock); + out: + if (substream) + had_substream_put(intelhaddata); kfree(intelhaddata->chmap->chmap); intelhaddata->chmap->chmap = NULL; } diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 7bd273ec3275..6e5a1978e9c7 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -72,9 +72,10 @@ #define AUD_CONFIG_CH_MASK 0x70 struct pcm_stream_info { - struct snd_pcm_substream *had_substream; + struct snd_pcm_substream *substream; u64 buffer_rendered; u32 ring_buf_size; + int substream_refcount; }; struct ring_buf_info { -- cgit v1.2.3 From 182cdf23dbf6672954ac646871bf5902050268c7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 2 Feb 2017 14:43:39 +0100 Subject: ALSA: x86: Implement runtime PM Although the driver has some PM callbacks, it doesn't do it right: - the suspend callback doesn't handle to suspend the running PCM, - the runtime PM ops are missing, - pm_runtime_get_sync() isn't used at the right place. This patch covers the above and provides the basic runtime PM functionality. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 127 +++++++++++++++++-------------------------- 1 file changed, 50 insertions(+), 77 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index c209d9498c0e..04ff7f14fe12 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -975,7 +975,7 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) runtime = substream->runtime; intelhaddata->underrun_count = 0; - pm_runtime_get(intelhaddata->dev); + pm_runtime_get_sync(intelhaddata->dev); if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { dev_dbg(intelhaddata->dev, "%s: HDMI cable plugged-out\n", @@ -1129,6 +1129,8 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, switch (cmd) { case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: /* Disable local INTRs till register prgmng is done */ if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { dev_dbg(intelhaddata->dev, @@ -1145,6 +1147,8 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, break; case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: spin_lock(&intelhaddata->had_spinlock); intelhaddata->curr_buf = 0; @@ -1354,80 +1358,6 @@ out: return retval; } -/* - * hdmi_lpe_audio_suspend - power management suspend function - * @pdev: platform device - * - * This function is called to suspend the hdmi audio. - */ -static int hdmi_lpe_audio_suspend(struct platform_device *pdev, - pm_message_t state) -{ - struct had_stream_data *had_stream; - struct snd_intelhad *intelhaddata = platform_get_drvdata(pdev); - - had_stream = &intelhaddata->stream_data; - - if (!pm_runtime_status_suspended(intelhaddata->dev)) { - dev_err(intelhaddata->dev, "audio stream is active\n"); - return -EAGAIN; - } - - spin_lock_irq(&intelhaddata->had_spinlock); - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { - spin_unlock_irq(&intelhaddata->had_spinlock); - dev_dbg(intelhaddata->dev, "had not connected\n"); - return 0; - } - - if (intelhaddata->drv_status == HAD_DRV_SUSPENDED) { - spin_unlock_irq(&intelhaddata->had_spinlock); - dev_dbg(intelhaddata->dev, "had already suspended\n"); - return 0; - } - - intelhaddata->drv_status = HAD_DRV_SUSPENDED; - dev_dbg(intelhaddata->dev, - "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_SUSPENDED\n", - __func__, __LINE__); - - spin_unlock_irq(&intelhaddata->had_spinlock); - snd_intelhad_enable_audio_int(intelhaddata, false); - return 0; -} - -/* - * hdmi_lpe_audio_resume - power management resume function - * @pdev: platform device - * - * This function is called to resume the hdmi audio. - */ -static int hdmi_lpe_audio_resume(struct platform_device *pdev) -{ - struct snd_intelhad *intelhaddata = platform_get_drvdata(pdev); - - spin_lock_irq(&intelhaddata->had_spinlock); - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { - spin_unlock_irq(&intelhaddata->had_spinlock); - dev_dbg(intelhaddata->dev, "had not connected\n"); - return 0; - } - - if (intelhaddata->drv_status != HAD_DRV_SUSPENDED) { - spin_unlock_irq(&intelhaddata->had_spinlock); - dev_dbg(intelhaddata->dev, "had is not in suspended state\n"); - return 0; - } - - intelhaddata->drv_status = HAD_DRV_CONNECTED; - dev_dbg(intelhaddata->dev, - "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", - __func__, __LINE__); - spin_unlock_irq(&intelhaddata->had_spinlock); - snd_intelhad_enable_audio_int(intelhaddata, true); - return 0; -} - static inline int had_chk_intrmiss(struct snd_intelhad *intelhaddata, enum intel_had_aud_buf_type buf_id) { @@ -1808,6 +1738,7 @@ static void had_audio_wq(struct work_struct *work) container_of(work, struct snd_intelhad, hdmi_audio_wq); struct intel_hdmi_lpe_audio_pdata *pdata = ctx->dev->platform_data; + pm_runtime_get_sync(ctx->dev); mutex_lock(&ctx->mutex); if (!pdata->hdmi_connected) { dev_dbg(ctx->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG\n", @@ -1848,6 +1779,44 @@ static void had_audio_wq(struct work_struct *work) hdmi_audio_mode_change(ctx); } mutex_unlock(&ctx->mutex); + pm_runtime_put(ctx->dev); +} + +/* + * PM callbacks + */ + +static int hdmi_lpe_audio_runtime_suspend(struct device *dev) +{ + struct snd_intelhad *ctx = dev_get_drvdata(dev); + struct snd_pcm_substream *substream; + + substream = had_substream_get(ctx); + if (substream) { + snd_pcm_suspend(substream); + had_substream_put(ctx); + } + + return 0; +} + +static int hdmi_lpe_audio_suspend(struct device *dev) +{ + struct snd_intelhad *ctx = dev_get_drvdata(dev); + int err; + + err = hdmi_lpe_audio_runtime_suspend(dev); + if (!err) + snd_power_change_state(ctx->card, SNDRV_CTL_POWER_D3hot); + return err; +} + +static int hdmi_lpe_audio_resume(struct device *dev) +{ + struct snd_intelhad *ctx = dev_get_drvdata(dev); + + snd_power_change_state(ctx->card, SNDRV_CTL_POWER_D0); + return 0; } /* release resources */ @@ -2021,14 +1990,18 @@ static int hdmi_lpe_audio_remove(struct platform_device *pdev) return 0; } +static const struct dev_pm_ops hdmi_lpe_audio_pm = { + SET_SYSTEM_SLEEP_PM_OPS(hdmi_lpe_audio_suspend, hdmi_lpe_audio_resume) + SET_RUNTIME_PM_OPS(hdmi_lpe_audio_runtime_suspend, NULL, NULL) +}; + static struct platform_driver hdmi_lpe_audio_driver = { .driver = { .name = "hdmi-lpe-audio", + .pm = &hdmi_lpe_audio_pm, }, .probe = hdmi_lpe_audio_probe, .remove = hdmi_lpe_audio_remove, - .suspend = hdmi_lpe_audio_suspend, - .resume = hdmi_lpe_audio_resume }; module_platform_driver(hdmi_lpe_audio_driver); -- cgit v1.2.3 From f69bd104b5cded0db547636fddd9512d7e6cfbf3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 2 Feb 2017 14:57:22 +0100 Subject: ALSA: x86: Move stream status into pcm_stream_info The only remaining field in struct had_stream_data is stream_type that holds the current stream status. Such information fits better in struct pcm_stream_info, so move it as a boolean "running" field to be clearer. This allows us to get rid or had_stream_data definition and references. Also, the superfluous status check get removed in a couple of places where we can call PCM helpers in anyway. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 50 +++++++++++----------------------------- sound/x86/intel_hdmi_audio.h | 6 +---- sound/x86/intel_hdmi_lpe_audio.h | 8 ------- 3 files changed, 14 insertions(+), 50 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 04ff7f14fe12..985b7e8d4eae 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -967,11 +967,9 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) { struct snd_intelhad *intelhaddata; struct snd_pcm_runtime *runtime; - struct had_stream_data *had_stream; int retval; intelhaddata = snd_pcm_substream_chip(substream); - had_stream = &intelhaddata->stream_data; runtime = substream->runtime; intelhaddata->underrun_count = 0; @@ -1122,10 +1120,8 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, { int retval = 0; struct snd_intelhad *intelhaddata; - struct had_stream_data *had_stream; intelhaddata = snd_pcm_substream_chip(substream); - had_stream = &intelhaddata->stream_data; switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -1139,7 +1135,7 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, break; } - had_stream->stream_type = HAD_RUNNING_STREAM; + intelhaddata->stream_info.running = true; /* Enable Audio */ snd_intelhad_enable_audio_int(intelhaddata, true); @@ -1154,7 +1150,7 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, /* Stop reporting BUFFER_DONE/UNDERRUN to above layers */ - had_stream->stream_type = HAD_INIT; + intelhaddata->stream_info.running = false; spin_unlock(&intelhaddata->had_spinlock); /* Disable Audio */ snd_intelhad_enable_audio_int(intelhaddata, false); @@ -1184,11 +1180,9 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) u32 link_rate = 0; struct snd_intelhad *intelhaddata; struct snd_pcm_runtime *runtime; - struct had_stream_data *had_stream; intelhaddata = snd_pcm_substream_chip(substream); runtime = substream->runtime; - had_stream = &intelhaddata->stream_data; if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { dev_dbg(intelhaddata->dev, "%s: HDMI cable plugged-out\n", @@ -1364,9 +1358,6 @@ static inline int had_chk_intrmiss(struct snd_intelhad *intelhaddata, int i, intr_count = 0; enum intel_had_aud_buf_type buff_done; u32 buf_size, buf_addr; - struct had_stream_data *had_stream; - - had_stream = &intelhaddata->stream_data; buff_done = buf_id; @@ -1409,11 +1400,9 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) struct pcm_stream_info *stream; struct snd_pcm_substream *substream; u32 buf_size; - struct had_stream_data *had_stream; int intr_count; unsigned long flags; - had_stream = &intelhaddata->stream_data; stream = &intelhaddata->stream_info; intr_count = 1; @@ -1435,7 +1424,7 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) */ /* Check for any intr_miss in case of active playback */ - if (had_stream->stream_type == HAD_RUNNING_STREAM) { + if (stream->running) { intr_count = had_chk_intrmiss(intelhaddata, buf_id); if (!intr_count || (intr_count > 3)) { spin_unlock_irqrestore(&intelhaddata->had_spinlock, @@ -1450,7 +1439,7 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) intelhaddata->buf_info[buf_id].is_valid = true; if (intelhaddata->valid_buf_cnt-1 == buf_id) { - if (had_stream->stream_type >= HAD_RUNNING_STREAM) + if (stream->running) intelhaddata->curr_buf = HAD_BUF_TYPE_A; } else intelhaddata->curr_buf = buf_id + 1; @@ -1496,27 +1485,23 @@ static int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) { enum intel_had_aud_buf_type buf_id; struct pcm_stream_info *stream; - struct had_stream_data *had_stream; struct snd_pcm_substream *substream; - enum had_status_stream stream_type; unsigned long flags; int drv_status; - had_stream = &intelhaddata->stream_data; stream = &intelhaddata->stream_info; spin_lock_irqsave(&intelhaddata->had_spinlock, flags); buf_id = intelhaddata->curr_buf; - stream_type = had_stream->stream_type; intelhaddata->buff_done = buf_id; drv_status = intelhaddata->drv_status; - if (stream_type == HAD_RUNNING_STREAM) + if (stream->running) intelhaddata->curr_buf = HAD_BUF_TYPE_A; spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags); - dev_dbg(intelhaddata->dev, "Enter:%s buf_id=%d, stream_type=%d\n", - __func__, buf_id, stream_type); + dev_dbg(intelhaddata->dev, "Enter:%s buf_id=%d, stream_running=%d\n", + __func__, buf_id, stream->running); snd_intelhad_handle_underrun(intelhaddata); @@ -1526,13 +1511,11 @@ static int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) return 0; } - if (stream_type == HAD_RUNNING_STREAM) { - /* Report UNDERRUN error to above layers */ - substream = had_substream_get(intelhaddata); - if (substream) { - snd_pcm_stop_xrun(substream); - had_substream_put(intelhaddata); - } + /* Report UNDERRUN error to above layers */ + substream = had_substream_get(intelhaddata); + if (substream) { + snd_pcm_stop_xrun(substream); + had_substream_put(intelhaddata); } return 0; @@ -1543,9 +1526,6 @@ static void had_process_hot_plug(struct snd_intelhad *intelhaddata) { enum intel_had_aud_buf_type buf_id; struct snd_pcm_substream *substream; - struct had_stream_data *had_stream; - - had_stream = &intelhaddata->stream_data; spin_lock_irq(&intelhaddata->had_spinlock); if (intelhaddata->drv_status == HAD_DRV_CONNECTED) { @@ -1582,10 +1562,8 @@ static void had_process_hot_plug(struct snd_intelhad *intelhaddata) static void had_process_hot_unplug(struct snd_intelhad *intelhaddata) { enum intel_had_aud_buf_type buf_id; - struct had_stream_data *had_stream; struct snd_pcm_substream *substream; - had_stream = &intelhaddata->stream_data; buf_id = intelhaddata->curr_buf; substream = had_substream_get(intelhaddata); @@ -1607,7 +1585,6 @@ static void had_process_hot_unplug(struct snd_intelhad *intelhaddata) dev_dbg(intelhaddata->dev, "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", __func__, __LINE__); - had_stream->stream_type = HAD_INIT; spin_unlock_irq(&intelhaddata->had_spinlock); /* Report to above ALSA layer */ @@ -1775,8 +1752,7 @@ static void had_audio_wq(struct work_struct *work) had_process_hot_plug(ctx); /* Process mode change if stream is active */ - if (ctx->stream_data.stream_type == HAD_RUNNING_STREAM) - hdmi_audio_mode_change(ctx); + hdmi_audio_mode_change(ctx); } mutex_unlock(&ctx->mutex); pm_runtime_put(ctx->dev); diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 6e5a1978e9c7..2804e94a6710 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -76,6 +76,7 @@ struct pcm_stream_info { u64 buffer_rendered; u32 ring_buf_size; int substream_refcount; + bool running; }; struct ring_buf_info { @@ -84,10 +85,6 @@ struct ring_buf_info { u8 is_valid; }; -struct had_stream_data { - enum had_status_stream stream_type; -}; - /** * struct snd_intelhad - intelhad driver structure * @@ -115,7 +112,6 @@ struct snd_intelhad { enum intel_had_aud_buf_type curr_buf; int valid_buf_cnt; unsigned int aes_bits; - struct had_stream_data stream_data; spinlock_t had_spinlock; enum intel_had_aud_buf_type buff_done; struct device *dev; diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index 483b9feeff30..1e7e6db987c6 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -223,14 +223,6 @@ union otm_hdmi_eld_t { } __packed; }; -/** - * enum had_status_stream - HAD stream states - */ -enum had_status_stream { - HAD_INIT = 0, - HAD_RUNNING_STREAM, -}; - enum had_drv_status { HAD_DRV_CONNECTED, HAD_DRV_RUNNING, -- cgit v1.2.3 From df0435db1db9e385acdc0a354896d2c0e878dbd5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 2 Feb 2017 15:37:11 +0100 Subject: ALSA: x86: Use the standard ELD bytes definitions We have some constants defined in drm/drm_edid.h, and clean up our own definitions. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 14 ++--- sound/x86/intel_hdmi_audio.h | 3 +- sound/x86/intel_hdmi_lpe_audio.h | 119 --------------------------------------- 3 files changed, 9 insertions(+), 127 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 985b7e8d4eae..496d3e92b2a8 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -451,7 +451,7 @@ static int snd_intelhad_channel_allocation(struct snd_intelhad *intelhaddata, */ for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) { - if (intelhaddata->eld.speaker_allocation_block & (1 << i)) + if (intelhaddata->eld[DRM_ELD_SPEAKER] & (1 << i)) spk_mask |= eld_speaker_allocation_bits[i]; } @@ -496,8 +496,8 @@ static void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata) return; } - dev_dbg(intelhaddata->dev, "eld.speaker_allocation_block = %x\n", - intelhaddata->eld.speaker_allocation_block); + dev_dbg(intelhaddata->dev, "eld speaker = %x\n", + intelhaddata->eld[DRM_ELD_SPEAKER]); /* WA: Fix the max channel supported to 8 */ @@ -508,14 +508,14 @@ static void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata) */ /* if 0x2F < eld < 0x4F fall back to 0x2f, else fall back to 0x4F */ - eld_high = intelhaddata->eld.speaker_allocation_block & eld_high_mask; + eld_high = intelhaddata->eld[DRM_ELD_SPEAKER] & eld_high_mask; if ((eld_high & (eld_high-1)) && (eld_high > 0x1F)) { /* eld_high & (eld_high-1): if more than 1 bit set */ /* 0x1F: 7 channels */ for (i = 1; i < 4; i++) { high_msb = eld_high & (0x80 >> i); if (high_msb) { - intelhaddata->eld.speaker_allocation_block &= + intelhaddata->eld[DRM_ELD_SPEAKER] &= high_msb | 0xF; break; } @@ -523,7 +523,7 @@ static void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata) } for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) { - if (intelhaddata->eld.speaker_allocation_block & (1 << i)) + if (intelhaddata->eld[DRM_ELD_SPEAKER] & (1 << i)) spk_mask |= eld_speaker_allocation_bits[i]; } @@ -1743,7 +1743,7 @@ static void had_audio_wq(struct work_struct *work) break; } - memcpy(&ctx->eld, eld->eld_data, sizeof(ctx->eld)); + memcpy(ctx->eld, eld->eld_data, sizeof(ctx->eld)); ctx->dp_output = pdata->dp_output; ctx->tmds_clock_speed = pdata->tmds_clock_speed; diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 2804e94a6710..4ccaa8b18566 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -37,6 +37,7 @@ #include #include #include +#include #include "intel_hdmi_lpe_audio.h" #define PCM_INDEX 0 @@ -107,7 +108,7 @@ struct snd_intelhad { enum had_drv_status drv_status; struct ring_buf_info buf_info[HAD_NUM_OF_RING_BUFS]; struct pcm_stream_info stream_info; - union otm_hdmi_eld_t eld; + unsigned char eld[HDMI_MAX_ELD_BYTES]; bool dp_output; enum intel_had_aud_buf_type curr_buf; int valid_buf_cnt; diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index 1e7e6db987c6..f9c184960b34 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -104,125 +104,6 @@ #define MAX_CNT 0xFF #define HAD_SUSPEND_DELAY 1000 -#define OTM_HDMI_ELD_SIZE 128 - -union otm_hdmi_eld_t { - unsigned char eld_data[OTM_HDMI_ELD_SIZE]; - struct { - /* Byte[0] = ELD Version Number */ - union { - unsigned char byte0; - struct { - unsigned char reserved:3; /* Reserf */ - unsigned char eld_ver:5; /* ELD Version Number */ - /* 00000b - reserved - * 00001b - first rev, obsoleted - * 00010b - version 2, supporting CEA version - * 861D or below - * 00011b:11111b - reserved - * for future - */ - }; - }; - - /* Byte[1] = Vendor Version Field */ - union { - unsigned char vendor_version; - struct { - unsigned char reserved1:3; - unsigned char veld_ver:5; /* Version number of the ELD - * extension. This value is - * provisioned and unique to - * each vendor. - */ - }; - }; - - /* Byte[2] = Baseline Length field */ - unsigned char baseline_eld_length; /* Length of the Baseline structure - * divided by Four. - */ - - /* Byte [3] = Reserved for future use */ - unsigned char byte3; - - /* Starting of the BaseLine EELD structure - * Byte[4] = Monitor Name Length - */ - union { - unsigned char byte4; - struct { - unsigned char mnl:5; - unsigned char cea_edid_rev_id:3; - }; - }; - - /* Byte[5] = Capabilities */ - union { - unsigned char capabilities; - struct { - unsigned char hdcp:1; /* HDCP support */ - unsigned char ai_support:1; /* AI support */ - unsigned char connection_type:2; /* Connection type - * 00 - HDMI - * 01 - DP - * 10 -11 Reserved - * for future - * connection types - */ - unsigned char sadc:4; /* Indicates number of 3 bytes - * Short Audio Descriptors. - */ - }; - }; - - /* Byte[6] = Audio Synch Delay */ - unsigned char audio_synch_delay; /* Amount of time reported by the - * sink that the video trails audio - * in milliseconds. - */ - - /* Byte[7] = Speaker Allocation Block */ - union { - unsigned char speaker_allocation_block; - struct { - unsigned char flr:1; /*Front Left and Right channels*/ - unsigned char lfe:1; /*Low Frequency Effect channel*/ - unsigned char fc:1; /*Center transmission channel*/ - unsigned char rlr:1; /*Rear Left and Right channels*/ - unsigned char rc:1; /*Rear Center channel*/ - unsigned char flrc:1; /*Front left and Right of Center - *transmission channels - */ - unsigned char rlrc:1; /*Rear left and Right of Center - *transmission channels - */ - unsigned char reserved3:1; /* Reserved */ - }; - }; - - /* Byte[8 - 15] - 8 Byte port identification value */ - unsigned char port_id_value[8]; - - /* Byte[16 - 17] - 2 Byte Manufacturer ID */ - unsigned char manufacturer_id[2]; - - /* Byte[18 - 19] - 2 Byte Product ID */ - unsigned char product_id[2]; - - /* Byte [20-83] - 64 Bytes of BaseLine Data */ - unsigned char mn_sand_sads[64]; /* This will include - * - ASCII string of Monitor name - * - List of 3 byte SADs - * - Zero padding - */ - - /* Vendor ELD Block should continue here! - * No Vendor ELD block defined as of now. - */ - } __packed; -}; - enum had_drv_status { HAD_DRV_CONNECTED, HAD_DRV_RUNNING, -- cgit v1.2.3 From 7ceba75f21e4ecb520b110ffada72cc0c9f5c072 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 2 Feb 2017 15:58:35 +0100 Subject: ALSA: x86: Reduce redundant register field names Currently each register definition contains the own prefix in the union struct itself; for example, union aud_ch_status_0 has status_0_regx and status_0_regval fields. These are simply superfluous, since usually the type of the variable is seen in its declaration or in its name. In this patch, we cut off these prefixes. Now all register definitions have regx and regval fields consistently, instead. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 102 ++++++++++++------------- sound/x86/intel_hdmi_audio.h | 1 - sound/x86/intel_hdmi_lpe_audio.h | 156 ++++++++++----------------------------- 3 files changed, 90 insertions(+), 169 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 496d3e92b2a8..f825d514500e 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -263,7 +263,7 @@ static void snd_intelhad_enable_audio(struct snd_pcm_substream *substream, struct snd_intelhad *intelhaddata, bool enable) { - union aud_cfg cfg_val = {.cfg_regval = 0}; + union aud_cfg cfg_val = {.regval = 0}; u8 channels, data, mask; /* @@ -271,9 +271,9 @@ static void snd_intelhad_enable_audio(struct snd_pcm_substream *substream, * In this case just set channels to 2 */ channels = substream ? substream->runtime->channels : 2; - cfg_val.cfg_regx.num_ch = channels - 2; + cfg_val.regx.num_ch = channels - 2; - data = cfg_val.cfg_regval; + data = cfg_val.regval; if (enable) data |= 1; mask = AUD_CONFIG_CH_MASK | 1; @@ -310,39 +310,39 @@ static void snd_intelhad_reset_audio(struct snd_intelhad *intelhaddata, static int had_prog_status_reg(struct snd_pcm_substream *substream, struct snd_intelhad *intelhaddata) { - union aud_cfg cfg_val = {.cfg_regval = 0}; - union aud_ch_status_0 ch_stat0 = {.status_0_regval = 0}; - union aud_ch_status_1 ch_stat1 = {.status_1_regval = 0}; + union aud_cfg cfg_val = {.regval = 0}; + union aud_ch_status_0 ch_stat0 = {.regval = 0}; + union aud_ch_status_1 ch_stat1 = {.regval = 0}; int format; - ch_stat0.status_0_regx.lpcm_id = (intelhaddata->aes_bits & + ch_stat0.regx.lpcm_id = (intelhaddata->aes_bits & IEC958_AES0_NONAUDIO) >> 1; - ch_stat0.status_0_regx.clk_acc = (intelhaddata->aes_bits & + ch_stat0.regx.clk_acc = (intelhaddata->aes_bits & IEC958_AES3_CON_CLOCK) >> 4; - cfg_val.cfg_regx.val_bit = ch_stat0.status_0_regx.lpcm_id; + cfg_val.regx.val_bit = ch_stat0.regx.lpcm_id; switch (substream->runtime->rate) { case AUD_SAMPLE_RATE_32: - ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_32KHZ; + ch_stat0.regx.samp_freq = CH_STATUS_MAP_32KHZ; break; case AUD_SAMPLE_RATE_44_1: - ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_44KHZ; + ch_stat0.regx.samp_freq = CH_STATUS_MAP_44KHZ; break; case AUD_SAMPLE_RATE_48: - ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_48KHZ; + ch_stat0.regx.samp_freq = CH_STATUS_MAP_48KHZ; break; case AUD_SAMPLE_RATE_88_2: - ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_88KHZ; + ch_stat0.regx.samp_freq = CH_STATUS_MAP_88KHZ; break; case AUD_SAMPLE_RATE_96: - ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_96KHZ; + ch_stat0.regx.samp_freq = CH_STATUS_MAP_96KHZ; break; case AUD_SAMPLE_RATE_176_4: - ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_176KHZ; + ch_stat0.regx.samp_freq = CH_STATUS_MAP_176KHZ; break; case AUD_SAMPLE_RATE_192: - ch_stat0.status_0_regx.samp_freq = CH_STATUS_MAP_192KHZ; + ch_stat0.regx.samp_freq = CH_STATUS_MAP_192KHZ; break; default: @@ -351,23 +351,23 @@ static int had_prog_status_reg(struct snd_pcm_substream *substream, } had_write_register(intelhaddata, - AUD_CH_STATUS_0, ch_stat0.status_0_regval); + AUD_CH_STATUS_0, ch_stat0.regval); format = substream->runtime->format; if (format == SNDRV_PCM_FORMAT_S16_LE) { - ch_stat1.status_1_regx.max_wrd_len = MAX_SMPL_WIDTH_20; - ch_stat1.status_1_regx.wrd_len = SMPL_WIDTH_16BITS; + ch_stat1.regx.max_wrd_len = MAX_SMPL_WIDTH_20; + ch_stat1.regx.wrd_len = SMPL_WIDTH_16BITS; } else if (format == SNDRV_PCM_FORMAT_S24_LE) { - ch_stat1.status_1_regx.max_wrd_len = MAX_SMPL_WIDTH_24; - ch_stat1.status_1_regx.wrd_len = SMPL_WIDTH_24BITS; + ch_stat1.regx.max_wrd_len = MAX_SMPL_WIDTH_24; + ch_stat1.regx.wrd_len = SMPL_WIDTH_24BITS; } else { - ch_stat1.status_1_regx.max_wrd_len = 0; - ch_stat1.status_1_regx.wrd_len = 0; + ch_stat1.regx.max_wrd_len = 0; + ch_stat1.regx.wrd_len = 0; } had_write_register(intelhaddata, - AUD_CH_STATUS_1, ch_stat1.status_1_regval); + AUD_CH_STATUS_1, ch_stat1.regval); return 0; } @@ -379,26 +379,26 @@ static int had_prog_status_reg(struct snd_pcm_substream *substream, static int snd_intelhad_audio_ctrl(struct snd_pcm_substream *substream, struct snd_intelhad *intelhaddata) { - union aud_cfg cfg_val = {.cfg_regval = 0}; - union aud_buf_config buf_cfg = {.buf_cfgval = 0}; + union aud_cfg cfg_val = {.regval = 0}; + union aud_buf_config buf_cfg = {.regval = 0}; u8 channels; had_prog_status_reg(substream, intelhaddata); - buf_cfg.buf_cfg_regx.audio_fifo_watermark = FIFO_THRESHOLD; - buf_cfg.buf_cfg_regx.dma_fifo_watermark = DMA_FIFO_THRESHOLD; - buf_cfg.buf_cfg_regx.aud_delay = 0; - had_write_register(intelhaddata, AUD_BUF_CONFIG, buf_cfg.buf_cfgval); + buf_cfg.regx.audio_fifo_watermark = FIFO_THRESHOLD; + buf_cfg.regx.dma_fifo_watermark = DMA_FIFO_THRESHOLD; + buf_cfg.regx.aud_delay = 0; + had_write_register(intelhaddata, AUD_BUF_CONFIG, buf_cfg.regval); channels = substream->runtime->channels; - cfg_val.cfg_regx.num_ch = channels - 2; + cfg_val.regx.num_ch = channels - 2; if (channels <= 2) - cfg_val.cfg_regx.layout = LAYOUT0; + cfg_val.regx.layout = LAYOUT0; else - cfg_val.cfg_regx.layout = LAYOUT1; + cfg_val.regx.layout = LAYOUT1; - cfg_val.cfg_regx.val_bit = 1; - had_write_register(intelhaddata, AUD_CONFIG, cfg_val.cfg_regval); + cfg_val.regx.val_bit = 1; + had_write_register(intelhaddata, AUD_CONFIG, cfg_val.regval); return 0; } @@ -618,49 +618,49 @@ static void snd_intelhad_prog_dip(struct snd_pcm_substream *substream, struct snd_intelhad *intelhaddata) { int i; - union aud_ctrl_st ctrl_state = {.ctrl_val = 0}; - union aud_info_frame2 frame2 = {.fr2_val = 0}; - union aud_info_frame3 frame3 = {.fr3_val = 0}; + union aud_ctrl_st ctrl_state = {.regval = 0}; + union aud_info_frame2 frame2 = {.regval = 0}; + union aud_info_frame3 frame3 = {.regval = 0}; u8 checksum = 0; u32 info_frame; int channels; channels = substream->runtime->channels; - had_write_register(intelhaddata, AUD_CNTL_ST, ctrl_state.ctrl_val); + had_write_register(intelhaddata, AUD_CNTL_ST, ctrl_state.regval); if (intelhaddata->dp_output) { info_frame = DP_INFO_FRAME_WORD1; - frame2.fr2_val = 1; + frame2.regval = 1; } else { info_frame = HDMI_INFO_FRAME_WORD1; - frame2.fr2_regx.chnl_cnt = substream->runtime->channels - 1; + frame2.regx.chnl_cnt = substream->runtime->channels - 1; - frame3.fr3_regx.chnl_alloc = snd_intelhad_channel_allocation( + frame3.regx.chnl_alloc = snd_intelhad_channel_allocation( intelhaddata, channels); /* Calculte the byte wide checksum for all valid DIP words */ for (i = 0; i < BYTES_PER_WORD; i++) - checksum += (info_frame >> i*BITS_PER_BYTE) & MASK_BYTE0; + checksum += (info_frame >> (i * 8)) & 0xff; for (i = 0; i < BYTES_PER_WORD; i++) - checksum += (frame2.fr2_val >> i*BITS_PER_BYTE) & MASK_BYTE0; + checksum += (frame2.regval >> (i * 8)) & 0xff; for (i = 0; i < BYTES_PER_WORD; i++) - checksum += (frame3.fr3_val >> i*BITS_PER_BYTE) & MASK_BYTE0; + checksum += (frame3.regval >> (i * 8)) & 0xff; - frame2.fr2_regx.chksum = -(checksum); + frame2.regx.chksum = -(checksum); } had_write_register(intelhaddata, AUD_HDMIW_INFOFR, info_frame); - had_write_register(intelhaddata, AUD_HDMIW_INFOFR, frame2.fr2_val); - had_write_register(intelhaddata, AUD_HDMIW_INFOFR, frame3.fr3_val); + had_write_register(intelhaddata, AUD_HDMIW_INFOFR, frame2.regval); + had_write_register(intelhaddata, AUD_HDMIW_INFOFR, frame3.regval); /* program remaining DIP words with zero */ for (i = 0; i < HAD_MAX_DIP_WORDS-VALID_DIP_WORDS; i++) had_write_register(intelhaddata, AUD_HDMIW_INFOFR, 0x0); - ctrl_state.ctrl_regx.dip_freq = 1; - ctrl_state.ctrl_regx.dip_en_sta = 1; - had_write_register(intelhaddata, AUD_CNTL_ST, ctrl_state.ctrl_val); + ctrl_state.regx.dip_freq = 1; + ctrl_state.regx.dip_en_sta = 1; + had_write_register(intelhaddata, AUD_CNTL_ST, ctrl_state.regval); } /* diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 4ccaa8b18566..9dc0da474f05 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -65,7 +65,6 @@ #define SMPL_WIDTH_16BITS 0x1 #define SMPL_WIDTH_24BITS 0x5 #define CHANNEL_ALLOCATION 0x1F -#define MASK_BYTE0 0x000000FF #define VALID_DIP_WORDS 3 #define LAYOUT0 0 #define LAYOUT1 1 diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index f9c184960b34..0e8397970e4a 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -199,13 +199,7 @@ struct channel_map_table { int spk_mask; /* speaker position bit mask */ }; -/** - * union aud_cfg - Audio configuration - * - * @cfg_regx: individual register bits - * @cfg_regval: full register value - * - */ +/* Audio configuration */ union aud_cfg { struct { u32 aud_en:1; @@ -222,17 +216,11 @@ union aud_cfg { u32 bogus_sample:1; u32 dp_modei:1; u32 rsvd:16; - } cfg_regx; - u32 cfg_regval; + } regx; + u32 regval; }; -/** - * union aud_ch_status_0 - Audio Channel Status 0 Attributes - * - * @status_0_regx:individual register bits - * @status_0_regval:full register value - * - */ +/* Audio Channel Status 0 Attributes */ union aud_ch_status_0 { struct { u32 ch_status:1; @@ -246,65 +234,41 @@ union aud_ch_status_0 { u32 samp_freq:4; u32 clk_acc:2; u32 rsvd:2; - } status_0_regx; - u32 status_0_regval; + } regx; + u32 regval; }; -/** - * union aud_ch_status_1 - Audio Channel Status 1 Attributes - * - * @status_1_regx: individual register bits - * @status_1_regval: full register value - * - */ +/* Audio Channel Status 1 Attributes */ union aud_ch_status_1 { struct { u32 max_wrd_len:1; u32 wrd_len:3; u32 rsvd:28; - } status_1_regx; - u32 status_1_regval; + } regx; + u32 regval; }; -/** - * union aud_hdmi_cts - CTS register - * - * @cts_regx: individual register bits - * @cts_regval: full register value - * - */ +/* CTS register */ union aud_hdmi_cts { struct { u32 cts_val:24; u32 en_cts_prog:1; u32 rsvd:7; - } cts_regx; - u32 cts_regval; + } regx; + u32 regval; }; -/** - * union aud_hdmi_n_enable - N register - * - * @n_regx: individual register bits - * @n_regval: full register value - * - */ +/* N register */ union aud_hdmi_n_enable { struct { u32 n_val:24; u32 en_n_prog:1; u32 rsvd:7; - } n_regx; - u32 n_regval; + } regx; + u32 regval; }; -/** - * union aud_buf_config - Audio Buffer configurations - * - * @buf_cfg_regx: individual register bits - * @buf_cfgval: full register value - * - */ +/* Audio Buffer configurations */ union aud_buf_config { struct { u32 audio_fifo_watermark:8; @@ -312,17 +276,11 @@ union aud_buf_config { u32 rsvd0:5; u32 aud_delay:8; u32 rsvd1:8; - } buf_cfg_regx; - u32 buf_cfgval; + } regx; + u32 regval; }; -/** - * union aud_buf_ch_swap - Audio Sample Swapping offset - * - * @buf_ch_swap_regx: individual register bits - * @buf_ch_swap_val: full register value - * - */ +/* Audio Sample Swapping offset */ union aud_buf_ch_swap { struct { u32 first_0:3; @@ -334,49 +292,31 @@ union aud_buf_ch_swap { u32 first_3:3; u32 second_3:3; u32 rsvd:8; - } buf_ch_swap_regx; - u32 buf_ch_swap_val; + } regx; + u32 regval; }; -/** - * union aud_buf_addr - Address for Audio Buffer - * - * @buf_addr_regx: individual register bits - * @buf_addr_val: full register value - * - */ +/* Address for Audio Buffer */ union aud_buf_addr { struct { u32 valid:1; u32 intr_en:1; u32 rsvd:4; u32 addr:26; - } buf_addr_regx; - u32 buf_addr_val; + } regx; + u32 regval; }; -/** - * union aud_buf_len - Length of Audio Buffer - * - * @buf_len_regx: individual register bits - * @buf_len_val: full register value - * - */ +/* Length of Audio Buffer */ union aud_buf_len { struct { u32 buf_len:20; u32 rsvd:12; - } buf_len_regx; - u32 buf_len_val; + } regx; + u32 regval; }; -/** - * union aud_ctrl_st - Audio Control State Register offset - * - * @ctrl_regx: individual register bits - * @ctrl_val: full register value - * - */ +/* Audio Control State Register offset */ union aud_ctrl_st { struct { u32 ram_addr:4; @@ -389,34 +329,22 @@ union aud_ctrl_st { u32 dip_idx:3; u32 dip_en_sta:4; u32 rsvd:7; - } ctrl_regx; - u32 ctrl_val; + } regx; + u32 regval; }; -/** - * union aud_info_frame1 - Audio HDMI Widget Data Island Packet offset - * - * @fr1_regx: individual register bits - * @fr1_val: full register value - * - */ +/* Audio HDMI Widget Data Island Packet offset */ union aud_info_frame1 { struct { u32 pkt_type:8; u32 ver_num:8; u32 len:5; u32 rsvd:11; - } fr1_regx; - u32 fr1_val; + } regx; + u32 regval; }; -/** - * union aud_info_frame2 - DIP frame 2 - * - * @fr2_regx: individual register bits - * @fr2_val: full register value - * - */ +/* DIP frame 2 */ union aud_info_frame2 { struct { u32 chksum:8; @@ -427,17 +355,11 @@ union aud_info_frame2 { u32 smpl_freq:3; u32 rsvd1:3; u32 format:8; - } fr2_regx; - u32 fr2_val; + } regx; + u32 regval; }; -/** - * union aud_info_frame3 - DIP frame 3 - * - * @fr3_regx: individual register bits - * @fr3_val: full register value - * - */ +/* DIP frame 3 */ union aud_info_frame3 { struct { u32 chnl_alloc:8; @@ -445,8 +367,8 @@ union aud_info_frame3 { u32 lsv:4; u32 dm_inh:1; u32 rsvd1:16; - } fr3_regx; - u32 fr3_val; + } regx; + u32 regval; }; #define HDMI_AUDIO_UNDERRUN (1UL<<31) -- cgit v1.2.3 From 03c3437755881a9f6f1b5f8c05e62edf7898a87f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 2 Feb 2017 16:19:03 +0100 Subject: ALSA: x86: Clean up unused defines and inclusions Many defines and constants are left unused. Clean them up. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 10 ++++-- sound/x86/intel_hdmi_audio.h | 11 +------ sound/x86/intel_hdmi_lpe_audio.h | 68 +++++++--------------------------------- 3 files changed, 20 insertions(+), 69 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index f825d514500e..82f48fbcd74b 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -21,19 +21,21 @@ * ALSA driver for Intel HDMI audio */ +#include #include #include #include #include #include -#include +#include #include -#include #include +#include +#include #include #include #include -#include +#include #include #include "intel_hdmi_audio.h" @@ -929,6 +931,8 @@ static int snd_intelhad_prog_n(u32 aud_samp_freq, u32 *n_param, return 0; } +#define MAX_CNT 0xFF + static void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata) { u32 hdmi_status = 0, i = 0; diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 9dc0da474f05..dea51fcfc07f 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -30,20 +30,11 @@ #ifndef _INTEL_HDMI_AUDIO_H_ #define _INTEL_HDMI_AUDIO_H_ -#include -#include -#include -#include -#include -#include -#include -#include #include "intel_hdmi_lpe_audio.h" #define PCM_INDEX 0 #define MAX_PB_STREAMS 1 #define MAX_CAP_STREAMS 0 -#define HDMI_AUDIO_DRIVER "hdmi-audio" #define HDMI_INFO_FRAME_WORD1 0x000a0184 #define DP_INFO_FRAME_WORD1 0x00441b84 @@ -85,7 +76,7 @@ struct ring_buf_info { u8 is_valid; }; -/** +/* * struct snd_intelhad - intelhad driver structure * * @card: ptr to hold card details diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index 0e8397970e4a..5a5adb7f0cde 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -23,20 +23,6 @@ #ifndef __INTEL_HDMI_LPE_AUDIO_H #define __INTEL_HDMI_LPE_AUDIO_H -#include -#include -#include -#include -#include -#include -#include -#include - -#define AUD_CONFIG_VALID_BIT (1<<9) -#define AUD_CONFIG_DP_MODE (1<<15) -#define AUD_CONFIG_BLOCK_BIT (1<<7) - -#define HMDI_LPE_AUDIO_DRIVER_NAME "intel-hdmi-lpe-audio" #define HAD_MAX_DEVICES 1 #define HAD_MIN_CHANNEL 2 #define HAD_MAX_CHANNEL 8 @@ -96,14 +82,6 @@ /* Naud Value */ #define DP_NAUD_VAL 32768 -/* _AUD_CONFIG register MASK */ -#define AUD_CONFIG_MASK_UNDERRUN 0xC0000000 -#define AUD_CONFIG_MASK_SRDBG 0x00000002 -#define AUD_CONFIG_MASK_FUNCRST 0x00000001 - -#define MAX_CNT 0xFF -#define HAD_SUSPEND_DELAY 1000 - enum had_drv_status { HAD_DRV_CONNECTED, HAD_DRV_RUNNING, @@ -120,17 +98,10 @@ enum intel_had_aud_buf_type { HAD_BUF_TYPE_D = 3, }; -enum num_aud_ch { - CH_STEREO = 0, - CH_THREE_FOUR = 1, - CH_FIVE_SIX = 2, - CH_SEVEN_EIGHT = 3 -}; - /* HDMI Controller register offsets - audio domain common */ /* Base address for below regs = 0x65000 */ enum hdmi_ctrl_reg_offset_common { - AUDIO_HDMI_CONFIG_A = 0x000, + AUDIO_HDMI_CONFIG_A = 0x000, AUDIO_HDMI_CONFIG_B = 0x800, AUDIO_HDMI_CONFIG_C = 0x900, }; @@ -220,6 +191,10 @@ union aud_cfg { u32 regval; }; +#define AUD_CONFIG_BLOCK_BIT (1 << 7) +#define AUD_CONFIG_VALID_BIT (1 << 9) +#define AUD_CONFIG_DP_MODE (1 << 15) + /* Audio Channel Status 0 Attributes */ union aud_ch_status_0 { struct { @@ -371,32 +346,13 @@ union aud_info_frame3 { u32 regval; }; -#define HDMI_AUDIO_UNDERRUN (1UL<<31) -#define HDMI_AUDIO_BUFFER_DONE (1UL<<29) +/* AUD_HDMI_STATUS bits */ +#define HDMI_AUDIO_UNDERRUN (1U << 31) +#define HDMI_AUDIO_BUFFER_DONE (1U << 29) - -#define PORT_ENABLE (1 << 31) -#define SDVO_AUDIO_ENABLE (1 << 6) - -enum had_caps_list { - HAD_GET_ELD = 1, - HAD_GET_DISPLAY_RATE, - HAD_GET_DP_OUTPUT, - HAD_GET_LINK_RATE, - HAD_SET_ENABLE_AUDIO, - HAD_SET_DISABLE_AUDIO, - HAD_SET_ENABLE_AUDIO_INT, - HAD_SET_DISABLE_AUDIO_INT, -}; - -enum had_event_type { - HAD_EVENT_HOT_PLUG = 1, - HAD_EVENT_HOT_UNPLUG, - HAD_EVENT_MODE_CHANGING, - HAD_EVENT_AUDIO_BUFFER_DONE, - HAD_EVENT_AUDIO_BUFFER_UNDERRUN, - HAD_EVENT_QUERY_IS_AUDIO_BUSY, - HAD_EVENT_QUERY_IS_AUDIO_SUSPENDED, -}; +/* AUD_HDMI_STATUS register mask */ +#define AUD_CONFIG_MASK_UNDERRUN 0xC0000000 +#define AUD_CONFIG_MASK_SRDBG 0x00000002 +#define AUD_CONFIG_MASK_FUNCRST 0x00000001 #endif -- cgit v1.2.3 From 4aedb9465f717a8393bb5f40581eb7942af12506 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 2 Feb 2017 16:38:39 +0100 Subject: ALSA: x86: Create ELD control element Like other drivers, expose the ELD bytes via a control element so that user-space can parse it. For the simplicity, the code to register the ctl elements is refactored using an array. Also, since ELD ctl read copies the bytes also during disconnection, clear the ELD bytes at hot-unplug, in order to avoid the leak of the previous bogus ELD. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 72 +++++++++++++++++++++++++++++++------------- 1 file changed, 51 insertions(+), 21 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 82f48fbcd74b..f49520117dd6 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1669,22 +1669,52 @@ static int had_iec958_put(struct snd_kcontrol *kcontrol, return changed; } -static struct snd_kcontrol_new had_control_iec958_mask = { - .access = SNDRV_CTL_ELEM_ACCESS_READ, - .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK), - .info = had_iec958_info, /* shared */ - .get = had_iec958_mask_get, -}; +static int had_ctl_eld_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = HDMI_MAX_ELD_BYTES; + return 0; +} -static struct snd_kcontrol_new had_control_iec958 = { - .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), - .info = had_iec958_info, - .get = had_iec958_get, - .put = had_iec958_put +static int had_ctl_eld_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_intelhad *intelhaddata = snd_kcontrol_chip(kcontrol); + + mutex_lock(&intelhaddata->mutex); + memcpy(ucontrol->value.bytes.data, intelhaddata->eld, + HDMI_MAX_ELD_BYTES); + mutex_unlock(&intelhaddata->mutex); + return 0; +} + +static struct snd_kcontrol_new had_controls[] = { + { + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK), + .info = had_iec958_info, /* shared */ + .get = had_iec958_mask_get, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), + .info = had_iec958_info, + .get = had_iec958_get, + .put = had_iec958_put, + }, + { + .access = (SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE), + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "ELD", + .info = had_ctl_eld_info, + .get = had_ctl_eld_get, + }, }; + static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id) { struct snd_intelhad *ctx = dev_id; @@ -1724,6 +1754,7 @@ static void had_audio_wq(struct work_struct *work) if (!pdata->hdmi_connected) { dev_dbg(ctx->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG\n", __func__); + memset(ctx->eld, 0, sizeof(ctx->eld)); /* clear the old ELD */ had_process_hot_unplug(ctx); } else { struct intel_hdmi_lpe_audio_eld *eld = &pdata->eld; @@ -1826,7 +1857,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) struct intel_hdmi_lpe_audio_pdata *pdata; int irq; struct resource *res_mmio; - int ret; + int i, ret; dev_dbg(&pdev->dev, "dma_mask: %p\n", pdev->dev.dma_mask); @@ -1918,13 +1949,12 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) SNDRV_DMA_TYPE_DEV, NULL, HAD_MAX_BUFFER, HAD_MAX_BUFFER); - /* IEC958 controls */ - ret = snd_ctl_add(card, snd_ctl_new1(&had_control_iec958_mask, ctx)); - if (ret < 0) - goto err; - ret = snd_ctl_add(card, snd_ctl_new1(&had_control_iec958, ctx)); - if (ret < 0) - goto err; + /* create controls */ + for (i = 0; i < ARRAY_SIZE(had_controls); i++) { + ret = snd_ctl_add(card, snd_ctl_new1(&had_controls[i], ctx)); + if (ret < 0) + goto err; + } init_channel_allocations(); -- cgit v1.2.3 From 36ed34662f1944ebf553b30fcba1abab1703d125 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 2 Feb 2017 17:06:38 +0100 Subject: ALSA: x86: Set CA bits for DisplayPort too This is a guess work. Usually the DP audio info frame is just 8-bit shifted from HDMI AI, so let's try to put CA in DIP frame 2 [24-31]. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index f49520117dd6..24a18b88c927 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -626,20 +626,20 @@ static void snd_intelhad_prog_dip(struct snd_pcm_substream *substream, u8 checksum = 0; u32 info_frame; int channels; + int ca; channels = substream->runtime->channels; had_write_register(intelhaddata, AUD_CNTL_ST, ctrl_state.regval); + ca = snd_intelhad_channel_allocation(intelhaddata, channels); if (intelhaddata->dp_output) { info_frame = DP_INFO_FRAME_WORD1; - frame2.regval = 1; + frame2.regval = (substream->runtime->channels - 1) | (ca << 24); } else { info_frame = HDMI_INFO_FRAME_WORD1; frame2.regx.chnl_cnt = substream->runtime->channels - 1; - - frame3.regx.chnl_alloc = snd_intelhad_channel_allocation( - intelhaddata, channels); + frame3.regx.chnl_alloc = ca; /* Calculte the byte wide checksum for all valid DIP words */ for (i = 0; i < BYTES_PER_WORD; i++) -- cgit v1.2.3 From 44684f61b23c68786834dd2a99d4a68d40a13308 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 2 Feb 2017 17:27:40 +0100 Subject: ALSA: x86: Simplify comments It's a stand-alone small driver code, and we don't have to describe too much formalized comments in kernel-doc style for local functions at all. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 66 ++++++++++---------------------------------- 1 file changed, 14 insertions(+), 52 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 24a18b88c927..5613c675ce70 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -609,11 +609,7 @@ static int had_register_chmap_ctls(struct snd_intelhad *intelhaddata, } /* - * snd_intelhad_prog_dip - to initialize Data Island Packets registers - * - * @substream:substream for which the prepare function is called - * @intelhaddata:substream private data - * + * Initialize Data Island Packets registers * This function is called in the prepare callback */ static void snd_intelhad_prog_dip(struct snd_pcm_substream *substream, @@ -666,10 +662,7 @@ static void snd_intelhad_prog_dip(struct snd_pcm_substream *substream, } /* - * snd_intelhad_prog_buffer - programs buffer address and length registers - * @substream: substream for which the prepare function is called - * @intelhaddata: substream private data - * + * Programs buffer address and length registers * This function programs ring buffer address and length into registers. */ static int snd_intelhad_prog_buffer(struct snd_pcm_substream *substream, @@ -824,7 +817,7 @@ static int had_calculate_maud_value(u32 aud_samp_freq, u32 link_rate) } /* - * snd_intelhad_prog_cts - Program HDMI audio CTS value + * Program HDMI audio CTS value * * @aud_samp_freq: sampling frequency of audio data * @tmds: sampling frequency of the display data @@ -896,7 +889,7 @@ static int had_calculate_n_value(u32 aud_samp_freq) } /* - * snd_intelhad_prog_n - Program HDMI audio N value + * Program HDMI audio N value * * @aud_samp_freq: sampling frequency of audio data * @n_param: N value, depends on aud_samp_freq @@ -962,10 +955,7 @@ static void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata) } /* - * snd_intelhad_open - stream initializations are done here - * @substream:substream for which the stream function is called - * - * This function is called whenever a PCM stream is opened + * ALSA PCM open callback */ static int snd_intelhad_open(struct snd_pcm_substream *substream) { @@ -1017,10 +1007,7 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) } /* - * snd_intelhad_close - to free parameteres when stream is stopped - * @substream: substream for which the function is called - * - * This function is called by ALSA framework when stream is stopped + * ALSA PCM close callback */ static int snd_intelhad_close(struct snd_pcm_substream *substream) { @@ -1051,12 +1038,7 @@ static int snd_intelhad_close(struct snd_pcm_substream *substream) } /* - * snd_intelhad_hw_params - to setup the hardware parameters - * like allocating the buffers - * @substream: substream for which the function is called - * @hw_params: hardware parameters - * - * This function is called by ALSA framework when hardware params are set + * ALSA PCM hw_params callback */ static int snd_intelhad_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) @@ -1090,11 +1072,7 @@ static int snd_intelhad_hw_params(struct snd_pcm_substream *substream, } /* - * snd_intelhad_hw_free - to release the resources allocated during - * hardware params setup - * @substream: substream for which the function is called - * - * This function is called by ALSA framework before close callback. + * ALSA PCM hw_free callback */ static int snd_intelhad_hw_free(struct snd_pcm_substream *substream) { @@ -1113,11 +1091,7 @@ static int snd_intelhad_hw_free(struct snd_pcm_substream *substream) } /* - * snd_intelhad_pcm_trigger - stream activities are handled here - * @substream: substream for which the stream function is called - * @cmd: the stream commamd thats requested from upper layer - * - * This function is called whenever an a stream activity is invoked + * ALSA PCM trigger callback */ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, int cmd) @@ -1172,10 +1146,7 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, } /* - * snd_intelhad_pcm_prepare - internal preparation before starting a stream - * @substream: substream for which the function is called - * - * This function is called when a stream is started for internal preparation. + * ALSA PCM prepare callback */ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) { @@ -1243,14 +1214,10 @@ prep_end: } /* - * snd_intelhad_pcm_pointer- to send the current buffer pointerprocessed by hw - * @substream: substream for which the function is called - * - * This function is called by ALSA framework to get the current hw buffer ptr - * when a period is elapsed + * ALSA PCM pointer callback */ -static snd_pcm_uframes_t snd_intelhad_pcm_pointer( - struct snd_pcm_substream *substream) +static snd_pcm_uframes_t +snd_intelhad_pcm_pointer(struct snd_pcm_substream *substream) { struct snd_intelhad *intelhaddata; u32 bytes_rendered = 0; @@ -1299,12 +1266,7 @@ static snd_pcm_uframes_t snd_intelhad_pcm_pointer( } /* - * snd_intelhad_pcm_mmap- mmaps a kernel buffer to user space for copying data - * @substream: substream for which the function is called - * @vma: struct instance of memory VMM memory area - * - * This function is called by OS when a user space component - * tries to get mmap memory from driver + * ALSA PCM mmap callback */ static int snd_intelhad_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) -- cgit v1.2.3 From 73997b050c995f34f3617d344f1e767d15b2477d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 2 Feb 2017 17:38:50 +0100 Subject: ALSA: x86: Yet more tidy-up and clean-ups - Add a few more comments to functions. - Move the initialization of some PCM state variables to open and prepare callbacks, where these are clearer places. - Remove superfluous NULL checks. - Get rid of the bogus drv_status change to CONNECTED at close; this doesn't make any sense. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 68 +++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 5613c675ce70..f032610d1287 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -965,7 +965,6 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) intelhaddata = snd_pcm_substream_chip(substream); runtime = substream->runtime; - intelhaddata->underrun_count = 0; pm_runtime_get_sync(intelhaddata->dev); @@ -989,17 +988,20 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) */ retval = snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64); - if (retval < 0) { - dev_dbg(intelhaddata->dev, "%s:step_size=64 failed,err=%d\n", - __func__, retval); + if (retval < 0) goto error; - } + /* expose PCM substream */ spin_lock_irq(&intelhaddata->had_spinlock); intelhaddata->stream_info.substream = substream; intelhaddata->stream_info.substream_refcount++; spin_unlock_irq(&intelhaddata->had_spinlock); + /* these are cleared in prepare callback, but just to be sure */ + intelhaddata->curr_buf = 0; + intelhaddata->underrun_count = 0; + intelhaddata->stream_info.buffer_rendered = 0; + return retval; error: pm_runtime_put(intelhaddata->dev); @@ -1015,7 +1017,7 @@ static int snd_intelhad_close(struct snd_pcm_substream *substream) intelhaddata = snd_pcm_substream_chip(substream); - intelhaddata->stream_info.buffer_rendered = 0; + /* unreference and sync with the pending PCM accesses */ spin_lock_irq(&intelhaddata->had_spinlock); intelhaddata->stream_info.substream = NULL; intelhaddata->stream_info.substream_refcount--; @@ -1026,13 +1028,6 @@ static int snd_intelhad_close(struct snd_pcm_substream *substream) } spin_unlock_irq(&intelhaddata->had_spinlock); - /* Check if following drv_status modification is required - VA */ - if (intelhaddata->drv_status != HAD_DRV_DISCONNECTED) { - intelhaddata->drv_status = HAD_DRV_CONNECTED; - dev_dbg(intelhaddata->dev, - "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_CONNECTED\n", - __func__, __LINE__); - } pm_runtime_put(intelhaddata->dev); return 0; } @@ -1047,9 +1042,6 @@ static int snd_intelhad_hw_params(struct snd_pcm_substream *substream, unsigned long addr; int pages, buf_size, retval; - if (!hw_params) - return -EINVAL; - intelhaddata = snd_pcm_substream_chip(substream); buf_size = params_buffer_bytes(hw_params); retval = snd_pcm_lib_malloc_pages(substream, buf_size); @@ -1124,7 +1116,6 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: spin_lock(&intelhaddata->had_spinlock); - intelhaddata->curr_buf = 0; /* Stop reporting BUFFER_DONE/UNDERRUN to above layers */ @@ -1174,6 +1165,8 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) dev_dbg(intelhaddata->dev, "rate=%d\n", runtime->rate); dev_dbg(intelhaddata->dev, "channels=%d\n", runtime->channels); + intelhaddata->curr_buf = 0; + intelhaddata->underrun_count = 0; intelhaddata->stream_info.buffer_rendered = 0; /* Get N value in KHz */ @@ -1247,7 +1240,6 @@ snd_intelhad_pcm_pointer(struct snd_pcm_substream *substream) dev_dbg(intelhaddata->dev, "assume audio_codec_reset, underrun = %d - do xrun\n", intelhaddata->underrun_count); - intelhaddata->underrun_count = 0; return SNDRV_PCM_POS_XRUN; } } else { @@ -1277,6 +1269,21 @@ static int snd_intelhad_pcm_mmap(struct snd_pcm_substream *substream, vma->vm_end - vma->vm_start, vma->vm_page_prot); } +/* + * ALSA PCM ops + */ +static const struct snd_pcm_ops snd_intelhad_playback_ops = { + .open = snd_intelhad_open, + .close = snd_intelhad_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_intelhad_hw_params, + .hw_free = snd_intelhad_hw_free, + .prepare = snd_intelhad_pcm_prepare, + .trigger = snd_intelhad_pcm_trigger, + .pointer = snd_intelhad_pcm_pointer, + .mmap = snd_intelhad_pcm_mmap, +}; + /* process mode change of the running stream; called in mutex */ static int hdmi_audio_mode_change(struct snd_intelhad *intelhaddata) { @@ -1564,18 +1571,9 @@ static void had_process_hot_unplug(struct snd_intelhad *intelhaddata) intelhaddata->chmap->chmap = NULL; } -/* PCM operations structure and the calls back for the same */ -static struct snd_pcm_ops snd_intelhad_playback_ops = { - .open = snd_intelhad_open, - .close = snd_intelhad_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_intelhad_hw_params, - .hw_free = snd_intelhad_hw_free, - .prepare = snd_intelhad_pcm_prepare, - .trigger = snd_intelhad_pcm_trigger, - .pointer = snd_intelhad_pcm_pointer, - .mmap = snd_intelhad_pcm_mmap, -}; +/* + * ALSA iec958 and ELD controls + */ static int had_iec958_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) @@ -1651,7 +1649,7 @@ static int had_ctl_eld_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new had_controls[] = { +static const struct snd_kcontrol_new had_controls[] = { { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -1676,7 +1674,9 @@ static struct snd_kcontrol_new had_controls[] = { }, }; - +/* + * audio interrupt handler + */ static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id) { struct snd_intelhad *ctx = dev_id; @@ -1698,6 +1698,9 @@ static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id) return IRQ_HANDLED; } +/* + * monitor plug/unplug notification from i915; just kick off the work + */ static void notify_audio_lpe(struct platform_device *pdev) { struct snd_intelhad *ctx = platform_get_drvdata(pdev); @@ -1705,6 +1708,7 @@ static void notify_audio_lpe(struct platform_device *pdev) schedule_work(&ctx->hdmi_audio_wq); } +/* the work to handle monitor hot plug/unplug */ static void had_audio_wq(struct work_struct *work) { struct snd_intelhad *ctx = -- cgit v1.2.3 From 91b0cb0cc07bcb5114df2897531f4ea41c148c8e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 2 Feb 2017 17:46:49 +0100 Subject: ALSA: x86: Rename drv_status to connected After the rewrite of the runtime PM code, we have only two driver status: CONNECTED and DISCONNECTED. So it's clearer to use a boolean flag, and name it easier one, "connected". Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 40 ++++++++++++++++++++-------------------- sound/x86/intel_hdmi_audio.h | 4 ++-- sound/x86/intel_hdmi_lpe_audio.h | 8 -------- 3 files changed, 22 insertions(+), 30 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index f032610d1287..c83f02c2593e 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -202,7 +202,7 @@ mid_hdmi_audio_write(struct snd_intelhad *ctx, u32 reg, u32 val) static int had_read_register(struct snd_intelhad *intelhaddata, u32 offset, u32 *data) { - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) + if (!intelhaddata->connected) return -ENODEV; mid_hdmi_audio_read(intelhaddata, offset, data); @@ -221,7 +221,7 @@ static void fixup_dp_config(struct snd_intelhad *intelhaddata, static int had_write_register(struct snd_intelhad *intelhaddata, u32 offset, u32 data) { - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) + if (!intelhaddata->connected) return -ENODEV; fixup_dp_config(intelhaddata, offset, &data); @@ -234,7 +234,7 @@ static int had_read_modify(struct snd_intelhad *intelhaddata, u32 offset, { u32 val_tmp; - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) + if (!intelhaddata->connected) return -ENODEV; mid_hdmi_audio_read(intelhaddata, offset, &val_tmp); @@ -556,7 +556,7 @@ static int had_chmap_ctl_info(struct snd_kcontrol *kcontrol, struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); struct snd_intelhad *intelhaddata = info->private_data; - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) + if (!intelhaddata->connected) return -ENODEV; uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = HAD_MAX_CHANNEL; @@ -573,7 +573,7 @@ static int had_chmap_ctl_get(struct snd_kcontrol *kcontrol, int i; const struct snd_pcm_chmap_elem *chmap; - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) + if (!intelhaddata->connected) return -ENODEV; mutex_lock(&intelhaddata->mutex); @@ -968,7 +968,7 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) pm_runtime_get_sync(intelhaddata->dev); - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { + if (!intelhaddata->connected) { dev_dbg(intelhaddata->dev, "%s: HDMI cable plugged-out\n", __func__); retval = -ENODEV; @@ -1098,7 +1098,7 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_RESUME: /* Disable local INTRs till register prgmng is done */ - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { + if (!intelhaddata->connected) { dev_dbg(intelhaddata->dev, "_START: HDMI cable plugged-out\n"); retval = -ENODEV; @@ -1150,7 +1150,7 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) intelhaddata = snd_pcm_substream_chip(substream); runtime = substream->runtime; - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { + if (!intelhaddata->connected) { dev_dbg(intelhaddata->dev, "%s: HDMI cable plugged-out\n", __func__); retval = -ENODEV; @@ -1219,7 +1219,7 @@ snd_intelhad_pcm_pointer(struct snd_pcm_substream *substream) intelhaddata = snd_pcm_substream_chip(substream); - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) + if (!intelhaddata->connected) return SNDRV_PCM_POS_XRUN; /* Use a hw register to calculate sub-period position reports. @@ -1380,7 +1380,7 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) intr_count = 1; spin_lock_irqsave(&intelhaddata->had_spinlock, flags); - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { + if (!intelhaddata->connected) { spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags); dev_dbg(intelhaddata->dev, "%s:Device already disconnected\n", __func__); @@ -1419,7 +1419,7 @@ static int had_process_buffer_done(struct snd_intelhad *intelhaddata) spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags); - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { + if (!intelhaddata->connected) { dev_dbg(intelhaddata->dev, "HDMI cable plugged-out\n"); return 0; } @@ -1460,14 +1460,14 @@ static int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) struct pcm_stream_info *stream; struct snd_pcm_substream *substream; unsigned long flags; - int drv_status; + int connected; stream = &intelhaddata->stream_info; spin_lock_irqsave(&intelhaddata->had_spinlock, flags); buf_id = intelhaddata->curr_buf; intelhaddata->buff_done = buf_id; - drv_status = intelhaddata->drv_status; + connected = intelhaddata->connected; if (stream->running) intelhaddata->curr_buf = HAD_BUF_TYPE_A; @@ -1478,7 +1478,7 @@ static int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) snd_intelhad_handle_underrun(intelhaddata); - if (drv_status == HAD_DRV_DISCONNECTED) { + if (!connected) { dev_dbg(intelhaddata->dev, "%s:Device already disconnected\n", __func__); return 0; @@ -1501,7 +1501,7 @@ static void had_process_hot_plug(struct snd_intelhad *intelhaddata) struct snd_pcm_substream *substream; spin_lock_irq(&intelhaddata->had_spinlock); - if (intelhaddata->drv_status == HAD_DRV_CONNECTED) { + if (intelhaddata->connected) { dev_dbg(intelhaddata->dev, "Device already connected\n"); spin_unlock_irq(&intelhaddata->had_spinlock); return; @@ -1509,7 +1509,7 @@ static void had_process_hot_plug(struct snd_intelhad *intelhaddata) buf_id = intelhaddata->curr_buf; intelhaddata->buff_done = buf_id; - intelhaddata->drv_status = HAD_DRV_CONNECTED; + intelhaddata->connected = true; dev_dbg(intelhaddata->dev, "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_CONNECTED\n", __func__, __LINE__); @@ -1543,7 +1543,7 @@ static void had_process_hot_unplug(struct snd_intelhad *intelhaddata) spin_lock_irq(&intelhaddata->had_spinlock); - if (intelhaddata->drv_status == HAD_DRV_DISCONNECTED) { + if (!intelhaddata->connected) { dev_dbg(intelhaddata->dev, "Device already disconnected\n"); spin_unlock_irq(&intelhaddata->had_spinlock); goto out; @@ -1554,7 +1554,7 @@ static void had_process_hot_unplug(struct snd_intelhad *intelhaddata) snd_intelhad_enable_audio_int(intelhaddata, false); snd_intelhad_enable_audio(substream, intelhaddata, false); - intelhaddata->drv_status = HAD_DRV_DISCONNECTED; + intelhaddata->connected = false; dev_dbg(intelhaddata->dev, "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n", __func__, __LINE__); @@ -1855,7 +1855,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) ctx = card->private_data; spin_lock_init(&ctx->had_spinlock); mutex_init(&ctx->mutex); - ctx->drv_status = HAD_DRV_DISCONNECTED; + ctx->connected = false; ctx->dev = &pdev->dev; ctx->card = card; ctx->aes_bits = SNDRV_PCM_DEFAULT_CON_SPDIF; @@ -1960,7 +1960,7 @@ static int hdmi_lpe_audio_remove(struct platform_device *pdev) { struct snd_intelhad *ctx = platform_get_drvdata(pdev); - if (ctx->drv_status != HAD_DRV_DISCONNECTED) + if (ctx->connected) snd_intelhad_enable_audio_int(ctx, false); snd_card_free(ctx->card); return 0; diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index dea51fcfc07f..9f713a8a88bc 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -80,7 +80,7 @@ struct ring_buf_info { * struct snd_intelhad - intelhad driver structure * * @card: ptr to hold card details - * @drv_status: driver status + * @connected: the monitor connection status * @buf_info: ring buffer info * @stream_info: stream information * @eld: holds ELD info @@ -95,7 +95,7 @@ struct ring_buf_info { */ struct snd_intelhad { struct snd_card *card; - enum had_drv_status drv_status; + bool connected; struct ring_buf_info buf_info[HAD_NUM_OF_RING_BUFS]; struct pcm_stream_info stream_info; unsigned char eld[HDMI_MAX_ELD_BYTES]; diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index 5a5adb7f0cde..be9783910a3a 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -82,14 +82,6 @@ /* Naud Value */ #define DP_NAUD_VAL 32768 -enum had_drv_status { - HAD_DRV_CONNECTED, - HAD_DRV_RUNNING, - HAD_DRV_DISCONNECTED, - HAD_DRV_SUSPENDED, - HAD_DRV_ERR, -}; - /* enum intel_had_aud_buf_type - HDMI controller ring buffer types */ enum intel_had_aud_buf_type { HAD_BUF_TYPE_A = 0, -- cgit v1.2.3 From 412bbe7d5b8cdb103af82c3616149138c50d1efa Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 2 Feb 2017 22:03:22 +0100 Subject: ALSA: x86: Explicit specify 32bit DMA LPE audio is capable only up to 32bit address, as it seems. Then we should limit the DMA addresses accordingly via dma-mapping API. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index c83f02c2593e..fac30cf2794f 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -1825,8 +1826,6 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) struct resource *res_mmio; int i, ret; - dev_dbg(&pdev->dev, "dma_mask: %p\n", pdev->dev.dma_mask); - pdata = pdev->dev.platform_data; if (!pdata) { dev_err(&pdev->dev, "%s: quit: pdata not allocated by i915!!\n", __func__); @@ -1907,6 +1906,11 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) /* setup the ops for playabck */ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_intelhad_playback_ops); + + /* only 32bit addressable */ + dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); + dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); + /* allocate dma pages for ALSA stream operations * memory allocated is based on size, not max value * thus using same argument for max & size -- cgit v1.2.3 From 83af57dd515cf06883f6e954dd0efa9b15b514a6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 3 Feb 2017 08:50:06 +0100 Subject: ALSA: x86: Don't check connection in lowlevel accessors The lowlevel register read/write don't have to be careful about the connection state. It should be checked in the caller side instead. By dropping the check, we can simplify the code, and readability. This patch also refacors the functions slightly: namely, - drop the useless always-zero return values - fold the inline functions to the main accessor functions themselves - move the DP audio hack for AUD_CONFIG to the caller side - simplify snd_intelhad_eanble_audio() and drop the unused had_read_modify() Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 91 ++++++++++++-------------------------------- 1 file changed, 25 insertions(+), 66 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index fac30cf2794f..db437efbb87d 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -188,69 +188,20 @@ static void had_substream_put(struct snd_intelhad *intelhaddata) } /* Register access functions */ -static inline void -mid_hdmi_audio_read(struct snd_intelhad *ctx, u32 reg, u32 *val) +static void had_read_register(struct snd_intelhad *ctx, u32 reg, u32 *val) { *val = ioread32(ctx->mmio_start + ctx->had_config_offset + reg); } -static inline void -mid_hdmi_audio_write(struct snd_intelhad *ctx, u32 reg, u32 val) +static void had_write_register(struct snd_intelhad *ctx, u32 reg, u32 val) { iowrite32(val, ctx->mmio_start + ctx->had_config_offset + reg); } -static int had_read_register(struct snd_intelhad *intelhaddata, - u32 offset, u32 *data) -{ - if (!intelhaddata->connected) - return -ENODEV; - - mid_hdmi_audio_read(intelhaddata, offset, data); - return 0; -} - -static void fixup_dp_config(struct snd_intelhad *intelhaddata, - u32 offset, u32 *data) -{ - if (intelhaddata->dp_output) { - if (offset == AUD_CONFIG && (*data & AUD_CONFIG_VALID_BIT)) - *data |= AUD_CONFIG_DP_MODE | AUD_CONFIG_BLOCK_BIT; - } -} - -static int had_write_register(struct snd_intelhad *intelhaddata, - u32 offset, u32 data) -{ - if (!intelhaddata->connected) - return -ENODEV; - - fixup_dp_config(intelhaddata, offset, &data); - mid_hdmi_audio_write(intelhaddata, offset, data); - return 0; -} - -static int had_read_modify(struct snd_intelhad *intelhaddata, u32 offset, - u32 data, u32 mask) -{ - u32 val_tmp; - - if (!intelhaddata->connected) - return -ENODEV; - - mid_hdmi_audio_read(intelhaddata, offset, &val_tmp); - val_tmp &= ~mask; - val_tmp |= (data & mask); - - fixup_dp_config(intelhaddata, offset, &val_tmp); - mid_hdmi_audio_write(intelhaddata, offset, val_tmp); - return 0; -} - /* * enable / disable audio configuration * - * The had_read_modify() function should not directly be used on VLV2 for + * The normal read/modify should not directly be used on VLV2 for * updating AUD_CONFIG register. * This is because: * Bit6 of AUD_CONFIG register is writeonly due to a silicon bug on VLV2 @@ -267,24 +218,25 @@ static void snd_intelhad_enable_audio(struct snd_pcm_substream *substream, bool enable) { union aud_cfg cfg_val = {.regval = 0}; - u8 channels, data, mask; + u8 channels; + u32 mask, val; /* * If substream is NULL, there is no active stream. * In this case just set channels to 2 */ channels = substream ? substream->runtime->channels : 2; - cfg_val.regx.num_ch = channels - 2; + dev_dbg(intelhaddata->dev, "enable %d, ch=%d\n", enable, channels); - data = cfg_val.regval; + cfg_val.regx.num_ch = channels - 2; if (enable) - data |= 1; + cfg_val.regx.aud_en = 1; mask = AUD_CONFIG_CH_MASK | 1; - dev_dbg(intelhaddata->dev, "%s : data = %x, mask =%x\n", - __func__, data, mask); - - had_read_modify(intelhaddata, AUD_CONFIG, data, mask); + had_read_register(intelhaddata, AUD_CONFIG, &val); + val &= ~mask; + val |= cfg_val.regval; + had_write_register(intelhaddata, AUD_CONFIG, val); } /* enable / disable the audio interface */ @@ -293,10 +245,10 @@ static void snd_intelhad_enable_audio_int(struct snd_intelhad *ctx, bool enable) u32 status_reg; if (enable) { - mid_hdmi_audio_read(ctx, AUD_HDMI_STATUS, &status_reg); + had_read_register(ctx, AUD_HDMI_STATUS, &status_reg); status_reg |= HDMI_AUDIO_BUFFER_DONE | HDMI_AUDIO_UNDERRUN; - mid_hdmi_audio_write(ctx, AUD_HDMI_STATUS, status_reg); - mid_hdmi_audio_read(ctx, AUD_HDMI_STATUS, &status_reg); + had_write_register(ctx, AUD_HDMI_STATUS, status_reg); + had_read_register(ctx, AUD_HDMI_STATUS, &status_reg); } } @@ -401,6 +353,13 @@ static int snd_intelhad_audio_ctrl(struct snd_pcm_substream *substream, cfg_val.regx.layout = LAYOUT1; cfg_val.regx.val_bit = 1; + + /* fix up the DP bits */ + if (intelhaddata->dp_output) { + cfg_val.regx.dp_modei = 1; + cfg_val.regx.set = 1; + } + had_write_register(intelhaddata, AUD_CONFIG, cfg_val.regval); return 0; } @@ -1684,15 +1643,15 @@ static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id) u32 audio_stat, audio_reg; audio_reg = AUD_HDMI_STATUS; - mid_hdmi_audio_read(ctx, audio_reg, &audio_stat); + had_read_register(ctx, audio_reg, &audio_stat); if (audio_stat & HDMI_AUDIO_UNDERRUN) { - mid_hdmi_audio_write(ctx, audio_reg, HDMI_AUDIO_UNDERRUN); + had_write_register(ctx, audio_reg, HDMI_AUDIO_UNDERRUN); had_process_buffer_underrun(ctx); } if (audio_stat & HDMI_AUDIO_BUFFER_DONE) { - mid_hdmi_audio_write(ctx, audio_reg, HDMI_AUDIO_BUFFER_DONE); + had_write_register(ctx, audio_reg, HDMI_AUDIO_BUFFER_DONE); had_process_buffer_done(ctx); } -- cgit v1.2.3 From f4566aa112b86649b74f3d64c21ec2c8a84d5c1d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 4 Feb 2017 21:39:56 +0100 Subject: ALSA: x86: Minor cleanup of reset buffer procedure The procedure to reset buffer pointers is performed in two places and still open-coded. Simplify the helper function and use it consistently. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index db437efbb87d..0a9c82aca05f 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -252,10 +252,11 @@ static void snd_intelhad_enable_audio_int(struct snd_intelhad *ctx, bool enable) } } -static void snd_intelhad_reset_audio(struct snd_intelhad *intelhaddata, - u8 reset) +/* Reset buffer pointers */ +static void had_reset_audio(struct snd_intelhad *intelhaddata) { - had_write_register(intelhaddata, AUD_HDMI_STATUS, reset); + had_write_register(intelhaddata, AUD_HDMI_STATUS, 1); + had_write_register(intelhaddata, AUD_HDMI_STATUS, 0); } /* @@ -893,8 +894,7 @@ static void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata) /* Handle Underrun interrupt within Audio Unit */ had_write_register(intelhaddata, AUD_CONFIG, 0); /* Reset buffer pointers */ - had_write_register(intelhaddata, AUD_HDMI_STATUS, 1); - had_write_register(intelhaddata, AUD_HDMI_STATUS, 0); + had_reset_audio(intelhaddata); /* * The interrupt status 'sticky' bits might not be cleared by * setting '1' to that bit once... @@ -1085,8 +1085,7 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, snd_intelhad_enable_audio_int(intelhaddata, false); snd_intelhad_enable_audio(substream, intelhaddata, false); /* Reset buffer pointers */ - snd_intelhad_reset_audio(intelhaddata, 1); - snd_intelhad_reset_audio(intelhaddata, 0); + had_reset_audio(intelhaddata); snd_intelhad_enable_audio_int(intelhaddata, false); break; -- cgit v1.2.3 From b556290f9a8386ff6afeec12cae29fbab77321a3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 4 Feb 2017 22:05:33 +0100 Subject: ALSA: x86: Unify local function prefix Use had_ prefix consistently to all local helper functions, as well as had_pcm_ for PCM ops. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 127 ++++++++++++++++++++----------------------- 1 file changed, 60 insertions(+), 67 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 0a9c82aca05f..57042ef3a480 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -130,7 +130,7 @@ static const struct channel_map_table map_tables[] = { }; /* hardware capability structure */ -static const struct snd_pcm_hardware snd_intel_hadstream = { +static const struct snd_pcm_hardware had_pcm_hardware = { .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_DOUBLE | SNDRV_PCM_INFO_MMAP| @@ -213,9 +213,9 @@ static void had_write_register(struct snd_intelhad *ctx, u32 reg, u32 val) * bad audio. The fix is to always write the AUD_CONFIG[6:4] with * appropriate value when doing read-modify of AUD_CONFIG register. */ -static void snd_intelhad_enable_audio(struct snd_pcm_substream *substream, - struct snd_intelhad *intelhaddata, - bool enable) +static void had_enable_audio(struct snd_pcm_substream *substream, + struct snd_intelhad *intelhaddata, + bool enable) { union aud_cfg cfg_val = {.regval = 0}; u8 channels; @@ -240,7 +240,7 @@ static void snd_intelhad_enable_audio(struct snd_pcm_substream *substream, } /* enable / disable the audio interface */ -static void snd_intelhad_enable_audio_int(struct snd_intelhad *ctx, bool enable) +static void had_enable_audio_int(struct snd_intelhad *ctx, bool enable) { u32 status_reg; @@ -332,8 +332,8 @@ static int had_prog_status_reg(struct snd_pcm_substream *substream, * registers and buffer confgiuration registers * This function is called in the prepare callback */ -static int snd_intelhad_audio_ctrl(struct snd_pcm_substream *substream, - struct snd_intelhad *intelhaddata) +static int had_init_audio_ctrl(struct snd_pcm_substream *substream, + struct snd_intelhad *intelhaddata) { union aud_cfg cfg_val = {.regval = 0}; union aud_buf_config buf_cfg = {.regval = 0}; @@ -393,8 +393,8 @@ static void init_channel_allocations(void) * * TODO: it could select the wrong CA from multiple candidates. */ -static int snd_intelhad_channel_allocation(struct snd_intelhad *intelhaddata, - int channels) +static int had_channel_allocation(struct snd_intelhad *intelhaddata, + int channels) { int i; int ca = 0; @@ -573,8 +573,8 @@ static int had_register_chmap_ctls(struct snd_intelhad *intelhaddata, * Initialize Data Island Packets registers * This function is called in the prepare callback */ -static void snd_intelhad_prog_dip(struct snd_pcm_substream *substream, - struct snd_intelhad *intelhaddata) +static void had_prog_dip(struct snd_pcm_substream *substream, + struct snd_intelhad *intelhaddata) { int i; union aud_ctrl_st ctrl_state = {.regval = 0}; @@ -589,7 +589,7 @@ static void snd_intelhad_prog_dip(struct snd_pcm_substream *substream, had_write_register(intelhaddata, AUD_CNTL_ST, ctrl_state.regval); - ca = snd_intelhad_channel_allocation(intelhaddata, channels); + ca = had_channel_allocation(intelhaddata, channels); if (intelhaddata->dp_output) { info_frame = DP_INFO_FRAME_WORD1; frame2.regval = (substream->runtime->channels - 1) | (ca << 24); @@ -782,14 +782,14 @@ static int had_calculate_maud_value(u32 aud_samp_freq, u32 link_rate) * * @aud_samp_freq: sampling frequency of audio data * @tmds: sampling frequency of the display data + * @link_rate: DP link rate * @n_param: N value, depends on aud_samp_freq - * @intelhaddata:substream private data + * @intelhaddata: substream private data * * Program CTS register based on the audio and display sampling frequency */ -static void snd_intelhad_prog_cts(u32 aud_samp_freq, u32 tmds, - u32 link_rate, u32 n_param, - struct snd_intelhad *intelhaddata) +static void had_prog_cts(u32 aud_samp_freq, u32 tmds, u32 link_rate, + u32 n_param, struct snd_intelhad *intelhaddata) { u32 cts_val; u64 dividend, divisor; @@ -854,13 +854,13 @@ static int had_calculate_n_value(u32 aud_samp_freq) * * @aud_samp_freq: sampling frequency of audio data * @n_param: N value, depends on aud_samp_freq - * @intelhaddata:substream private data + * @intelhaddata: substream private data * * This function is called in the prepare callback. * It programs based on the audio and display sampling frequency */ -static int snd_intelhad_prog_n(u32 aud_samp_freq, u32 *n_param, - struct snd_intelhad *intelhaddata) +static int had_prog_n(u32 aud_samp_freq, u32 *n_param, + struct snd_intelhad *intelhaddata) { int n_val; @@ -917,7 +917,7 @@ static void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata) /* * ALSA PCM open callback */ -static int snd_intelhad_open(struct snd_pcm_substream *substream) +static int had_pcm_open(struct snd_pcm_substream *substream) { struct snd_intelhad *intelhaddata; struct snd_pcm_runtime *runtime; @@ -936,7 +936,7 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) } /* set the runtime hw parameter with local snd_pcm_hardware struct */ - runtime->hw = snd_intel_hadstream; + runtime->hw = had_pcm_hardware; retval = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); @@ -971,7 +971,7 @@ static int snd_intelhad_open(struct snd_pcm_substream *substream) /* * ALSA PCM close callback */ -static int snd_intelhad_close(struct snd_pcm_substream *substream) +static int had_pcm_close(struct snd_pcm_substream *substream) { struct snd_intelhad *intelhaddata; @@ -995,8 +995,8 @@ static int snd_intelhad_close(struct snd_pcm_substream *substream) /* * ALSA PCM hw_params callback */ -static int snd_intelhad_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) +static int had_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) { struct snd_intelhad *intelhaddata; unsigned long addr; @@ -1026,7 +1026,7 @@ static int snd_intelhad_hw_params(struct snd_pcm_substream *substream, /* * ALSA PCM hw_free callback */ -static int snd_intelhad_hw_free(struct snd_pcm_substream *substream) +static int had_pcm_hw_free(struct snd_pcm_substream *substream) { unsigned long addr; u32 pages; @@ -1045,8 +1045,7 @@ static int snd_intelhad_hw_free(struct snd_pcm_substream *substream) /* * ALSA PCM trigger callback */ -static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, - int cmd) +static int had_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { int retval = 0; struct snd_intelhad *intelhaddata; @@ -1068,8 +1067,8 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, intelhaddata->stream_info.running = true; /* Enable Audio */ - snd_intelhad_enable_audio_int(intelhaddata, true); - snd_intelhad_enable_audio(substream, intelhaddata, true); + had_enable_audio_int(intelhaddata, true); + had_enable_audio(substream, intelhaddata, true); break; case SNDRV_PCM_TRIGGER_STOP: @@ -1082,11 +1081,11 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, intelhaddata->stream_info.running = false; spin_unlock(&intelhaddata->had_spinlock); /* Disable Audio */ - snd_intelhad_enable_audio_int(intelhaddata, false); - snd_intelhad_enable_audio(substream, intelhaddata, false); + had_enable_audio_int(intelhaddata, false); + had_enable_audio(substream, intelhaddata, false); /* Reset buffer pointers */ had_reset_audio(intelhaddata); - snd_intelhad_enable_audio_int(intelhaddata, false); + had_enable_audio_int(intelhaddata, false); break; default: @@ -1098,7 +1097,7 @@ static int snd_intelhad_pcm_trigger(struct snd_pcm_substream *substream, /* * ALSA PCM prepare callback */ -static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) +static int had_pcm_prepare(struct snd_pcm_substream *substream) { int retval; u32 disp_samp_freq, n_param; @@ -1131,8 +1130,7 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) /* Get N value in KHz */ disp_samp_freq = intelhaddata->tmds_clock_speed; - retval = snd_intelhad_prog_n(substream->runtime->rate, &n_param, - intelhaddata); + retval = had_prog_n(substream->runtime->rate, &n_param, intelhaddata); if (retval) { dev_err(intelhaddata->dev, "programming N value failed %#x\n", retval); @@ -1142,13 +1140,12 @@ static int snd_intelhad_pcm_prepare(struct snd_pcm_substream *substream) if (intelhaddata->dp_output) link_rate = intelhaddata->link_rate; - snd_intelhad_prog_cts(substream->runtime->rate, - disp_samp_freq, link_rate, - n_param, intelhaddata); + had_prog_cts(substream->runtime->rate, disp_samp_freq, link_rate, + n_param, intelhaddata); - snd_intelhad_prog_dip(substream, intelhaddata); + had_prog_dip(substream, intelhaddata); - retval = snd_intelhad_audio_ctrl(substream, intelhaddata); + retval = had_init_audio_ctrl(substream, intelhaddata); /* Prog buffer address */ retval = snd_intelhad_prog_buffer(substream, intelhaddata, @@ -1168,8 +1165,7 @@ prep_end: /* * ALSA PCM pointer callback */ -static snd_pcm_uframes_t -snd_intelhad_pcm_pointer(struct snd_pcm_substream *substream) +static snd_pcm_uframes_t had_pcm_pointer(struct snd_pcm_substream *substream) { struct snd_intelhad *intelhaddata; u32 bytes_rendered = 0; @@ -1219,8 +1215,8 @@ snd_intelhad_pcm_pointer(struct snd_pcm_substream *substream) /* * ALSA PCM mmap callback */ -static int snd_intelhad_pcm_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *vma) +static int had_pcm_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) { vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); return remap_pfn_range(vma, vma->vm_start, @@ -1231,20 +1227,20 @@ static int snd_intelhad_pcm_mmap(struct snd_pcm_substream *substream, /* * ALSA PCM ops */ -static const struct snd_pcm_ops snd_intelhad_playback_ops = { - .open = snd_intelhad_open, - .close = snd_intelhad_close, +static const struct snd_pcm_ops had_pcm_ops = { + .open = had_pcm_open, + .close = had_pcm_close, .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_intelhad_hw_params, - .hw_free = snd_intelhad_hw_free, - .prepare = snd_intelhad_pcm_prepare, - .trigger = snd_intelhad_pcm_trigger, - .pointer = snd_intelhad_pcm_pointer, - .mmap = snd_intelhad_pcm_mmap, + .hw_params = had_pcm_hw_params, + .hw_free = had_pcm_hw_free, + .prepare = had_pcm_prepare, + .trigger = had_pcm_trigger, + .pointer = had_pcm_pointer, + .mmap = had_pcm_mmap, }; /* process mode change of the running stream; called in mutex */ -static int hdmi_audio_mode_change(struct snd_intelhad *intelhaddata) +static int had_process_mode_change(struct snd_intelhad *intelhaddata) { struct snd_pcm_substream *substream; int retval = 0; @@ -1256,13 +1252,12 @@ static int hdmi_audio_mode_change(struct snd_intelhad *intelhaddata) return 0; /* Disable Audio */ - snd_intelhad_enable_audio(substream, intelhaddata, false); + had_enable_audio(substream, intelhaddata, false); /* Update CTS value */ disp_samp_freq = intelhaddata->tmds_clock_speed; - retval = snd_intelhad_prog_n(substream->runtime->rate, &n_param, - intelhaddata); + retval = had_prog_n(substream->runtime->rate, &n_param, intelhaddata); if (retval) { dev_err(intelhaddata->dev, "programming N value failed %#x\n", retval); @@ -1272,12 +1267,11 @@ static int hdmi_audio_mode_change(struct snd_intelhad *intelhaddata) if (intelhaddata->dp_output) link_rate = intelhaddata->link_rate; - snd_intelhad_prog_cts(substream->runtime->rate, - disp_samp_freq, link_rate, - n_param, intelhaddata); + had_prog_cts(substream->runtime->rate, disp_samp_freq, link_rate, + n_param, intelhaddata); /* Enable Audio */ - snd_intelhad_enable_audio(substream, intelhaddata, true); + had_enable_audio(substream, intelhaddata, true); out: had_substream_put(intelhaddata); @@ -1510,8 +1504,8 @@ static void had_process_hot_unplug(struct snd_intelhad *intelhaddata) } /* Disable Audio */ - snd_intelhad_enable_audio_int(intelhaddata, false); - snd_intelhad_enable_audio(substream, intelhaddata, false); + had_enable_audio_int(intelhaddata, false); + had_enable_audio(substream, intelhaddata, false); intelhaddata->connected = false; dev_dbg(intelhaddata->dev, @@ -1712,7 +1706,7 @@ static void had_audio_wq(struct work_struct *work) had_process_hot_plug(ctx); /* Process mode change if stream is active */ - hdmi_audio_mode_change(ctx); + had_process_mode_change(ctx); } mutex_unlock(&ctx->mutex); pm_runtime_put(ctx->dev); @@ -1862,8 +1856,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) pcm->info_flags = 0; strncpy(pcm->name, card->shortname, strlen(card->shortname)); /* setup the ops for playabck */ - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, - &snd_intelhad_playback_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &had_pcm_ops); /* only 32bit addressable */ dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); @@ -1923,7 +1916,7 @@ static int hdmi_lpe_audio_remove(struct platform_device *pdev) struct snd_intelhad *ctx = platform_get_drvdata(pdev); if (ctx->connected) - snd_intelhad_enable_audio_int(ctx, false); + had_enable_audio_int(ctx, false); snd_card_free(ctx->card); return 0; } -- cgit v1.2.3 From 1cf05ba2cafa079a943c2cbae51b2f2c2e247466 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 5 Feb 2017 08:58:46 +0100 Subject: ALSA: pcm: Define dummy snd_pcm_suspend() for CONFIG_PM=n ... so that the driver can avoid ifdef's for the dead PM callbacks. The compiler should optimize them out in anyway. Reported-by: kbuild test robot Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index af1fb37c6b26..361749e60799 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -570,6 +570,15 @@ int snd_pcm_stop_xrun(struct snd_pcm_substream *substream); #ifdef CONFIG_PM int snd_pcm_suspend(struct snd_pcm_substream *substream); int snd_pcm_suspend_all(struct snd_pcm *pcm); +#else +static inline int snd_pcm_suspend(struct snd_pcm_substream *substream) +{ + return 0; +} +static inline int snd_pcm_suspend_all(struct snd_pcm *pcm) +{ + return 0; +} #endif int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg); int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, struct file *file, -- cgit v1.2.3 From e1b239f371c0c745542cb8108d085ec728e8a69c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 3 Feb 2017 00:01:18 +0100 Subject: ALSA: x86: Refactor PCM process engine This is again a big rewrite of the driver; now it touches the code to process PCM stream transfers. The most fundamental change is that the driver may support more than four periods. Instead of keeping the same index between both the ring buffer (with the fixed four buffer descriptors) and the PCM buffer periods, we keep difference indices for both (bd_head and pcm_head fields). In addition, when the periods are more than four, we need to track both head and next indices. That is, we now have three indices: bd_head, pcm_head and pcm_filled. Also, the driver works better for periods < 4, too: the remaining BDs out of four are marked as invalid, so that the hardware skips those BDs in its loop. By this flexibility, we can use even ALSA-lib dmix plugin, which requires 16 periods as default. The buffer size could be up to 20bit, so the max buffer size was increased accordingly. However, the buffer pre-allocation is kept as the old value (600kB) as default. The reason is the limited number of BDs: since it doesn't suffice for the useful SG page management that can fit with the usual page allocator like some other drivers, we have to still allocate continuous pages, hence we shouldn't take too big memories there. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 536 ++++++++++++++++----------------------- sound/x86/intel_hdmi_audio.h | 24 +- sound/x86/intel_hdmi_lpe_audio.h | 25 +- 3 files changed, 231 insertions(+), 354 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 57042ef3a480..8978dc9bf579 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -622,82 +622,6 @@ static void had_prog_dip(struct snd_pcm_substream *substream, had_write_register(intelhaddata, AUD_CNTL_ST, ctrl_state.regval); } -/* - * Programs buffer address and length registers - * This function programs ring buffer address and length into registers. - */ -static int snd_intelhad_prog_buffer(struct snd_pcm_substream *substream, - struct snd_intelhad *intelhaddata, - int start, int end) -{ - u32 ring_buf_addr, ring_buf_size, period_bytes; - u8 i, num_periods; - - ring_buf_addr = substream->runtime->dma_addr; - ring_buf_size = snd_pcm_lib_buffer_bytes(substream); - intelhaddata->stream_info.ring_buf_size = ring_buf_size; - period_bytes = frames_to_bytes(substream->runtime, - substream->runtime->period_size); - num_periods = substream->runtime->periods; - - /* - * buffer addr should be 64 byte aligned, period bytes - * will be used to calculate addr offset - */ - period_bytes &= ~0x3F; - - /* Hardware supports MAX_PERIODS buffers */ - if (end >= HAD_MAX_PERIODS) - return -EINVAL; - - for (i = start; i <= end; i++) { - /* Program the buf registers with addr and len */ - intelhaddata->buf_info[i].buf_addr = ring_buf_addr + - (i * period_bytes); - if (i < num_periods-1) - intelhaddata->buf_info[i].buf_size = period_bytes; - else - intelhaddata->buf_info[i].buf_size = ring_buf_size - - (i * period_bytes); - - had_write_register(intelhaddata, - AUD_BUF_A_ADDR + (i * HAD_REG_WIDTH), - intelhaddata->buf_info[i].buf_addr | - BIT(0) | BIT(1)); - had_write_register(intelhaddata, - AUD_BUF_A_LENGTH + (i * HAD_REG_WIDTH), - period_bytes); - intelhaddata->buf_info[i].is_valid = true; - } - dev_dbg(intelhaddata->dev, "%s:buf[%d-%d] addr=%#x and size=%d\n", - __func__, start, end, - intelhaddata->buf_info[start].buf_addr, - intelhaddata->buf_info[start].buf_size); - intelhaddata->valid_buf_cnt = num_periods; - return 0; -} - -static int snd_intelhad_read_len(struct snd_intelhad *intelhaddata) -{ - int i, retval = 0; - u32 len[4]; - - for (i = 0; i < 4 ; i++) { - had_read_register(intelhaddata, - AUD_BUF_A_LENGTH + (i * HAD_REG_WIDTH), - &len[i]); - if (!len[i]) - retval++; - } - if (retval != 1) { - for (i = 0; i < 4 ; i++) - dev_dbg(intelhaddata->dev, "buf[%d] size=%d\n", - i, len[i]); - } - - return retval; -} - static int had_calculate_maud_value(u32 aud_samp_freq, u32 link_rate) { u32 maud_val; @@ -885,33 +809,217 @@ static int had_prog_n(u32 aud_samp_freq, u32 *n_param, return 0; } +/* + * PCM ring buffer handling + * + * The hardware provides a ring buffer with the fixed 4 buffer descriptors + * (BDs). The driver maps these 4 BDs onto the PCM ring buffer. The mapping + * moves at each period elapsed. The below illustrates how it works: + * + * At time=0 + * PCM | 0 | 1 | 2 | 3 | 4 | 5 | .... |n-1| + * BD | 0 | 1 | 2 | 3 | + * + * At time=1 (period elapsed) + * PCM | 0 | 1 | 2 | 3 | 4 | 5 | .... |n-1| + * BD | 1 | 2 | 3 | 0 | + * + * At time=2 (second period elapsed) + * PCM | 0 | 1 | 2 | 3 | 4 | 5 | .... |n-1| + * BD | 2 | 3 | 0 | 1 | + * + * The bd_head field points to the index of the BD to be read. It's also the + * position to be filled at next. The pcm_head and the pcm_filled fields + * point to the indices of the current position and of the next position to + * be filled, respectively. For PCM buffer there are both _head and _filled + * because they may be difference when nperiods > 4. For example, in the + * example above at t=1, bd_head=1 and pcm_head=1 while pcm_filled=5: + * + * pcm_head (=1) --v v-- pcm_filled (=5) + * PCM | 0 | 1 | 2 | 3 | 4 | 5 | .... |n-1| + * BD | 1 | 2 | 3 | 0 | + * bd_head (=1) --^ ^-- next to fill (= bd_head) + * + * For nperiods < 4, the remaining BDs out of 4 are marked as invalid, so that + * the hardware skips those BDs in the loop. + */ + +#define AUD_BUF_ADDR(x) (AUD_BUF_A_ADDR + (x) * HAD_REG_WIDTH) +#define AUD_BUF_LEN(x) (AUD_BUF_A_LENGTH + (x) * HAD_REG_WIDTH) + +/* Set up a buffer descriptor at the "filled" position */ +static void had_prog_bd(struct snd_pcm_substream *substream, + struct snd_intelhad *intelhaddata) +{ + int idx = intelhaddata->bd_head; + int ofs = intelhaddata->pcmbuf_filled * intelhaddata->period_bytes; + u32 addr = substream->runtime->dma_addr + ofs; + + addr |= AUD_BUF_VALID | AUD_BUF_INTR_EN; + had_write_register(intelhaddata, AUD_BUF_ADDR(idx), addr); + had_write_register(intelhaddata, AUD_BUF_LEN(idx), + intelhaddata->period_bytes); + + /* advance the indices to the next */ + intelhaddata->bd_head++; + intelhaddata->bd_head %= intelhaddata->num_bds; + intelhaddata->pcmbuf_filled++; + intelhaddata->pcmbuf_filled %= substream->runtime->periods; +} + +/* invalidate a buffer descriptor with the given index */ +static void had_invalidate_bd(struct snd_intelhad *intelhaddata, + int idx) +{ + had_write_register(intelhaddata, AUD_BUF_ADDR(idx), 0); + had_write_register(intelhaddata, AUD_BUF_LEN(idx), 0); +} + +/* Initial programming of ring buffer */ +static void had_init_ringbuf(struct snd_pcm_substream *substream, + struct snd_intelhad *intelhaddata) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + int i, num_periods; + + num_periods = runtime->periods; + intelhaddata->num_bds = min(num_periods, HAD_NUM_OF_RING_BUFS); + intelhaddata->period_bytes = + frames_to_bytes(runtime, runtime->period_size); + WARN_ON(intelhaddata->period_bytes & 0x3f); + + intelhaddata->bd_head = 0; + intelhaddata->pcmbuf_head = 0; + intelhaddata->pcmbuf_filled = 0; + + for (i = 0; i < HAD_NUM_OF_RING_BUFS; i++) { + if (i < num_periods) + had_prog_bd(substream, intelhaddata); + else /* invalidate the rest */ + had_invalidate_bd(intelhaddata, i); + } + + intelhaddata->bd_head = 0; /* reset at head again before starting */ +} + +/* process a bd, advance to the next */ +static void had_advance_ringbuf(struct snd_pcm_substream *substream, + struct snd_intelhad *intelhaddata) +{ + int num_periods = substream->runtime->periods; + + /* reprogram the next buffer */ + had_prog_bd(substream, intelhaddata); + + /* proceed to next */ + intelhaddata->pcmbuf_head++; + intelhaddata->pcmbuf_head %= num_periods; +} + +/* process the current BD(s); + * returns the current PCM buffer byte position, or -EPIPE for underrun. + */ +static int had_process_ringbuf(struct snd_pcm_substream *substream, + struct snd_intelhad *intelhaddata) +{ + int len, processed; + unsigned long flags; + + processed = 0; + spin_lock_irqsave(&intelhaddata->had_spinlock, flags); + for (;;) { + /* get the remaining bytes on the buffer */ + had_read_register(intelhaddata, + AUD_BUF_LEN(intelhaddata->bd_head), + &len); + if (len < 0 || len > intelhaddata->period_bytes) { + dev_dbg(intelhaddata->dev, "Invalid buf length %d\n", + len); + len = -EPIPE; + goto out; + } + + if (len > 0) /* OK, this is the current buffer */ + break; + + /* len=0 => already empty, check the next buffer */ + if (++processed >= intelhaddata->num_bds) { + len = -EPIPE; /* all empty? - report underrun */ + goto out; + } + had_advance_ringbuf(substream, intelhaddata); + } + + len = intelhaddata->period_bytes - len; + len += intelhaddata->period_bytes * intelhaddata->pcmbuf_head; + out: + spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags); + return len; +} + +/* called from irq handler */ +static void had_process_buffer_done(struct snd_intelhad *intelhaddata) +{ + struct snd_pcm_substream *substream; + + if (!intelhaddata->connected) + return; /* disconnected? - bail out */ + + substream = had_substream_get(intelhaddata); + if (!substream) + return; /* no stream? - bail out */ + + /* process or stop the stream */ + if (had_process_ringbuf(substream, intelhaddata) < 0) + snd_pcm_stop_xrun(substream); + else + snd_pcm_period_elapsed(substream); + + had_substream_put(intelhaddata); +} + #define MAX_CNT 0xFF -static void snd_intelhad_handle_underrun(struct snd_intelhad *intelhaddata) +/* + * The interrupt status 'sticky' bits might not be cleared by + * setting '1' to that bit once... + */ +static void wait_clear_underrun_bit(struct snd_intelhad *intelhaddata) +{ + int i; + u32 val; + + for (i = 0; i < MAX_CNT; i++) { + /* clear bit30, 31 AUD_HDMI_STATUS */ + had_read_register(intelhaddata, AUD_HDMI_STATUS, &val); + if (!(val & AUD_CONFIG_MASK_UNDERRUN)) + return; + had_write_register(intelhaddata, AUD_HDMI_STATUS, val); + } + dev_err(intelhaddata->dev, "Unable to clear UNDERRUN bits\n"); +} + +/* called from irq handler */ +static void had_process_buffer_underrun(struct snd_intelhad *intelhaddata) { - u32 hdmi_status = 0, i = 0; + struct snd_pcm_substream *substream; /* Handle Underrun interrupt within Audio Unit */ had_write_register(intelhaddata, AUD_CONFIG, 0); /* Reset buffer pointers */ had_reset_audio(intelhaddata); - /* - * The interrupt status 'sticky' bits might not be cleared by - * setting '1' to that bit once... - */ - do { /* clear bit30, 31 AUD_HDMI_STATUS */ - had_read_register(intelhaddata, AUD_HDMI_STATUS, - &hdmi_status); - dev_dbg(intelhaddata->dev, "HDMI status =0x%x\n", hdmi_status); - if (hdmi_status & AUD_CONFIG_MASK_UNDERRUN) { - i++; - had_write_register(intelhaddata, - AUD_HDMI_STATUS, hdmi_status); - } else - break; - } while (i < MAX_CNT); - if (i >= MAX_CNT) - dev_err(intelhaddata->dev, "Unable to clear UNDERRUN bits\n"); + + wait_clear_underrun_bit(intelhaddata); + + if (!intelhaddata->connected) + return; /* disconnected? - bail out */ + + /* Report UNDERRUN error to above layers */ + substream = had_substream_get(intelhaddata); + if (substream) { + snd_pcm_stop_xrun(substream); + had_substream_put(intelhaddata); + } } /* @@ -957,11 +1065,6 @@ static int had_pcm_open(struct snd_pcm_substream *substream) intelhaddata->stream_info.substream_refcount++; spin_unlock_irq(&intelhaddata->had_spinlock); - /* these are cleared in prepare callback, but just to be sure */ - intelhaddata->curr_buf = 0; - intelhaddata->underrun_count = 0; - intelhaddata->stream_info.buffer_rendered = 0; - return retval; error: pm_runtime_put(intelhaddata->dev); @@ -1123,10 +1226,6 @@ static int had_pcm_prepare(struct snd_pcm_substream *substream) dev_dbg(intelhaddata->dev, "rate=%d\n", runtime->rate); dev_dbg(intelhaddata->dev, "channels=%d\n", runtime->channels); - intelhaddata->curr_buf = 0; - intelhaddata->underrun_count = 0; - intelhaddata->stream_info.buffer_rendered = 0; - /* Get N value in KHz */ disp_samp_freq = intelhaddata->tmds_clock_speed; @@ -1148,8 +1247,7 @@ static int had_pcm_prepare(struct snd_pcm_substream *substream) retval = had_init_audio_ctrl(substream, intelhaddata); /* Prog buffer address */ - retval = snd_intelhad_prog_buffer(substream, intelhaddata, - HAD_BUF_TYPE_A, HAD_BUF_TYPE_D); + had_init_ringbuf(substream, intelhaddata); /* * Program channel mapping in following order: @@ -1168,48 +1266,17 @@ prep_end: static snd_pcm_uframes_t had_pcm_pointer(struct snd_pcm_substream *substream) { struct snd_intelhad *intelhaddata; - u32 bytes_rendered = 0; - u32 t; - int buf_id; + int len; intelhaddata = snd_pcm_substream_chip(substream); if (!intelhaddata->connected) return SNDRV_PCM_POS_XRUN; - /* Use a hw register to calculate sub-period position reports. - * This makes PulseAudio happier. - */ - - buf_id = intelhaddata->curr_buf % 4; - had_read_register(intelhaddata, - AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH), &t); - - if ((t == 0) || (t == ((u32)-1L))) { - intelhaddata->underrun_count++; - dev_dbg(intelhaddata->dev, - "discovered buffer done for buf %d, count = %d\n", - buf_id, intelhaddata->underrun_count); - - if (intelhaddata->underrun_count > (HAD_MIN_PERIODS/2)) { - dev_dbg(intelhaddata->dev, - "assume audio_codec_reset, underrun = %d - do xrun\n", - intelhaddata->underrun_count); - return SNDRV_PCM_POS_XRUN; - } - } else { - /* Reset Counter */ - intelhaddata->underrun_count = 0; - } - - t = intelhaddata->buf_info[buf_id].buf_size - t; - - if (intelhaddata->stream_info.buffer_rendered) - div_u64_rem(intelhaddata->stream_info.buffer_rendered, - intelhaddata->stream_info.ring_buf_size, - &(bytes_rendered)); - - return bytes_to_frames(substream->runtime, bytes_rendered + t); + len = had_process_ringbuf(substream, intelhaddata); + if (len < 0) + return SNDRV_PCM_POS_XRUN; + return bytes_to_frames(substream->runtime, len); } /* @@ -1278,179 +1345,9 @@ out: return retval; } -static inline int had_chk_intrmiss(struct snd_intelhad *intelhaddata, - enum intel_had_aud_buf_type buf_id) -{ - int i, intr_count = 0; - enum intel_had_aud_buf_type buff_done; - u32 buf_size, buf_addr; - - buff_done = buf_id; - - intr_count = snd_intelhad_read_len(intelhaddata); - if (intr_count > 1) { - /* In case of active playback */ - dev_err(intelhaddata->dev, - "Driver detected %d missed buffer done interrupt(s)\n", - (intr_count - 1)); - if (intr_count > 3) - return intr_count; - - buf_id += (intr_count - 1); - /* Reprogram registers*/ - for (i = buff_done; i < buf_id; i++) { - int j = i % 4; - - buf_size = intelhaddata->buf_info[j].buf_size; - buf_addr = intelhaddata->buf_info[j].buf_addr; - had_write_register(intelhaddata, - AUD_BUF_A_LENGTH + - (j * HAD_REG_WIDTH), buf_size); - had_write_register(intelhaddata, - AUD_BUF_A_ADDR+(j * HAD_REG_WIDTH), - (buf_addr | BIT(0) | BIT(1))); - } - buf_id = buf_id % 4; - intelhaddata->buff_done = buf_id; - } - - return intr_count; -} - -/* called from irq handler */ -static int had_process_buffer_done(struct snd_intelhad *intelhaddata) -{ - u32 len = 1; - enum intel_had_aud_buf_type buf_id; - enum intel_had_aud_buf_type buff_done; - struct pcm_stream_info *stream; - struct snd_pcm_substream *substream; - u32 buf_size; - int intr_count; - unsigned long flags; - - stream = &intelhaddata->stream_info; - intr_count = 1; - - spin_lock_irqsave(&intelhaddata->had_spinlock, flags); - if (!intelhaddata->connected) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags); - dev_dbg(intelhaddata->dev, - "%s:Device already disconnected\n", __func__); - return 0; - } - buf_id = intelhaddata->curr_buf; - intelhaddata->buff_done = buf_id; - buff_done = intelhaddata->buff_done; - buf_size = intelhaddata->buf_info[buf_id].buf_size; - - /* Every debug statement has an implication - * of ~5msec. Thus, avoid having >3 debug statements - * for each buffer_done handling. - */ - - /* Check for any intr_miss in case of active playback */ - if (stream->running) { - intr_count = had_chk_intrmiss(intelhaddata, buf_id); - if (!intr_count || (intr_count > 3)) { - spin_unlock_irqrestore(&intelhaddata->had_spinlock, - flags); - dev_err(intelhaddata->dev, - "HAD SW state in non-recoverable mode\n"); - return 0; - } - buf_id += (intr_count - 1); - buf_id = buf_id % 4; - } - - intelhaddata->buf_info[buf_id].is_valid = true; - if (intelhaddata->valid_buf_cnt-1 == buf_id) { - if (stream->running) - intelhaddata->curr_buf = HAD_BUF_TYPE_A; - } else - intelhaddata->curr_buf = buf_id + 1; - - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags); - - if (!intelhaddata->connected) { - dev_dbg(intelhaddata->dev, "HDMI cable plugged-out\n"); - return 0; - } - - /* Reprogram the registers with addr and length */ - had_write_register(intelhaddata, - AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH), - buf_size); - had_write_register(intelhaddata, - AUD_BUF_A_ADDR + (buf_id * HAD_REG_WIDTH), - intelhaddata->buf_info[buf_id].buf_addr | - BIT(0) | BIT(1)); - - had_read_register(intelhaddata, - AUD_BUF_A_LENGTH + (buf_id * HAD_REG_WIDTH), - &len); - dev_dbg(intelhaddata->dev, "%s:Enabled buf[%d]\n", __func__, buf_id); - - /* In case of actual data, - * report buffer_done to above ALSA layer - */ - substream = had_substream_get(intelhaddata); - if (substream) { - buf_size = intelhaddata->buf_info[buf_id].buf_size; - intelhaddata->stream_info.buffer_rendered += - (intr_count * buf_size); - snd_pcm_period_elapsed(substream); - had_substream_put(intelhaddata); - } - - return 0; -} - -/* called from irq handler */ -static int had_process_buffer_underrun(struct snd_intelhad *intelhaddata) -{ - enum intel_had_aud_buf_type buf_id; - struct pcm_stream_info *stream; - struct snd_pcm_substream *substream; - unsigned long flags; - int connected; - - stream = &intelhaddata->stream_info; - - spin_lock_irqsave(&intelhaddata->had_spinlock, flags); - buf_id = intelhaddata->curr_buf; - intelhaddata->buff_done = buf_id; - connected = intelhaddata->connected; - if (stream->running) - intelhaddata->curr_buf = HAD_BUF_TYPE_A; - - spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags); - - dev_dbg(intelhaddata->dev, "Enter:%s buf_id=%d, stream_running=%d\n", - __func__, buf_id, stream->running); - - snd_intelhad_handle_underrun(intelhaddata); - - if (!connected) { - dev_dbg(intelhaddata->dev, - "%s:Device already disconnected\n", __func__); - return 0; - } - - /* Report UNDERRUN error to above layers */ - substream = had_substream_get(intelhaddata); - if (substream) { - snd_pcm_stop_xrun(substream); - had_substream_put(intelhaddata); - } - - return 0; -} - /* process hot plug, called from wq with mutex locked */ static void had_process_hot_plug(struct snd_intelhad *intelhaddata) { - enum intel_had_aud_buf_type buf_id; struct snd_pcm_substream *substream; spin_lock_irq(&intelhaddata->had_spinlock); @@ -1460,17 +1357,12 @@ static void had_process_hot_plug(struct snd_intelhad *intelhaddata) return; } - buf_id = intelhaddata->curr_buf; - intelhaddata->buff_done = buf_id; intelhaddata->connected = true; dev_dbg(intelhaddata->dev, "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_CONNECTED\n", __func__, __LINE__); spin_unlock_irq(&intelhaddata->had_spinlock); - dev_dbg(intelhaddata->dev, "Processing HOT_PLUG, buf_id = %d\n", - buf_id); - /* Safety check */ substream = had_substream_get(intelhaddata); if (substream) { @@ -1487,11 +1379,8 @@ static void had_process_hot_plug(struct snd_intelhad *intelhaddata) /* process hot unplug, called from wq with mutex locked */ static void had_process_hot_unplug(struct snd_intelhad *intelhaddata) { - enum intel_had_aud_buf_type buf_id; struct snd_pcm_substream *substream; - buf_id = intelhaddata->curr_buf; - substream = had_substream_get(intelhaddata); spin_lock_irq(&intelhaddata->had_spinlock); @@ -1862,13 +1751,12 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); - /* allocate dma pages for ALSA stream operations - * memory allocated is based on size, not max value - * thus using same argument for max & size + /* allocate dma pages; + * try to allocate 600k buffer as default which is large enough */ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, NULL, - HAD_MAX_BUFFER, HAD_MAX_BUFFER); + HAD_DEFAULT_BUFFER, HAD_MAX_BUFFER); /* create controls */ for (i = 0; i < ARRAY_SIZE(had_controls); i++) { diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 9f713a8a88bc..7e2546b853ca 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -64,24 +64,15 @@ struct pcm_stream_info { struct snd_pcm_substream *substream; - u64 buffer_rendered; - u32 ring_buf_size; int substream_refcount; bool running; }; -struct ring_buf_info { - u32 buf_addr; - u32 buf_size; - u8 is_valid; -}; - /* * struct snd_intelhad - intelhad driver structure * * @card: ptr to hold card details * @connected: the monitor connection status - * @buf_info: ring buffer info * @stream_info: stream information * @eld: holds ELD info * @curr_buf: pointer to hold current active ring buf @@ -91,26 +82,29 @@ struct ring_buf_info { * @buff_done: id of current buffer done intr * @dev: platoform device handle * @chmap: holds channel map info - * @underrun_count: PCM stream underrun counter */ struct snd_intelhad { struct snd_card *card; bool connected; - struct ring_buf_info buf_info[HAD_NUM_OF_RING_BUFS]; struct pcm_stream_info stream_info; unsigned char eld[HDMI_MAX_ELD_BYTES]; bool dp_output; - enum intel_had_aud_buf_type curr_buf; - int valid_buf_cnt; unsigned int aes_bits; spinlock_t had_spinlock; - enum intel_had_aud_buf_type buff_done; struct device *dev; struct snd_pcm_chmap *chmap; - int underrun_count; int tmds_clock_speed; int link_rate; + /* ring buffer (BD) position index */ + unsigned int bd_head; + /* PCM buffer position indices */ + unsigned int pcmbuf_head; /* being processed */ + unsigned int pcmbuf_filled; /* to be filled */ + + unsigned int num_bds; /* number of BDs */ + unsigned int period_bytes; /* PCM period size in bytes */ + /* internal stuff */ int irq; void __iomem *mmio_start; diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index be9783910a3a..ca4212dca94e 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -28,13 +28,13 @@ #define HAD_MAX_CHANNEL 8 #define HAD_NUM_OF_RING_BUFS 4 -/* Assume 192KHz, 8channel, 25msec period */ -#define HAD_MAX_BUFFER (600*1024) -#define HAD_MIN_BUFFER (32*1024) -#define HAD_MAX_PERIODS 4 -#define HAD_MIN_PERIODS 4 -#define HAD_MAX_PERIOD_BYTES (HAD_MAX_BUFFER/HAD_MIN_PERIODS) -#define HAD_MIN_PERIOD_BYTES 256 +/* max 20bit address, aligned to 64 */ +#define HAD_MAX_BUFFER ((1024 * 1024 - 1) & ~0x3f) +#define HAD_DEFAULT_BUFFER (600 * 1024) /* default prealloc size */ +#define HAD_MAX_PERIODS 256 /* arbitrary, but should suffice */ +#define HAD_MIN_PERIODS 2 +#define HAD_MAX_PERIOD_BYTES ((HAD_MAX_BUFFER / HAD_MIN_PERIODS) & ~0x3f) +#define HAD_MIN_PERIOD_BYTES 1024 /* might be smaller */ #define HAD_FIFO_SIZE 0 /* fifo not being used */ #define MAX_SPEAKERS 8 @@ -82,14 +82,6 @@ /* Naud Value */ #define DP_NAUD_VAL 32768 -/* enum intel_had_aud_buf_type - HDMI controller ring buffer types */ -enum intel_had_aud_buf_type { - HAD_BUF_TYPE_A = 0, - HAD_BUF_TYPE_B = 1, - HAD_BUF_TYPE_C = 2, - HAD_BUF_TYPE_D = 3, -}; - /* HDMI Controller register offsets - audio domain common */ /* Base address for below regs = 0x65000 */ enum hdmi_ctrl_reg_offset_common { @@ -274,6 +266,9 @@ union aud_buf_addr { u32 regval; }; +#define AUD_BUF_VALID (1U << 0) +#define AUD_BUF_INTR_EN (1U << 1) + /* Length of Audio Buffer */ union aud_buf_len { struct { -- cgit v1.2.3 From 5d81296b5e7849ba3bcc5bf430ffd37bf67ff7dc Mon Sep 17 00:00:00 2001 From: Andrej Krutak Date: Mon, 6 Feb 2017 20:34:58 +0100 Subject: ALSA: line6: Always setup isochronous transfer properties While not all line6 devices currently support PCM, it causes no harm to 'have it prepared'. This also fixes toneport, which only has PCM - in which case we previously skipped the USB transfer properties detection completely. Signed-off-by: Andrej Krutak Signed-off-by: Takashi Iwai --- sound/usb/line6/driver.c | 48 ++++++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c index ab3c280a23d1..0ff5a7d2e19f 100644 --- a/sound/usb/line6/driver.c +++ b/sound/usb/line6/driver.c @@ -492,42 +492,46 @@ static void line6_destruct(struct snd_card *card) usb_put_dev(usbdev); } -/* get data from endpoint descriptor (see usb_maxpacket): */ -static void line6_get_interval(struct usb_line6 *line6) +static void line6_get_usb_properties(struct usb_line6 *line6) { struct usb_device *usbdev = line6->usbdev; const struct line6_properties *properties = line6->properties; int pipe; - struct usb_host_endpoint *ep; + struct usb_host_endpoint *ep = NULL; - if (properties->capabilities & LINE6_CAP_CONTROL_MIDI) { - pipe = - usb_rcvintpipe(line6->usbdev, line6->properties->ep_ctrl_r); - } else { - pipe = - usb_rcvbulkpipe(line6->usbdev, line6->properties->ep_ctrl_r); + if (properties->capabilities & LINE6_CAP_CONTROL) { + if (properties->capabilities & LINE6_CAP_CONTROL_MIDI) { + pipe = usb_rcvintpipe(line6->usbdev, + line6->properties->ep_ctrl_r); + } else { + pipe = usb_rcvbulkpipe(line6->usbdev, + line6->properties->ep_ctrl_r); + } + ep = usbdev->ep_in[usb_pipeendpoint(pipe)]; } - ep = usbdev->ep_in[usb_pipeendpoint(pipe)]; + /* Control data transfer properties */ if (ep) { line6->interval = ep->desc.bInterval; - if (usbdev->speed == USB_SPEED_LOW) { - line6->intervals_per_second = USB_LOW_INTERVALS_PER_SECOND; - line6->iso_buffers = USB_LOW_ISO_BUFFERS; - } else { - line6->intervals_per_second = USB_HIGH_INTERVALS_PER_SECOND; - line6->iso_buffers = USB_HIGH_ISO_BUFFERS; - } - line6->max_packet_size = le16_to_cpu(ep->desc.wMaxPacketSize); } else { - dev_err(line6->ifcdev, - "endpoint not available, using fallback values"); + if (properties->capabilities & LINE6_CAP_CONTROL) { + dev_err(line6->ifcdev, + "endpoint not available, using fallback values"); + } line6->interval = LINE6_FALLBACK_INTERVAL; line6->max_packet_size = LINE6_FALLBACK_MAXPACKETSIZE; } -} + /* Isochronous transfer properties */ + if (usbdev->speed == USB_SPEED_LOW) { + line6->intervals_per_second = USB_LOW_INTERVALS_PER_SECOND; + line6->iso_buffers = USB_LOW_ISO_BUFFERS; + } else { + line6->intervals_per_second = USB_HIGH_INTERVALS_PER_SECOND; + line6->iso_buffers = USB_HIGH_ISO_BUFFERS; + } +} /* Enable buffering of incoming messages, flush the buffer */ static int line6_hwdep_open(struct snd_hwdep *hw, struct file *file) @@ -754,7 +758,7 @@ int line6_probe(struct usb_interface *interface, goto error; } - line6_get_interval(line6); + line6_get_usb_properties(line6); if (properties->capabilities & LINE6_CAP_CONTROL) { ret = line6_init_cap_control(line6); -- cgit v1.2.3 From 3e21a76ca32f535a7640b0657f8d56660527ddab Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 7 Feb 2017 08:13:50 +0100 Subject: ALSA: x86: Drop suspicious U24 format support U24 format is declared to be supported by the driver, but this looks really doubtful, as there is no corresponding code. Better to drop it. This format is very uncommon, so there should be practically no impact by this change. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 8978dc9bf579..11ee4dddc5dd 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -136,8 +136,7 @@ static const struct snd_pcm_hardware had_pcm_hardware = { SNDRV_PCM_INFO_MMAP| SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BATCH), - .formats = (SNDRV_PCM_FMTBIT_S24 | - SNDRV_PCM_FMTBIT_U24), + .formats = SNDRV_PCM_FMTBIT_S24, .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | -- cgit v1.2.3 From 075a1d46bed386138eb51f92a6a3130c82fdefec Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 7 Feb 2017 07:55:27 +0100 Subject: ALSA: x86: Rename had_enable_audio_int() to had_ack_irqs() had_enable_audio_int() came from the LPE audio shell set_caps callback with ENABLE_INT and DISABLE_INT caps. I interpreted as these correspond to enabling / disabling the audio interface, but the actual implementation is only to clear (send ACK) to both BUFFER_DONE and BUFFER_UNDERRUN interrupts unconditionally. And, there is no counterpart, DISABLE_INT, code at all. For avoiding the further misunderstanding, rename the function to the more fitting one, had_ack_irqs(), and drop the calls with enable=false in allover places. There is no functional changes at all. After this patch, there is only one caller at the PCM trigger start. Then it's doubtful whether this call is still really needed or not; I bet it not, but let's stay in the safer side for now and keep it as was. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 11ee4dddc5dd..8506a3dc0298 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -238,17 +238,15 @@ static void had_enable_audio(struct snd_pcm_substream *substream, had_write_register(intelhaddata, AUD_CONFIG, val); } -/* enable / disable the audio interface */ -static void had_enable_audio_int(struct snd_intelhad *ctx, bool enable) +/* forcibly ACKs to both BUFFER_DONE and BUFFER_UNDERRUN interrupts */ +static void had_ack_irqs(struct snd_intelhad *ctx) { u32 status_reg; - if (enable) { - had_read_register(ctx, AUD_HDMI_STATUS, &status_reg); - status_reg |= HDMI_AUDIO_BUFFER_DONE | HDMI_AUDIO_UNDERRUN; - had_write_register(ctx, AUD_HDMI_STATUS, status_reg); - had_read_register(ctx, AUD_HDMI_STATUS, &status_reg); - } + had_read_register(ctx, AUD_HDMI_STATUS, &status_reg); + status_reg |= HDMI_AUDIO_BUFFER_DONE | HDMI_AUDIO_UNDERRUN; + had_write_register(ctx, AUD_HDMI_STATUS, status_reg); + had_read_register(ctx, AUD_HDMI_STATUS, &status_reg); } /* Reset buffer pointers */ @@ -1169,7 +1167,7 @@ static int had_pcm_trigger(struct snd_pcm_substream *substream, int cmd) intelhaddata->stream_info.running = true; /* Enable Audio */ - had_enable_audio_int(intelhaddata, true); + had_ack_irqs(intelhaddata); /* FIXME: do we need this? */ had_enable_audio(substream, intelhaddata, true); break; @@ -1183,11 +1181,9 @@ static int had_pcm_trigger(struct snd_pcm_substream *substream, int cmd) intelhaddata->stream_info.running = false; spin_unlock(&intelhaddata->had_spinlock); /* Disable Audio */ - had_enable_audio_int(intelhaddata, false); had_enable_audio(substream, intelhaddata, false); /* Reset buffer pointers */ had_reset_audio(intelhaddata); - had_enable_audio_int(intelhaddata, false); break; default: @@ -1392,7 +1388,6 @@ static void had_process_hot_unplug(struct snd_intelhad *intelhaddata) } /* Disable Audio */ - had_enable_audio_int(intelhaddata, false); had_enable_audio(substream, intelhaddata, false); intelhaddata->connected = false; @@ -1802,8 +1797,6 @@ static int hdmi_lpe_audio_remove(struct platform_device *pdev) { struct snd_intelhad *ctx = platform_get_drvdata(pdev); - if (ctx->connected) - had_enable_audio_int(ctx, false); snd_card_free(ctx->card); return 0; } -- cgit v1.2.3 From 873ab035752e62a90eaeb1daf88a44dad1da6ea0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 7 Feb 2017 12:14:04 +0100 Subject: ALSA: x86: Fix driver name string overflow The driver sets card->driver name string over its size (16 bytes). Shorten the name string to fit with it. Also, set more verbose string to card->shortname and ->longname. This doesn't have to be identical with card->driver at all. Reported-by: Dan Carpenter Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 3 ++- sound/x86/intel_hdmi_lpe_audio.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 8506a3dc0298..dd7944c5ebc2 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1694,7 +1694,8 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) ctx->card = card; ctx->aes_bits = SNDRV_PCM_DEFAULT_CON_SPDIF; strcpy(card->driver, INTEL_HAD); - strcpy(card->shortname, INTEL_HAD); + strcpy(card->shortname, "Intel HDMI/DP LPE Audio"); + strcpy(card->longname, "Intel HDMI/DP LPE Audio"); ctx->irq = -1; ctx->tmds_clock_speed = DIS_SAMPLE_RATE_148_5; diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index ca4212dca94e..48cab1b84c7b 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -57,7 +57,7 @@ #define HAD_REG_WIDTH 0x08 #define HAD_MAX_HW_BUFS 0x04 #define HAD_MAX_DIP_WORDS 16 -#define INTEL_HAD "IntelHdmiLpeAudio" +#define INTEL_HAD "HdmiLpeAudio" /* DP Link Rates */ #define DP_2_7_GHZ 270000 -- cgit v1.2.3 From 1df989242d3d790aec79e72d12874bf763c958e1 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 7 Feb 2017 14:38:51 +0100 Subject: ALSA: x86: mark hdmi suspend/resume functions as __maybe_unused The two functions are unused when CONFIG_PM_SLEEP is disabled: sound/x86/intel_hdmi_audio.c:1633:12: error: 'hdmi_lpe_audio_resume' defined but not used [-Werror=unused-function] sound/x86/intel_hdmi_audio.c:1622:12: error: 'hdmi_lpe_audio_suspend' defined but not used [-Werror=unused-function] Marking them as __maybe_unused avoids the warning without introducing an ugly #ifdef. Fixes: 182cdf23dbf6 ("ALSA: x86: Implement runtime PM") Signed-off-by: Arnd Bergmann Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index dd7944c5ebc2..1022aaa005c4 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1613,7 +1613,7 @@ static int hdmi_lpe_audio_runtime_suspend(struct device *dev) return 0; } -static int hdmi_lpe_audio_suspend(struct device *dev) +static int __maybe_unused hdmi_lpe_audio_suspend(struct device *dev) { struct snd_intelhad *ctx = dev_get_drvdata(dev); int err; @@ -1624,7 +1624,7 @@ static int hdmi_lpe_audio_suspend(struct device *dev) return err; } -static int hdmi_lpe_audio_resume(struct device *dev) +static int __maybe_unused hdmi_lpe_audio_resume(struct device *dev) { struct snd_intelhad *ctx = dev_get_drvdata(dev); -- cgit v1.2.3 From 77531beeb97d079fb422d2b78a0d75c564384310 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 7 Feb 2017 12:17:23 +0100 Subject: ALSA: x86: Rearrange defines We have two header files and everything is mixed up chaotically. Move the chip-specific definitions like the hardware registers to intel_hdmi_lpe_audio.h, and the rest, the implementation specific stuff into intel_hdmi_audio.h. In addition, put some more comments to the register fields, and fix the incorrect name prefix for AUD_HDMI_STATUS bits, too. The whole changes are merely a code shuffling, and there is no functional change. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 5 ++- sound/x86/intel_hdmi_audio.h | 64 +++++++++++++++++---------- sound/x86/intel_hdmi_lpe_audio.h | 95 +++++++++++++++++----------------------- 3 files changed, 83 insertions(+), 81 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 1022aaa005c4..34750c54663a 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -252,7 +252,8 @@ static void had_ack_irqs(struct snd_intelhad *ctx) /* Reset buffer pointers */ static void had_reset_audio(struct snd_intelhad *intelhaddata) { - had_write_register(intelhaddata, AUD_HDMI_STATUS, 1); + had_write_register(intelhaddata, AUD_HDMI_STATUS, + AUD_HDMI_STATUSG_MASK_FUNCRST); had_write_register(intelhaddata, AUD_HDMI_STATUS, 0); } @@ -989,7 +990,7 @@ static void wait_clear_underrun_bit(struct snd_intelhad *intelhaddata) for (i = 0; i < MAX_CNT; i++) { /* clear bit30, 31 AUD_HDMI_STATUS */ had_read_register(intelhaddata, AUD_HDMI_STATUS, &val); - if (!(val & AUD_CONFIG_MASK_UNDERRUN)) + if (!(val & AUD_HDMI_STATUS_MASK_UNDERRUN)) return; had_write_register(intelhaddata, AUD_HDMI_STATUS, val); } diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 7e2546b853ca..fe8d99cb839f 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -35,32 +35,50 @@ #define PCM_INDEX 0 #define MAX_PB_STREAMS 1 #define MAX_CAP_STREAMS 0 - -#define HDMI_INFO_FRAME_WORD1 0x000a0184 -#define DP_INFO_FRAME_WORD1 0x00441b84 -#define FIFO_THRESHOLD 0xFE -#define DMA_FIFO_THRESHOLD 0x7 #define BYTES_PER_WORD 0x4 +#define INTEL_HAD "HdmiLpeAudio" + +/* + * CEA speaker placement: + * + * FL FLC FC FRC FR + * + * LFE + * + * RL RLC RC RRC RR + * + * The Left/Right Surround channel _notions_ LS/RS in SMPTE 320M + * corresponds to CEA RL/RR; The SMPTE channel _assignment_ C/LFE is + * swapped to CEA LFE/FC. + */ +enum cea_speaker_placement { + FL = (1 << 0), /* Front Left */ + FC = (1 << 1), /* Front Center */ + FR = (1 << 2), /* Front Right */ + FLC = (1 << 3), /* Front Left Center */ + FRC = (1 << 4), /* Front Right Center */ + RL = (1 << 5), /* Rear Left */ + RC = (1 << 6), /* Rear Center */ + RR = (1 << 7), /* Rear Right */ + RLC = (1 << 8), /* Rear Left Center */ + RRC = (1 << 9), /* Rear Right Center */ + LFE = (1 << 10), /* Low Frequency Effect */ +}; -/* Sampling rate as per IEC60958 Ver 3 */ -#define CH_STATUS_MAP_32KHZ 0x3 -#define CH_STATUS_MAP_44KHZ 0x0 -#define CH_STATUS_MAP_48KHZ 0x2 -#define CH_STATUS_MAP_88KHZ 0x8 -#define CH_STATUS_MAP_96KHZ 0xA -#define CH_STATUS_MAP_176KHZ 0xC -#define CH_STATUS_MAP_192KHZ 0xE +struct cea_channel_speaker_allocation { + int ca_index; + int speakers[8]; -#define MAX_SMPL_WIDTH_20 0x0 -#define MAX_SMPL_WIDTH_24 0x1 -#define SMPL_WIDTH_16BITS 0x1 -#define SMPL_WIDTH_24BITS 0x5 -#define CHANNEL_ALLOCATION 0x1F -#define VALID_DIP_WORDS 3 -#define LAYOUT0 0 -#define LAYOUT1 1 -#define SWAP_LFE_CENTER 0x00fac4c8 -#define AUD_CONFIG_CH_MASK 0x70 + /* derived values, just for convenience */ + int channels; + int spk_mask; +}; + +struct channel_map_table { + unsigned char map; /* ALSA API channel map position */ + unsigned char cea_slot; /* CEA slot value */ + int spk_mask; /* speaker position bit mask */ +}; struct pcm_stream_info { struct snd_pcm_substream *substream; diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index 48cab1b84c7b..97bbca19333a 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -23,7 +23,6 @@ #ifndef __INTEL_HDMI_LPE_AUDIO_H #define __INTEL_HDMI_LPE_AUDIO_H -#define HAD_MAX_DEVICES 1 #define HAD_MIN_CHANNEL 2 #define HAD_MAX_CHANNEL 8 #define HAD_NUM_OF_RING_BUFS 4 @@ -55,9 +54,7 @@ #define DIS_SAMPLE_RATE_74_25 74250 #define DIS_SAMPLE_RATE_148_5 148500 #define HAD_REG_WIDTH 0x08 -#define HAD_MAX_HW_BUFS 0x04 #define HAD_MAX_DIP_WORDS 16 -#define INTEL_HAD "HdmiLpeAudio" /* DP Link Rates */ #define DP_2_7_GHZ 270000 @@ -112,72 +109,34 @@ enum hdmi_ctrl_reg_offset { AUD_HDMIW_INFOFR = 0x68, /* v2 */ }; -/* - * CEA speaker placement: - * - * FL FLC FC FRC FR - * - * LFE - * - * RL RLC RC RRC RR - * - * The Left/Right Surround channel _notions_ LS/RS in SMPTE 320M - * corresponds to CEA RL/RR; The SMPTE channel _assignment_ C/LFE is - * swapped to CEA LFE/FC. - */ -enum cea_speaker_placement { - FL = (1 << 0), /* Front Left */ - FC = (1 << 1), /* Front Center */ - FR = (1 << 2), /* Front Right */ - FLC = (1 << 3), /* Front Left Center */ - FRC = (1 << 4), /* Front Right Center */ - RL = (1 << 5), /* Rear Left */ - RC = (1 << 6), /* Rear Center */ - RR = (1 << 7), /* Rear Right */ - RLC = (1 << 8), /* Rear Left Center */ - RRC = (1 << 9), /* Rear Right Center */ - LFE = (1 << 10), /* Low Frequency Effect */ -}; - -struct cea_channel_speaker_allocation { - int ca_index; - int speakers[8]; - - /* derived values, just for convenience */ - int channels; - int spk_mask; -}; - -struct channel_map_table { - unsigned char map; /* ALSA API channel map position */ - unsigned char cea_slot; /* CEA slot value */ - int spk_mask; /* speaker position bit mask */ -}; - /* Audio configuration */ union aud_cfg { struct { u32 aud_en:1; - u32 layout:1; + u32 layout:1; /* LAYOUT[01], see below */ u32 fmt:2; u32 num_ch:3; u32 set:1; u32 flat:1; u32 val_bit:1; u32 user_bit:1; - u32 underrun:1; - u32 packet_mode:1; - u32 left_align:1; - u32 bogus_sample:1; - u32 dp_modei:1; + u32 underrun:1; /* 0: send null packets, + * 1: send silence stream + */ + u32 packet_mode:1; /* 0: 32bit container, 1: 16bit */ + u32 left_align:1; /* 0: MSB bits 0-23, 1: bits 8-31 */ + u32 bogus_sample:1; /* bogus sample for odd channels */ + u32 dp_modei:1; /* 0: HDMI, 1: DP */ u32 rsvd:16; } regx; u32 regval; }; -#define AUD_CONFIG_BLOCK_BIT (1 << 7) #define AUD_CONFIG_VALID_BIT (1 << 9) #define AUD_CONFIG_DP_MODE (1 << 15) +#define AUD_CONFIG_CH_MASK 0x70 +#define LAYOUT0 0 /* interleaved stereo */ +#define LAYOUT1 1 /* for channels > 2 */ /* Audio Channel Status 0 Attributes */ union aud_ch_status_0 { @@ -190,13 +149,22 @@ union aud_ch_status_0 { u32 ctg_code:8; u32 src_num:4; u32 ch_num:4; - u32 samp_freq:4; + u32 samp_freq:4; /* CH_STATUS_MAP_XXX */ u32 clk_acc:2; u32 rsvd:2; } regx; u32 regval; }; +/* samp_freq values - Sampling rate as per IEC60958 Ver 3 */ +#define CH_STATUS_MAP_32KHZ 0x3 +#define CH_STATUS_MAP_44KHZ 0x0 +#define CH_STATUS_MAP_48KHZ 0x2 +#define CH_STATUS_MAP_88KHZ 0x8 +#define CH_STATUS_MAP_96KHZ 0xA +#define CH_STATUS_MAP_176KHZ 0xC +#define CH_STATUS_MAP_192KHZ 0xE + /* Audio Channel Status 1 Attributes */ union aud_ch_status_1 { struct { @@ -207,6 +175,11 @@ union aud_ch_status_1 { u32 regval; }; +#define MAX_SMPL_WIDTH_20 0x0 +#define MAX_SMPL_WIDTH_24 0x1 +#define SMPL_WIDTH_16BITS 0x1 +#define SMPL_WIDTH_24BITS 0x5 + /* CTS register */ union aud_hdmi_cts { struct { @@ -239,6 +212,9 @@ union aud_buf_config { u32 regval; }; +#define FIFO_THRESHOLD 0xFE +#define DMA_FIFO_THRESHOLD 0x7 + /* Audio Sample Swapping offset */ union aud_buf_ch_swap { struct { @@ -255,6 +231,8 @@ union aud_buf_ch_swap { u32 regval; }; +#define SWAP_LFE_CENTER 0x00fac4c8 /* octal 76543210 */ + /* Address for Audio Buffer */ union aud_buf_addr { struct { @@ -306,6 +284,9 @@ union aud_info_frame1 { u32 regval; }; +#define HDMI_INFO_FRAME_WORD1 0x000a0184 +#define DP_INFO_FRAME_WORD1 0x00441b84 + /* DIP frame 2 */ union aud_info_frame2 { struct { @@ -333,13 +314,15 @@ union aud_info_frame3 { u32 regval; }; +#define VALID_DIP_WORDS 3 + /* AUD_HDMI_STATUS bits */ #define HDMI_AUDIO_UNDERRUN (1U << 31) #define HDMI_AUDIO_BUFFER_DONE (1U << 29) /* AUD_HDMI_STATUS register mask */ -#define AUD_CONFIG_MASK_UNDERRUN 0xC0000000 -#define AUD_CONFIG_MASK_SRDBG 0x00000002 -#define AUD_CONFIG_MASK_FUNCRST 0x00000001 +#define AUD_HDMI_STATUS_MASK_UNDERRUN 0xC0000000 +#define AUD_HDMI_STATUS_MASK_SRDBG 0x00000002 +#define AUD_HDMI_STATUSG_MASK_FUNCRST 0x00000001 #endif -- cgit v1.2.3 From 40ce4b5d70b0c7e70c3e831e56d2586b57b54915 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 7 Feb 2017 16:17:06 +0100 Subject: ALSA: x86: Cache AUD_CONFIG register value At enabling the audio, we modify AUD_CONFIG register bit 0. So far, it does read-modify-write procedure with a special hack for the channel bits due to the silicon bug. But we can optimize it by remembering the AUD_CONFIG register value privately. This simplifies the things a lot. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 39 ++++++++++++--------------------------- sound/x86/intel_hdmi_audio.h | 1 + 2 files changed, 13 insertions(+), 27 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 34750c54663a..15147fec1a7e 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -212,30 +212,13 @@ static void had_write_register(struct snd_intelhad *ctx, u32 reg, u32 val) * bad audio. The fix is to always write the AUD_CONFIG[6:4] with * appropriate value when doing read-modify of AUD_CONFIG register. */ -static void had_enable_audio(struct snd_pcm_substream *substream, - struct snd_intelhad *intelhaddata, +static void had_enable_audio(struct snd_intelhad *intelhaddata, bool enable) { - union aud_cfg cfg_val = {.regval = 0}; - u8 channels; - u32 mask, val; - - /* - * If substream is NULL, there is no active stream. - * In this case just set channels to 2 - */ - channels = substream ? substream->runtime->channels : 2; - dev_dbg(intelhaddata->dev, "enable %d, ch=%d\n", enable, channels); - - cfg_val.regx.num_ch = channels - 2; - if (enable) - cfg_val.regx.aud_en = 1; - mask = AUD_CONFIG_CH_MASK | 1; - - had_read_register(intelhaddata, AUD_CONFIG, &val); - val &= ~mask; - val |= cfg_val.regval; - had_write_register(intelhaddata, AUD_CONFIG, val); + /* update the cached value */ + intelhaddata->aud_config.regx.aud_en = enable; + had_write_register(intelhaddata, AUD_CONFIG, + intelhaddata->aud_config.regval); } /* forcibly ACKs to both BUFFER_DONE and BUFFER_UNDERRUN interrupts */ @@ -360,6 +343,7 @@ static int had_init_audio_ctrl(struct snd_pcm_substream *substream, } had_write_register(intelhaddata, AUD_CONFIG, cfg_val.regval); + intelhaddata->aud_config = cfg_val; return 0; } @@ -1004,6 +988,7 @@ static void had_process_buffer_underrun(struct snd_intelhad *intelhaddata) /* Handle Underrun interrupt within Audio Unit */ had_write_register(intelhaddata, AUD_CONFIG, 0); + intelhaddata->aud_config.regval = 0; /* Reset buffer pointers */ had_reset_audio(intelhaddata); @@ -1169,7 +1154,7 @@ static int had_pcm_trigger(struct snd_pcm_substream *substream, int cmd) /* Enable Audio */ had_ack_irqs(intelhaddata); /* FIXME: do we need this? */ - had_enable_audio(substream, intelhaddata, true); + had_enable_audio(intelhaddata, true); break; case SNDRV_PCM_TRIGGER_STOP: @@ -1182,7 +1167,7 @@ static int had_pcm_trigger(struct snd_pcm_substream *substream, int cmd) intelhaddata->stream_info.running = false; spin_unlock(&intelhaddata->had_spinlock); /* Disable Audio */ - had_enable_audio(substream, intelhaddata, false); + had_enable_audio(intelhaddata, false); /* Reset buffer pointers */ had_reset_audio(intelhaddata); break; @@ -1315,7 +1300,7 @@ static int had_process_mode_change(struct snd_intelhad *intelhaddata) return 0; /* Disable Audio */ - had_enable_audio(substream, intelhaddata, false); + had_enable_audio(intelhaddata, false); /* Update CTS value */ disp_samp_freq = intelhaddata->tmds_clock_speed; @@ -1334,7 +1319,7 @@ static int had_process_mode_change(struct snd_intelhad *intelhaddata) n_param, intelhaddata); /* Enable Audio */ - had_enable_audio(substream, intelhaddata, true); + had_enable_audio(intelhaddata, true); out: had_substream_put(intelhaddata); @@ -1389,7 +1374,7 @@ static void had_process_hot_unplug(struct snd_intelhad *intelhaddata) } /* Disable Audio */ - had_enable_audio(substream, intelhaddata, false); + had_enable_audio(intelhaddata, false); intelhaddata->connected = false; dev_dbg(intelhaddata->dev, diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index fe8d99cb839f..a96728a4e7bc 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -127,6 +127,7 @@ struct snd_intelhad { int irq; void __iomem *mmio_start; unsigned int had_config_offset; + union aud_cfg aud_config; /* AUD_CONFIG reg value cache */ struct work_struct hdmi_audio_wq; struct mutex mutex; /* for protecting chmap and eld */ }; -- cgit v1.2.3 From a9ebdd0ef261fb9838af2821c09d165f6a14789b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 2 Feb 2017 21:33:54 +0100 Subject: ALSA: x86: Don't pass SNDRV_PCM_INFO_BATCH flag The PCM engine on LPE audio isn't like a batch-style process any longer, but rather it deals with the standard ring buffer. Remove the BATCH info flag so that PA can handle the buffer in timer-sched mode. Similarly, the DOUBLE flag is also superfluous. Drop both bits. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 15147fec1a7e..73a662d20201 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -132,10 +132,8 @@ static const struct channel_map_table map_tables[] = { /* hardware capability structure */ static const struct snd_pcm_hardware had_pcm_hardware = { .info = (SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_DOUBLE | - SNDRV_PCM_INFO_MMAP| - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_BATCH), + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID), .formats = SNDRV_PCM_FMTBIT_S24, .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | -- cgit v1.2.3 From 8d48c0163d1ab0f56a18ebe9898a34ebcfdfaa1a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 7 Feb 2017 08:05:46 +0100 Subject: ALSA: x86: Allow single period PCM operation This is an implementation of PCM streaming with only 1 period. Since the hardware requires the refresh of BDs after each BD processing finishes, we'd need at least two BDs. The trick is that both BDs point to the same content: the address of the PCM buffer head, and the whole buffer size. Then it loops over to the whole buffer again after it finished once. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 14 ++++++++++++-- sound/x86/intel_hdmi_lpe_audio.h | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 73a662d20201..d2136498defe 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -822,6 +822,11 @@ static int had_prog_n(u32 aud_samp_freq, u32 *n_param, * * For nperiods < 4, the remaining BDs out of 4 are marked as invalid, so that * the hardware skips those BDs in the loop. + * + * An exceptional setup is the case with nperiods=1. Since we have to update + * BDs after finishing one BD processing, we'd need at least two BDs, where + * both BDs point to the same content, the same address, the same size of the + * whole PCM buffer. */ #define AUD_BUF_ADDR(x) (AUD_BUF_A_ADDR + (x) * HAD_REG_WIDTH) @@ -864,6 +869,8 @@ static void had_init_ringbuf(struct snd_pcm_substream *substream, num_periods = runtime->periods; intelhaddata->num_bds = min(num_periods, HAD_NUM_OF_RING_BUFS); + /* set the minimum 2 BDs for num_periods=1 */ + intelhaddata->num_bds = max(intelhaddata->num_bds, 2U); intelhaddata->period_bytes = frames_to_bytes(runtime, runtime->period_size); WARN_ON(intelhaddata->period_bytes & 0x3f); @@ -873,7 +880,7 @@ static void had_init_ringbuf(struct snd_pcm_substream *substream, intelhaddata->pcmbuf_filled = 0; for (i = 0; i < HAD_NUM_OF_RING_BUFS; i++) { - if (i < num_periods) + if (i < intelhaddata->num_bds) had_prog_bd(substream, intelhaddata); else /* invalidate the rest */ had_invalidate_bd(intelhaddata, i); @@ -1255,7 +1262,10 @@ static snd_pcm_uframes_t had_pcm_pointer(struct snd_pcm_substream *substream) len = had_process_ringbuf(substream, intelhaddata); if (len < 0) return SNDRV_PCM_POS_XRUN; - return bytes_to_frames(substream->runtime, len); + len = bytes_to_frames(substream->runtime, len); + /* wrapping may happen when periods=1 */ + len %= substream->runtime->buffer_size; + return len; } /* diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h index 97bbca19333a..477e5153307c 100644 --- a/sound/x86/intel_hdmi_lpe_audio.h +++ b/sound/x86/intel_hdmi_lpe_audio.h @@ -31,7 +31,7 @@ #define HAD_MAX_BUFFER ((1024 * 1024 - 1) & ~0x3f) #define HAD_DEFAULT_BUFFER (600 * 1024) /* default prealloc size */ #define HAD_MAX_PERIODS 256 /* arbitrary, but should suffice */ -#define HAD_MIN_PERIODS 2 +#define HAD_MIN_PERIODS 1 #define HAD_MAX_PERIOD_BYTES ((HAD_MAX_BUFFER / HAD_MIN_PERIODS) & ~0x3f) #define HAD_MIN_PERIOD_BYTES 1024 /* might be smaller */ #define HAD_FIFO_SIZE 0 /* fifo not being used */ -- cgit v1.2.3 From e8de9859e4e834a74da824e13070aa992c32de10 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 7 Feb 2017 08:09:12 +0100 Subject: ALSA: x86: Allow no-period-wakeup setup In the current implementation, the driver may update the BDs even at PCM pointer callback. This allows us to skip the period interrupt effectively. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index d2136498defe..80b1ab9b1c57 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -133,7 +133,8 @@ static const struct channel_map_table map_tables[] = { static const struct snd_pcm_hardware had_pcm_hardware = { .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID), + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP), .formats = SNDRV_PCM_FMTBIT_S24, .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | @@ -840,7 +841,9 @@ static void had_prog_bd(struct snd_pcm_substream *substream, int ofs = intelhaddata->pcmbuf_filled * intelhaddata->period_bytes; u32 addr = substream->runtime->dma_addr + ofs; - addr |= AUD_BUF_VALID | AUD_BUF_INTR_EN; + addr |= AUD_BUF_VALID; + if (!substream->runtime->no_period_wakeup) + addr |= AUD_BUF_INTR_EN; had_write_register(intelhaddata, AUD_BUF_ADDR(idx), addr); had_write_register(intelhaddata, AUD_BUF_LEN(idx), intelhaddata->period_bytes); -- cgit v1.2.3 From 85bd8748ca23a25f6dc56154d9a61d87ae07a807 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 7 Feb 2017 13:33:17 +0100 Subject: ALSA: x86: Support S32 format The hardware has the support for the left-aligned 24bit format in 32bit packet. This corresponds to S32 format in ALSA. We need to set the msbits restriction as well to inform user-space that only MSB 24bit are available. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 80b1ab9b1c57..e8f8be2f590b 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -135,7 +135,8 @@ static const struct snd_pcm_hardware had_pcm_hardware = { SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP), - .formats = SNDRV_PCM_FMTBIT_S24, + .formats = (SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE), .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | @@ -249,7 +250,6 @@ static int had_prog_status_reg(struct snd_pcm_substream *substream, union aud_cfg cfg_val = {.regval = 0}; union aud_ch_status_0 ch_stat0 = {.regval = 0}; union aud_ch_status_1 ch_stat1 = {.regval = 0}; - int format; ch_stat0.regx.lpcm_id = (intelhaddata->aes_bits & IEC958_AES0_NONAUDIO) >> 1; @@ -289,17 +289,20 @@ static int had_prog_status_reg(struct snd_pcm_substream *substream, had_write_register(intelhaddata, AUD_CH_STATUS_0, ch_stat0.regval); - format = substream->runtime->format; - - if (format == SNDRV_PCM_FORMAT_S16_LE) { + switch (substream->runtime->format) { +#if 0 /* FIXME: not supported yet */ + case SNDRV_PCM_FORMAT_S16_LE: ch_stat1.regx.max_wrd_len = MAX_SMPL_WIDTH_20; ch_stat1.regx.wrd_len = SMPL_WIDTH_16BITS; - } else if (format == SNDRV_PCM_FORMAT_S24_LE) { + break; +#endif + case SNDRV_PCM_FORMAT_S24_LE: + case SNDRV_PCM_FORMAT_S32_LE: ch_stat1.regx.max_wrd_len = MAX_SMPL_WIDTH_24; ch_stat1.regx.wrd_len = SMPL_WIDTH_24BITS; - } else { - ch_stat1.regx.max_wrd_len = 0; - ch_stat1.regx.wrd_len = 0; + break; + default: + return -EINVAL; } had_write_register(intelhaddata, @@ -333,6 +336,9 @@ static int had_init_audio_ctrl(struct snd_pcm_substream *substream, else cfg_val.regx.layout = LAYOUT1; + if (substream->runtime->format == SNDRV_PCM_FORMAT_S32_LE) + cfg_val.regx.left_align = 1; + cfg_val.regx.val_bit = 1; /* fix up the DP bits */ @@ -1050,6 +1056,10 @@ static int had_pcm_open(struct snd_pcm_substream *substream) if (retval < 0) goto error; + retval = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); + if (retval < 0) + goto error; + /* expose PCM substream */ spin_lock_irq(&intelhaddata->had_spinlock); intelhaddata->stream_info.substream = substream; -- cgit v1.2.3 From 3fe2cf7eb21ada0a9683b26c1ae309e7f5e90131 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 7 Feb 2017 13:53:42 +0100 Subject: ALSA: x86: Support S16 format Now we support S16 PCM format in addition. For this, we need to set packet_mode=1 in AUD_CONFIG register. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index e8f8be2f590b..c0a080e5d1f4 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -135,7 +135,8 @@ static const struct snd_pcm_hardware had_pcm_hardware = { SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP), - .formats = (SNDRV_PCM_FMTBIT_S24_LE | + .formats = (SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE), .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | @@ -290,12 +291,10 @@ static int had_prog_status_reg(struct snd_pcm_substream *substream, AUD_CH_STATUS_0, ch_stat0.regval); switch (substream->runtime->format) { -#if 0 /* FIXME: not supported yet */ case SNDRV_PCM_FORMAT_S16_LE: ch_stat1.regx.max_wrd_len = MAX_SMPL_WIDTH_20; ch_stat1.regx.wrd_len = SMPL_WIDTH_16BITS; break; -#endif case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_S32_LE: ch_stat1.regx.max_wrd_len = MAX_SMPL_WIDTH_24; @@ -336,6 +335,9 @@ static int had_init_audio_ctrl(struct snd_pcm_substream *substream, else cfg_val.regx.layout = LAYOUT1; + if (substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE) + cfg_val.regx.packet_mode = 1; + if (substream->runtime->format == SNDRV_PCM_FORMAT_S32_LE) cfg_val.regx.left_align = 1; -- cgit v1.2.3 From e2acecf2c88370f9d7252e7a05cd7b6d43aed720 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 11 Feb 2017 08:21:56 +0100 Subject: ALSA: x86: Handle reset at prepare callback Currently the driver handles some reset procedure at the trigger STOP and the underrun functions, where both are executed in the interrupt context. Especially the underrun function has a sync-loop to clear the UNDERRUN status bit, and this is supposed to be one of plausible causes of GPU hangup. Since the job to be done in the interrupt handler should be minimum, we move the reset function out of trigger and underrun, and push it into the prepare (and hw_free) callbacks instead. Here a new flag, need_reset, is introduced to indicate the requirement of the reset procedure. This is for avoiding the multiple resets when PCM prepare is called sequentially. Also in the UNDERRUN bit-clear sync loop, take a longer pause to be in the safer side. Taking a longer delay is no longer a problem now because we're running in the normal context. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 39 +++++++++++++++++++++++++-------------- sound/x86/intel_hdmi_audio.h | 1 + 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index c0a080e5d1f4..015d57cd9725 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -976,8 +977,6 @@ static void had_process_buffer_done(struct snd_intelhad *intelhaddata) had_substream_put(intelhaddata); } -#define MAX_CNT 0xFF - /* * The interrupt status 'sticky' bits might not be cleared by * setting '1' to that bit once... @@ -987,31 +986,37 @@ static void wait_clear_underrun_bit(struct snd_intelhad *intelhaddata) int i; u32 val; - for (i = 0; i < MAX_CNT; i++) { + for (i = 0; i < 100; i++) { /* clear bit30, 31 AUD_HDMI_STATUS */ had_read_register(intelhaddata, AUD_HDMI_STATUS, &val); if (!(val & AUD_HDMI_STATUS_MASK_UNDERRUN)) return; + udelay(100); + cond_resched(); had_write_register(intelhaddata, AUD_HDMI_STATUS, val); } dev_err(intelhaddata->dev, "Unable to clear UNDERRUN bits\n"); } -/* called from irq handler */ -static void had_process_buffer_underrun(struct snd_intelhad *intelhaddata) +/* Perform some reset procedure but only when need_reset is set; + * this is called from prepare or hw_free callbacks once after trigger STOP + * or underrun has been processed in order to settle down the h/w state. + */ +static void had_do_reset(struct snd_intelhad *intelhaddata) { - struct snd_pcm_substream *substream; + if (!intelhaddata->need_reset) + return; - /* Handle Underrun interrupt within Audio Unit */ - had_write_register(intelhaddata, AUD_CONFIG, 0); - intelhaddata->aud_config.regval = 0; /* Reset buffer pointers */ had_reset_audio(intelhaddata); - wait_clear_underrun_bit(intelhaddata); + intelhaddata->need_reset = false; +} - if (!intelhaddata->connected) - return; /* disconnected? - bail out */ +/* called from irq handler */ +static void had_process_buffer_underrun(struct snd_intelhad *intelhaddata) +{ + struct snd_pcm_substream *substream; /* Report UNDERRUN error to above layers */ substream = had_substream_get(intelhaddata); @@ -1019,6 +1024,7 @@ static void had_process_buffer_underrun(struct snd_intelhad *intelhaddata) snd_pcm_stop_xrun(substream); had_substream_put(intelhaddata); } + intelhaddata->need_reset = true; } /* @@ -1134,9 +1140,13 @@ static int had_pcm_hw_params(struct snd_pcm_substream *substream, */ static int had_pcm_hw_free(struct snd_pcm_substream *substream) { + struct snd_intelhad *intelhaddata; unsigned long addr; u32 pages; + intelhaddata = snd_pcm_substream_chip(substream); + had_do_reset(intelhaddata); + /* mark back the pages as cached/writeback region before the free */ if (substream->runtime->dma_area != NULL) { addr = (unsigned long) substream->runtime->dma_area; @@ -1188,8 +1198,7 @@ static int had_pcm_trigger(struct snd_pcm_substream *substream, int cmd) spin_unlock(&intelhaddata->had_spinlock); /* Disable Audio */ had_enable_audio(intelhaddata, false); - /* Reset buffer pointers */ - had_reset_audio(intelhaddata); + intelhaddata->need_reset = true; break; default: @@ -1227,6 +1236,8 @@ static int had_pcm_prepare(struct snd_pcm_substream *substream) dev_dbg(intelhaddata->dev, "rate=%d\n", runtime->rate); dev_dbg(intelhaddata->dev, "channels=%d\n", runtime->channels); + had_do_reset(intelhaddata); + /* Get N value in KHz */ disp_samp_freq = intelhaddata->tmds_clock_speed; diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index a96728a4e7bc..8b9e184fef44 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -130,6 +130,7 @@ struct snd_intelhad { union aud_cfg aud_config; /* AUD_CONFIG reg value cache */ struct work_struct hdmi_audio_wq; struct mutex mutex; /* for protecting chmap and eld */ + bool need_reset; }; #endif /* _INTEL_HDMI_AUDIO_ */ -- cgit v1.2.3 From df42cb499eb1869bfb535f6c6b5ea1406496baf4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 12 Feb 2017 11:35:44 +0100 Subject: ALSA: x86: Drop unused stream.running field The pcm_stream_info.running field is only set in the PCM trigger callback but never referred, thus it can be safely removed. Also, properly cover the spinlock in both the trigger START and STOP to protect had_enable_audio() calls. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 11 ++--------- sound/x86/intel_hdmi_audio.h | 1 - 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 015d57cd9725..9889cdf3ccf4 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1168,6 +1168,7 @@ static int had_pcm_trigger(struct snd_pcm_substream *substream, int cmd) intelhaddata = snd_pcm_substream_chip(substream); + spin_lock(&intelhaddata->had_spinlock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: @@ -1180,8 +1181,6 @@ static int had_pcm_trigger(struct snd_pcm_substream *substream, int cmd) break; } - intelhaddata->stream_info.running = true; - /* Enable Audio */ had_ack_irqs(intelhaddata); /* FIXME: do we need this? */ had_enable_audio(intelhaddata, true); @@ -1189,13 +1188,6 @@ static int had_pcm_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - case SNDRV_PCM_TRIGGER_SUSPEND: - spin_lock(&intelhaddata->had_spinlock); - - /* Stop reporting BUFFER_DONE/UNDERRUN to above layers */ - - intelhaddata->stream_info.running = false; - spin_unlock(&intelhaddata->had_spinlock); /* Disable Audio */ had_enable_audio(intelhaddata, false); intelhaddata->need_reset = true; @@ -1204,6 +1196,7 @@ static int had_pcm_trigger(struct snd_pcm_substream *substream, int cmd) default: retval = -EINVAL; } + spin_unlock(&intelhaddata->had_spinlock); return retval; } diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index 8b9e184fef44..d6ba90fd011d 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -83,7 +83,6 @@ struct channel_map_table { struct pcm_stream_info { struct snd_pcm_substream *substream; int substream_refcount; - bool running; }; /* -- cgit v1.2.3 From 078502b5842a52f6faf7edf178fb2ad22fa16b96 Mon Sep 17 00:00:00 2001 From: Darren Stevens Date: Mon, 13 Feb 2017 21:11:03 +0000 Subject: ALSA: hda/patch_sigmatel: Add AmigaOne X1000 pinconfigs The AmigaOne X1000 has a Sigmatel STAC92HD700 attached to the HD Audio on an ATI SB600. Add the required settings to enable sound. Signed-off-by: Darren Stevens Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 37b70f8e878f..faa3d38bac0b 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -166,6 +166,7 @@ enum { STAC_D965_VERBS, STAC_DELL_3ST, STAC_DELL_BIOS, + STAC_NEMO_DEFAULT, STAC_DELL_BIOS_AMIC, STAC_DELL_BIOS_SPDIF, STAC_927X_DELL_DMIC, @@ -1360,6 +1361,27 @@ static const struct hda_pintbl oqo9200_pin_configs[] = { {} }; +/* + * STAC 92HD700 + * 18881000 Amigaone X1000 + */ +static const struct hda_pintbl nemo_pin_configs[] = { + { 0x0a, 0x02214020 }, /* Front panel HP socket */ + { 0x0b, 0x02a19080 }, /* Front Mic */ + { 0x0c, 0x0181304e }, /* Line in */ + { 0x0d, 0x01014010 }, /* Line out */ + { 0x0e, 0x01a19040 }, /* Rear Mic */ + { 0x0f, 0x01011012 }, /* Rear speakers */ + { 0x10, 0x01016011 }, /* Center speaker */ + { 0x11, 0x01012014 }, /* Side speakers (7.1) */ + { 0x12, 0x103301f0 }, /* Motherboard CD line in connector */ + { 0x13, 0x411111f0 }, /* Unused */ + { 0x14, 0x411111f0 }, /* Unused */ + { 0x21, 0x01442170 }, /* S/PDIF line out */ + { 0x22, 0x411111f0 }, /* Unused */ + { 0x23, 0x411111f0 }, /* Unused */ + {} +}; static void stac9200_fixup_panasonic(struct hda_codec *codec, const struct hda_fixup *fix, int action) @@ -3883,6 +3905,10 @@ static const struct hda_fixup stac927x_fixups[] = { .type = HDA_FIXUP_PINS, .v.pins = d965_5st_no_fp_pin_configs, }, + [STAC_NEMO_DEFAULT] = { + .type = HDA_FIXUP_PINS, + .v.pins = nemo_pin_configs, + }, [STAC_DELL_3ST] = { .type = HDA_FIXUP_PINS, .v.pins = dell_3st_pin_configs, @@ -3939,6 +3965,7 @@ static const struct hda_model_fixup stac927x_models[] = { { .id = STAC_D965_5ST_NO_FP, .name = "5stack-no-fp" }, { .id = STAC_DELL_3ST, .name = "dell-3stack" }, { .id = STAC_DELL_BIOS, .name = "dell-bios" }, + { .id = STAC_NEMO_DEFAULT, .name = "nemo-default" }, { .id = STAC_DELL_BIOS_AMIC, .name = "dell-bios-amic" }, { .id = STAC_927X_VOLKNOB, .name = "volknob" }, {} @@ -3977,6 +4004,8 @@ static const struct snd_pci_quirk stac927x_fixup_tbl[] = { "Intel D965", STAC_D965_5ST), SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2500, "Intel D965", STAC_D965_5ST), + /* Nemo */ + SND_PCI_QUIRK(0x1888, 0x1000, "AmigaOne X1000", STAC_NEMO_DEFAULT), /* volume-knob fixes */ SND_PCI_QUIRK_VENDOR(0x10cf, "FSC", STAC_927X_VOLKNOB), {} /* terminator */ @@ -5036,6 +5065,7 @@ static const struct hda_device_id snd_hda_id_sigmatel[] = { HDA_CODEC_ENTRY(0x83847683, "STAC9221D A2", patch_stac922x), HDA_CODEC_ENTRY(0x83847618, "STAC9227", patch_stac927x), HDA_CODEC_ENTRY(0x83847619, "STAC9227", patch_stac927x), + HDA_CODEC_ENTRY(0x83847638, "STAC92HD700", patch_stac927x), HDA_CODEC_ENTRY(0x83847616, "STAC9228", patch_stac927x), HDA_CODEC_ENTRY(0x83847617, "STAC9228", patch_stac927x), HDA_CODEC_ENTRY(0x83847614, "STAC9229", patch_stac927x), -- cgit v1.2.3 From e7480b34ad1ab84a63540b2c884cb92c0764ab74 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 15 Feb 2017 17:09:42 +0100 Subject: ALSA: hda - fix Lewisburg audio issue Like for Sunrise Point, the total stream number of Lewisburg's input and output stream exceeds 15 (GCAP is 0x9701), which will cause some streams do not work because of the overflow on SDxCTL.STRM field if using the legacy stream tag allocation method. Fixes: 5cf92c8b3dc5 ("ALSA: hda - Add Intel Lewisburg device IDs Audio") Signed-off-by: Jaroslav Kysela Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index faf99cc71277..7d77bb504a16 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2214,9 +2214,9 @@ static const struct pci_device_id azx_ids[] = { .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, /* Lewisburg */ { PCI_DEVICE(0x8086, 0xa1f0), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE }, { PCI_DEVICE(0x8086, 0xa270), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE }, /* Lynx Point-LP */ { PCI_DEVICE(0x8086, 0x9c20), .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, -- cgit v1.2.3 From df56c3dbae0e6df0edcca2e778810a3d8c994f4e Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 15 Feb 2017 17:09:43 +0100 Subject: ALSA: hda - add sanity check to force the separate stream tags It seems that newer Intel chipsets have more than 15 I/O streams (total). This patch forces the separate stream tags, when this hardware is detected to avoid SDxCTL.STRM field overflow and an unexpected behaviour. Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 7d77bb504a16..16108f0eb688 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1778,6 +1778,14 @@ static int azx_first_init(struct azx *chip) chip->playback_index_offset = chip->capture_streams; chip->num_streams = chip->playback_streams + chip->capture_streams; + /* sanity check for the SDxCTL.STRM field overflow */ + if (chip->num_streams > 15 && + (chip->driver_caps & AZX_DCAPS_SEPARATE_STREAM_TAG) == 0) { + dev_warn(chip->card->dev, "number of I/O streams is %d, " + "forcing separate stream tags", chip->num_streams); + chip->driver_caps |= AZX_DCAPS_SEPARATE_STREAM_TAG; + } + /* initialize streams */ err = azx_init_streams(chip); if (err < 0) -- cgit v1.2.3 From 9f1bc2c4c58fcb2d86e0e26437dc8f3a18ac3276 Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Thu, 16 Feb 2017 15:26:54 +0800 Subject: ALSA: hda/realtek - Cannot adjust speaker's volume on a Dell AIO The issue is the same as "dd9aa335c880 ALSA: hda/realtek - Can't adjust speaker's volume on a Dell AIO", the output requires to connect to a node with Amp-out capability. Applying the same fixup "ALC298_FIXUP_SPK_VOLUME" can fix the issue. Signed-off-by: Kai-Heng Feng Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 89f0b01de30d..73a00460b5c1 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6097,6 +6097,12 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE, ALC298_STANDARD_PINS, {0x17, 0x90170150}), + SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_SPK_VOLUME, + {0x12, 0xb7a60140}, + {0x13, 0xb7a60150}, + {0x17, 0x90170110}, + {0x1a, 0x03011020}, + {0x21, 0x03211030}), {} }; -- cgit v1.2.3 From b9bacf275ca2eeb8e8fa85c1705d07e2475f1aaa Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 14 Feb 2017 12:29:38 +0100 Subject: ALSA: x86: Implement jack control This patch implements a jack interface for notifying HDMI/DP connection. PA listens to this, so it can handle the monitor connection more gracefully. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 23 +++++++++++++++++++++++ sound/x86/intel_hdmi_audio.h | 1 + 2 files changed, 24 insertions(+) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 9889cdf3ccf4..a30ca03e49ae 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include "intel_hdmi_audio.h" @@ -1382,6 +1383,8 @@ static void had_process_hot_plug(struct snd_intelhad *intelhaddata) } had_build_channel_allocation_map(intelhaddata); + + snd_jack_report(intelhaddata->jack, SND_JACK_AVOUT); } /* process hot unplug, called from wq with mutex locked */ @@ -1414,6 +1417,7 @@ static void had_process_hot_unplug(struct snd_intelhad *intelhaddata) snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); out: + snd_jack_report(intelhaddata->jack, 0); if (substream) had_substream_put(intelhaddata); kfree(intelhaddata->chmap->chmap); @@ -1608,6 +1612,21 @@ static void had_audio_wq(struct work_struct *work) pm_runtime_put(ctx->dev); } +/* + * Jack interface + */ +static int had_create_jack(struct snd_intelhad *ctx) +{ + int err; + + err = snd_jack_new(ctx->card, "HDMI/DP", SND_JACK_AVOUT, &ctx->jack, + true, false); + if (err < 0) + return err; + ctx->jack->private_data = ctx; + return 0; +} + /* * PM callbacks */ @@ -1780,6 +1799,10 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) if (ret < 0) goto err; + ret = had_create_jack(ctx); + if (ret < 0) + goto err; + ret = snd_card_register(card); if (ret) goto err; diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index d6ba90fd011d..2d3e389f76b3 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h @@ -130,6 +130,7 @@ struct snd_intelhad { struct work_struct hdmi_audio_wq; struct mutex mutex; /* for protecting chmap and eld */ bool need_reset; + struct snd_jack *jack; }; #endif /* _INTEL_HDMI_AUDIO_ */ -- cgit v1.2.3 From 5def90196b52d0bbec4f662448e25f2a4c06ddbc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 15 Feb 2017 21:36:38 +0100 Subject: ALSA: x86: Use snd_pcm_stop_xrun() for connection / disconnection paths This seems more friendly to user-space, as it's notified at least as an error, instead of forcibly moving the PCM state to SETUP out of sudden. Moreover, snd_pcm_stop() needs an extra PCM spinlock I forgot, while snd_pcm_stop_xrun() takes the spinlock by itself. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index a30ca03e49ae..a7343f2d2730 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1378,7 +1378,7 @@ static void had_process_hot_plug(struct snd_intelhad *intelhaddata) dev_dbg(intelhaddata->dev, "Force to stop the active stream by disconnection\n"); /* Set runtime->state to hw_params done */ - snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); + snd_pcm_stop_xrun(substream); had_substream_put(intelhaddata); } @@ -1414,7 +1414,7 @@ static void had_process_hot_unplug(struct snd_intelhad *intelhaddata) /* Report to above ALSA layer */ if (substream) - snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); + snd_pcm_stop_xrun(substream); out: snd_jack_report(intelhaddata->jack, 0); -- cgit v1.2.3 From 18353192b8f696a27420e2e8f39804c2075f26fb Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 15 Feb 2017 21:42:20 +0100 Subject: ALSA: x86: Fix memory leak in had_build_channel_allocation_map() The previously allocated chmap has to be released before setting the new one. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index a7343f2d2730..5f2445389716 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -444,11 +444,12 @@ static void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata) u8 eld_high, eld_high_mask = 0xF0; u8 high_msb; + kfree(intelhaddata->chmap->chmap); + intelhaddata->chmap->chmap = NULL; + chmap = kzalloc(sizeof(*chmap), GFP_KERNEL); - if (!chmap) { - intelhaddata->chmap->chmap = NULL; + if (!chmap) return; - } dev_dbg(intelhaddata->dev, "eld speaker = %x\n", intelhaddata->eld[DRM_ELD_SPEAKER]); @@ -493,10 +494,8 @@ static void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata) break; } } - if (i >= ARRAY_SIZE(channel_allocations)) { - intelhaddata->chmap->chmap = NULL; + if (i >= ARRAY_SIZE(channel_allocations)) kfree(chmap); - } } /* -- cgit v1.2.3 From a72ccfbad7fd6f604d8edd068119edb57e7984e1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 15 Feb 2017 21:45:06 +0100 Subject: ALSA: x86: Don't return an error from chmap ctl at disconnected It's not wise to return an error at info/get callback when disconnected, which happens at any time. The chmap ctl is supposed to fill zero for such a case, instead. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 5f2445389716..71f01204a590 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -504,11 +504,6 @@ static void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata) static int had_chmap_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); - struct snd_intelhad *intelhaddata = info->private_data; - - if (!intelhaddata->connected) - return -ENODEV; uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = HAD_MAX_CHANNEL; uinfo->value.integer.min = 0; @@ -524,13 +519,12 @@ static int had_chmap_ctl_get(struct snd_kcontrol *kcontrol, int i; const struct snd_pcm_chmap_elem *chmap; - if (!intelhaddata->connected) - return -ENODEV; - + memset(ucontrol->value.integer.value, 0, + sizeof(long) * HAD_MAX_CHANNEL); mutex_lock(&intelhaddata->mutex); if (!intelhaddata->chmap->chmap) { mutex_unlock(&intelhaddata->mutex); - return -ENODATA; + return 0; } chmap = intelhaddata->chmap->chmap; -- cgit v1.2.3 From 28ed125b9a07b9ad09ea680628a920427d079af6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 15 Feb 2017 22:02:10 +0100 Subject: ALSA: x86: Avoid register accesses during disconnection It seems that accessing registers during disconnection often leads to the GPU pipe error. The original driver had a similar check in the past, but it was lost through refactoring. Now put a connection check in the register access functions. One exception is the irq handler: it still needs to access the raw register even while disconnected, because it has to read and write to ACK the irq mask. Although the irq shouldn't be raised while disconnected (the stream should have been disabled), let's make it safer for now. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 71f01204a590..8d365718c692 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -190,14 +190,28 @@ static void had_substream_put(struct snd_intelhad *intelhaddata) } /* Register access functions */ +static u32 had_read_register_raw(struct snd_intelhad *ctx, u32 reg) +{ + return ioread32(ctx->mmio_start + ctx->had_config_offset + reg); +} + +static void had_write_register_raw(struct snd_intelhad *ctx, u32 reg, u32 val) +{ + iowrite32(val, ctx->mmio_start + ctx->had_config_offset + reg); +} + static void had_read_register(struct snd_intelhad *ctx, u32 reg, u32 *val) { - *val = ioread32(ctx->mmio_start + ctx->had_config_offset + reg); + if (!ctx->connected) + *val = 0; + else + *val = had_read_register_raw(ctx, reg); } static void had_write_register(struct snd_intelhad *ctx, u32 reg, u32 val) { - iowrite32(val, ctx->mmio_start + ctx->had_config_offset + reg); + if (ctx->connected) + had_write_register_raw(ctx, reg, val); } /* @@ -229,6 +243,8 @@ static void had_ack_irqs(struct snd_intelhad *ctx) { u32 status_reg; + if (!ctx->connected) + return; had_read_register(ctx, AUD_HDMI_STATUS, &status_reg); status_reg |= HDMI_AUDIO_BUFFER_DONE | HDMI_AUDIO_UNDERRUN; had_write_register(ctx, AUD_HDMI_STATUS, status_reg); @@ -998,7 +1014,7 @@ static void wait_clear_underrun_bit(struct snd_intelhad *intelhaddata) */ static void had_do_reset(struct snd_intelhad *intelhaddata) { - if (!intelhaddata->need_reset) + if (!intelhaddata->need_reset || !intelhaddata->connected) return; /* Reset buffer pointers */ @@ -1526,18 +1542,20 @@ static const struct snd_kcontrol_new had_controls[] = { static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id) { struct snd_intelhad *ctx = dev_id; - u32 audio_stat, audio_reg; + u32 audio_stat; - audio_reg = AUD_HDMI_STATUS; - had_read_register(ctx, audio_reg, &audio_stat); + /* use raw register access to ack IRQs even while disconnected */ + audio_stat = had_read_register_raw(ctx, AUD_HDMI_STATUS); if (audio_stat & HDMI_AUDIO_UNDERRUN) { - had_write_register(ctx, audio_reg, HDMI_AUDIO_UNDERRUN); + had_write_register_raw(ctx, AUD_HDMI_STATUS, + HDMI_AUDIO_UNDERRUN); had_process_buffer_underrun(ctx); } if (audio_stat & HDMI_AUDIO_BUFFER_DONE) { - had_write_register(ctx, audio_reg, HDMI_AUDIO_BUFFER_DONE); + had_write_register_raw(ctx, AUD_HDMI_STATUS, + HDMI_AUDIO_BUFFER_DONE); had_process_buffer_done(ctx); } -- cgit v1.2.3 From be9a2e933e301bec856d526516801e14247519c5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 15 Feb 2017 22:05:34 +0100 Subject: ALSA: x86: Stop the stream when buffer is processed after disconnection This shouldn't happen, but just to be sure... Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 8d365718c692..8d67031e8429 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -971,19 +971,22 @@ static void had_process_buffer_done(struct snd_intelhad *intelhaddata) { struct snd_pcm_substream *substream; - if (!intelhaddata->connected) - return; /* disconnected? - bail out */ - substream = had_substream_get(intelhaddata); if (!substream) return; /* no stream? - bail out */ + if (!intelhaddata->connected) { + snd_pcm_stop_xrun(substream); + goto out; /* disconnected? - bail out */ + } + /* process or stop the stream */ if (had_process_ringbuf(substream, intelhaddata) < 0) snd_pcm_stop_xrun(substream); else snd_pcm_period_elapsed(substream); + out: had_substream_put(intelhaddata); } -- cgit v1.2.3 From 2d42c033aec9f8e7e175c551ae62ea3f4dc200b9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 15 Feb 2017 22:08:21 +0100 Subject: ALSA: x86: Minor code rearrangement Put the stuff in the right order; notification should be at the end of the action. Also dropped a superfluous debug print and incorrect comments. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 8d67031e8429..dd3baabd1e82 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1384,18 +1384,15 @@ static void had_process_hot_plug(struct snd_intelhad *intelhaddata) __func__, __LINE__); spin_unlock_irq(&intelhaddata->had_spinlock); - /* Safety check */ + had_build_channel_allocation_map(intelhaddata); + + /* Report to above ALSA layer */ substream = had_substream_get(intelhaddata); if (substream) { - dev_dbg(intelhaddata->dev, - "Force to stop the active stream by disconnection\n"); - /* Set runtime->state to hw_params done */ snd_pcm_stop_xrun(substream); had_substream_put(intelhaddata); } - had_build_channel_allocation_map(intelhaddata); - snd_jack_report(intelhaddata->jack, SND_JACK_AVOUT); } @@ -1404,14 +1401,11 @@ static void had_process_hot_unplug(struct snd_intelhad *intelhaddata) { struct snd_pcm_substream *substream; - substream = had_substream_get(intelhaddata); - spin_lock_irq(&intelhaddata->had_spinlock); - if (!intelhaddata->connected) { dev_dbg(intelhaddata->dev, "Device already disconnected\n"); spin_unlock_irq(&intelhaddata->had_spinlock); - goto out; + return; } @@ -1424,16 +1418,17 @@ static void had_process_hot_unplug(struct snd_intelhad *intelhaddata) __func__, __LINE__); spin_unlock_irq(&intelhaddata->had_spinlock); + kfree(intelhaddata->chmap->chmap); + intelhaddata->chmap->chmap = NULL; + /* Report to above ALSA layer */ - if (substream) + substream = had_substream_get(intelhaddata); + if (substream) { snd_pcm_stop_xrun(substream); + had_substream_put(intelhaddata); + } - out: snd_jack_report(intelhaddata->jack, 0); - if (substream) - had_substream_put(intelhaddata); - kfree(intelhaddata->chmap->chmap); - intelhaddata->chmap->chmap = NULL; } /* -- cgit v1.2.3 From b1ef30e5ed17a417fc78eaff12da28f9a1c2efcc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 15 Feb 2017 22:11:13 +0100 Subject: ALSA: x86: Don't bail out from PCM ops when disconnected Currently the driver returns -ENODEV when the monitor is disconnected. But PA alsa module doesn't like this and it starts playing Juliet, kills itself as if it were a fatal tragedy. Since we protect the whole read/write at disconnection, just allow the PCM accesses even during disconnection. Signed-off-by: Takashi Iwai --- sound/x86/intel_hdmi_audio.c | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index dd3baabd1e82..360cff35b239 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1054,13 +1054,6 @@ static int had_pcm_open(struct snd_pcm_substream *substream) pm_runtime_get_sync(intelhaddata->dev); - if (!intelhaddata->connected) { - dev_dbg(intelhaddata->dev, "%s: HDMI cable plugged-out\n", - __func__); - retval = -ENODEV; - goto error; - } - /* set the runtime hw parameter with local snd_pcm_hardware struct */ runtime->hw = had_pcm_hardware; @@ -1186,14 +1179,6 @@ static int had_pcm_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_RESUME: - /* Disable local INTRs till register prgmng is done */ - if (!intelhaddata->connected) { - dev_dbg(intelhaddata->dev, - "_START: HDMI cable plugged-out\n"); - retval = -ENODEV; - break; - } - /* Enable Audio */ had_ack_irqs(intelhaddata); /* FIXME: do we need this? */ had_enable_audio(intelhaddata, true); @@ -1227,13 +1212,6 @@ static int had_pcm_prepare(struct snd_pcm_substream *substream) intelhaddata = snd_pcm_substream_chip(substream); runtime = substream->runtime; - if (!intelhaddata->connected) { - dev_dbg(intelhaddata->dev, "%s: HDMI cable plugged-out\n", - __func__); - retval = -ENODEV; - goto prep_end; - } - dev_dbg(intelhaddata->dev, "period_size=%d\n", (int)frames_to_bytes(runtime, runtime->period_size)); dev_dbg(intelhaddata->dev, "periods=%d\n", runtime->periods); -- cgit v1.2.3 From 3bb9eca913025ed05c0510de831c67b7bef652c5 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Sun, 19 Feb 2017 15:51:30 +0530 Subject: ALSA: emu10k1: constify snd_emux_operators structure Declare snd_emux_operators structure as const as it is only copied into another structure. So, snd_emux_operators structures having this property can be made const. Signed-off-by: Bhumika Goyal Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emu10k1_callback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/emu10k1/emu10k1_callback.c b/sound/pci/emu10k1/emu10k1_callback.c index d2c7ea3a7610..aa2cc27b8491 100644 --- a/sound/pci/emu10k1/emu10k1_callback.c +++ b/sound/pci/emu10k1/emu10k1_callback.c @@ -61,7 +61,7 @@ static void set_filterQ(struct snd_emu10k1 *hw, struct snd_emux_voice *vp); /* * set up operators */ -static struct snd_emux_operators emu10k1_ops = { +static const struct snd_emux_operators emu10k1_ops = { .owner = THIS_MODULE, .get_voice = get_voice, .prepare = start_voice, -- cgit v1.2.3