diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uac1 b/Documentation/ABI/testing/configfs-usb-gadget-uac1 index dc23fd776943..c4ba92f004c3 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-uac1 +++ b/Documentation/ABI/testing/configfs-usb-gadget-uac1 @@ -4,13 +4,30 @@ KernelVersion: 4.14 Description: The attributes: - ========== =================================== - c_chmask capture channel mask - c_srate capture sampling rate - c_ssize capture sample size (bytes) - p_chmask playback channel mask - p_srate playback sampling rate - p_ssize playback sample size (bytes) - req_number the number of pre-allocated request - for both capture and playback - ========== =================================== + ===================== ======================================= + c_chmask capture channel mask + c_srate list of capture sampling rates (comma-separated) + c_ssize capture sample size (bytes) + c_mute_present capture mute control enable + c_volume_present capture volume control enable + c_volume_min capture volume control min value + (in 1/256 dB) + c_volume_max capture volume control max value + (in 1/256 dB) + c_volume_res capture volume control resolution + (in 1/256 dB) + p_chmask playback channel mask + p_srate list of playback sampling rates (comma-separated) + p_ssize playback sample size (bytes) + p_mute_present playback mute control enable + p_volume_present playback volume control enable + p_volume_min playback volume control min value + (in 1/256 dB) + p_volume_max playback volume control max value + (in 1/256 dB) + p_volume_res playback volume control resolution + (in 1/256 dB) + req_number the number of pre-allocated requests + for both capture and playback + function_name name of the interface + ===================== ======================================= diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uac2 b/Documentation/ABI/testing/configfs-usb-gadget-uac2 index 26fb8e9b4e61..4c6bf63fcb22 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-uac2 +++ b/Documentation/ABI/testing/configfs-usb-gadget-uac2 @@ -4,13 +4,33 @@ KernelVersion: 3.18 Description: The attributes: - ========= ============================ - c_chmask capture channel mask - c_srate capture sampling rate - c_ssize capture sample size (bytes) - c_sync capture synchronization type (async/adaptive) - fb_max maximum extra bandwidth in async mode - p_chmask playback channel mask - p_srate playback sampling rate - p_ssize playback sample size (bytes) - ========= ============================ + ===================== ======================================= + c_chmask capture channel mask + c_srate list of capture sampling rates (comma-separated) + c_ssize capture sample size (bytes) + c_sync capture synchronization type + (async/adaptive) + c_mute_present capture mute control enable + c_volume_present capture volume control enable + c_volume_min capture volume control min value + (in 1/256 dB) + c_volume_max capture volume control max value + (in 1/256 dB) + c_volume_res capture volume control resolution + (in 1/256 dB) + fb_max maximum extra bandwidth in async mode + p_chmask playback channel mask + p_srate list of playback sampling rates (comma-separated) + p_ssize playback sample size (bytes) + p_mute_present playback mute control enable + p_volume_present playback volume control enable + p_volume_min playback volume control min value + (in 1/256 dB) + p_volume_max playback volume control max value + (in 1/256 dB) + p_volume_res playback volume control resolution + (in 1/256 dB) + req_number the number of pre-allocated requests + for both capture and playback + function_name name of the interface + ===================== ======================================= diff --git a/Documentation/sound/kernel-api/writing-an-alsa-driver.rst b/Documentation/sound/kernel-api/writing-an-alsa-driver.rst index 73bbd59afc33..690c5238f904 100644 --- a/Documentation/sound/kernel-api/writing-an-alsa-driver.rst +++ b/Documentation/sound/kernel-api/writing-an-alsa-driver.rst @@ -3508,14 +3508,15 @@ field must be set, though). “IEC958 Playback Con Mask” is used to return the bit-mask for the IEC958 status bits of consumer mode. Similarly, “IEC958 Playback Pro Mask” -returns the bitmask for professional mode. They are read-only controls, -and are defined as MIXER controls (iface = -``SNDRV_CTL_ELEM_IFACE_MIXER``). +returns the bitmask for professional mode. They are read-only controls. Meanwhile, “IEC958 Playback Default” control is defined for getting and -setting the current default IEC958 bits. Note that this one is usually -defined as a PCM control (iface = ``SNDRV_CTL_ELEM_IFACE_PCM``), -although in some places it's defined as a MIXER control. +setting the current default IEC958 bits. + +Due to historical reasons, both variants of the Playback Mask and the +Playback Default controls can be implemented on either a +``SNDRV_CTL_ELEM_IFACE_PCM`` or a ``SNDRV_CTL_ELEM_IFACE_MIXER`` iface. +Drivers should expose the mask and default on the same iface though. In addition, you can define the control switches to enable/disable or to set the raw bit mode. The implementation will depend on the chip, but diff --git a/Documentation/usb/gadget-testing.rst b/Documentation/usb/gadget-testing.rst index be1b085a0901..353e4daa7861 100644 --- a/Documentation/usb/gadget-testing.rst +++ b/Documentation/usb/gadget-testing.rst @@ -724,18 +724,29 @@ Function-specific configfs interface The function name to use when creating the function directory is "uac2". The uac2 function provides these attributes in its function directory: - =============== ==================================================== - c_chmask capture channel mask - c_srate capture sampling rate - c_ssize capture sample size (bytes) - c_sync capture synchronization type (async/adaptive) - fb_max maximum extra bandwidth in async mode - p_chmask playback channel mask - p_srate playback sampling rate - p_ssize playback sample size (bytes) - req_number the number of pre-allocated request for both capture - and playback - =============== ==================================================== + ================ ==================================================== + c_chmask capture channel mask + c_srate list of capture sampling rates (comma-separated) + c_ssize capture sample size (bytes) + c_sync capture synchronization type (async/adaptive) + c_mute_present capture mute control enable + c_volume_present capture volume control enable + c_volume_min capture volume control min value (in 1/256 dB) + c_volume_max capture volume control max value (in 1/256 dB) + c_volume_res capture volume control resolution (in 1/256 dB) + fb_max maximum extra bandwidth in async mode + p_chmask playback channel mask + p_srate list of playback sampling rates (comma-separated) + p_ssize playback sample size (bytes) + p_mute_present playback mute control enable + p_volume_present playback volume control enable + p_volume_min playback volume control min value (in 1/256 dB) + p_volume_max playback volume control max value (in 1/256 dB) + p_volume_res playback volume control resolution (in 1/256 dB) + req_number the number of pre-allocated request for both capture + and playback + function_name name of the interface + ================ ==================================================== The attributes have sane default values. @@ -905,16 +916,27 @@ Function-specific configfs interface The function name to use when creating the function directory is "uac1". The uac1 function provides these attributes in its function directory: - ========== ==================================================== - c_chmask capture channel mask - c_srate capture sampling rate - c_ssize capture sample size (bytes) - p_chmask playback channel mask - p_srate playback sampling rate - p_ssize playback sample size (bytes) - req_number the number of pre-allocated request for both capture - and playback - ========== ==================================================== + ================ ==================================================== + c_chmask capture channel mask + c_srate list of capture sampling rates (comma-separated) + c_ssize capture sample size (bytes) + c_mute_present capture mute control enable + c_volume_present capture volume control enable + c_volume_min capture volume control min value (in 1/256 dB) + c_volume_max capture volume control max value (in 1/256 dB) + c_volume_res capture volume control resolution (in 1/256 dB) + p_chmask playback channel mask + p_srate list of playback sampling rates (comma-separated) + p_ssize playback sample size (bytes) + p_mute_present playback mute control enable + p_volume_present playback volume control enable + p_volume_min playback volume control min value (in 1/256 dB) + p_volume_max playback volume control max value (in 1/256 dB) + p_volume_res playback volume control resolution (in 1/256 dB) + req_number the number of pre-allocated requests for both capture + and playback + function_name name of the interface + ================ ==================================================== The attributes have sane default values. diff --git a/android/abi_gki_aarch64.xml b/android/abi_gki_aarch64.xml index b2f1e5204d00..be7daf453b89 100755 --- a/android/abi_gki_aarch64.xml +++ b/android/abi_gki_aarch64.xml @@ -68,6 +68,7 @@ + @@ -208,6 +209,7 @@ + @@ -390,9 +392,12 @@ + + + @@ -444,7 +449,9 @@ + + @@ -488,6 +495,7 @@ + @@ -502,11 +510,13 @@ + + @@ -518,11 +528,17 @@ + + + + + + @@ -543,6 +559,7 @@ + @@ -577,6 +594,7 @@ + @@ -659,6 +677,7 @@ + @@ -1245,11 +1264,13 @@ + + @@ -1281,6 +1302,7 @@ + @@ -1312,6 +1334,7 @@ + @@ -1391,6 +1414,7 @@ + @@ -1464,6 +1488,7 @@ + @@ -1560,6 +1585,7 @@ + @@ -1630,6 +1656,7 @@ + @@ -1638,6 +1665,7 @@ + @@ -1661,6 +1689,7 @@ + @@ -1699,6 +1728,7 @@ + @@ -1811,6 +1841,7 @@ + @@ -1952,6 +1983,9 @@ + + + @@ -2040,6 +2074,7 @@ + @@ -2055,7 +2090,11 @@ + + + + @@ -2081,6 +2120,7 @@ + @@ -2183,6 +2223,7 @@ + @@ -2266,6 +2307,7 @@ + @@ -2293,6 +2335,8 @@ + + @@ -2623,6 +2667,7 @@ + @@ -2736,6 +2781,7 @@ + @@ -2899,6 +2945,7 @@ + @@ -3425,6 +3472,7 @@ + @@ -3639,6 +3687,7 @@ + @@ -3787,6 +3836,7 @@ + @@ -3825,6 +3875,7 @@ + @@ -4328,6 +4379,7 @@ + @@ -4346,6 +4398,7 @@ + @@ -4376,6 +4429,7 @@ + @@ -4480,6 +4534,8 @@ + + @@ -4712,6 +4768,7 @@ + @@ -4857,7 +4914,10 @@ + + + @@ -4930,6 +4990,7 @@ + @@ -4967,6 +5028,8 @@ + + @@ -5213,6 +5276,7 @@ + @@ -5734,6 +5798,7 @@ + @@ -5792,14 +5857,18 @@ + + + + @@ -6177,9 +6246,12 @@ + + + @@ -6231,7 +6303,9 @@ + + @@ -6278,6 +6352,7 @@ + @@ -6292,12 +6367,14 @@ + + @@ -6313,8 +6390,13 @@ + + + + + @@ -6322,6 +6404,7 @@ + @@ -6344,6 +6427,7 @@ + @@ -6381,6 +6465,7 @@ + @@ -6901,7 +6986,7 @@ - + @@ -6934,7 +7019,7 @@ - + @@ -7144,15 +7229,15 @@ - + - + - + - + @@ -7814,6 +7899,15 @@ + + + + + + + + + @@ -8047,7 +8141,7 @@ - + @@ -8280,7 +8374,7 @@ - + @@ -8459,26 +8553,26 @@ - + - + - + - + - + - + - + - + @@ -9694,21 +9788,21 @@ - + - + - + - + - + - + @@ -9870,6 +9964,11 @@ + + + + + @@ -10803,6 +10902,7 @@ + @@ -11569,6 +11669,7 @@ + @@ -11708,18 +11809,35 @@ - + - + + + + - + + + + - + + + + + + + + + + + + - + @@ -12758,7 +12876,7 @@ - + @@ -14373,24 +14491,24 @@ - + - + - + - + - + - + - + @@ -14513,42 +14631,42 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -14864,15 +14982,15 @@ - + - + - + - + @@ -14894,89 +15012,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -15002,24 +15037,24 @@ - + - + - + - + - + - + - + @@ -15028,60 +15063,60 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -15092,51 +15127,51 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -15578,45 +15613,45 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -15920,33 +15955,33 @@ - + - + - + - + - + - + - + - + - + - + @@ -17641,102 +17676,102 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -17923,27 +17958,27 @@ - + - + - + - + - + - + - + - + @@ -18289,45 +18324,45 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -18550,42 +18585,42 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -19511,7 +19546,7 @@ - + @@ -19647,6 +19682,7 @@ + @@ -26307,6 +26343,7 @@ + @@ -26499,6 +26536,14 @@ + + + + + + + + @@ -27124,6 +27169,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -27920,100 +27985,100 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -30039,15 +30104,15 @@ - + - + - + - + @@ -30552,18 +30617,18 @@ - + - + - + - + - + @@ -30973,6 +31038,11 @@ + + + + + @@ -33664,72 +33734,72 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -34073,12 +34143,12 @@ - + - + - + @@ -35147,15 +35217,15 @@ - + - + - + - + @@ -35769,6 +35839,10 @@ + + + + @@ -36870,7 +36944,7 @@ - + @@ -37369,7 +37443,7 @@ - + @@ -37728,153 +37802,153 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -38199,51 +38273,51 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -38495,7 +38569,7 @@ - + @@ -39910,6 +39984,7 @@ + @@ -42141,6 +42216,7 @@ + @@ -42902,39 +42978,39 @@ - + - + - + - + - + - + - + - + - + - + - + - + @@ -43089,6 +43165,23 @@ + + + + + + + + + + + + + + + + + @@ -44606,7 +44699,7 @@ - + @@ -45683,6 +45776,7 @@ + @@ -47037,36 +47131,36 @@ - + - + - + - + - + - + - + - + - + - + - + @@ -48220,9 +48314,9 @@ - + - + @@ -48276,7 +48370,7 @@ - + @@ -48380,12 +48474,12 @@ - + - + - + @@ -48506,63 +48600,63 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -49561,6 +49655,7 @@ + @@ -49972,51 +50067,51 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -50040,7 +50135,7 @@ - + @@ -50408,18 +50503,18 @@ - + - + - + - + - + @@ -50822,12 +50917,12 @@ - + - + - + @@ -51182,6 +51277,7 @@ + @@ -52649,81 +52745,81 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -52968,12 +53064,12 @@ - + - + - + @@ -52997,6 +53093,7 @@ + @@ -54244,27 +54341,27 @@ - + - + - + - + - + - + - + - + @@ -56302,39 +56399,39 @@ - + - + - + - + - + - + - + - + - + - + - + - + @@ -56574,18 +56671,18 @@ - + - + - + - + - + @@ -59352,18 +59449,18 @@ - + - + - + - + - + @@ -59829,9 +59926,9 @@ - + - + @@ -60314,24 +60411,24 @@ - + - + - + - + - + - + - + @@ -60539,12 +60636,12 @@ - + - + - + @@ -60719,7 +60816,7 @@ - + @@ -61136,6 +61233,7 @@ + @@ -61528,12 +61626,12 @@ - + - + - + @@ -61625,6 +61723,11 @@ + + + + + @@ -62164,21 +62267,21 @@ - + - + - + - + - + - + @@ -62359,24 +62462,24 @@ - + - + - + - + - + - + - + @@ -62705,7 +62808,7 @@ - + @@ -63352,7 +63455,7 @@ - + @@ -63439,102 +63542,102 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -64159,27 +64262,27 @@ - + - + - + - + - + - + - + - + @@ -65195,7 +65298,7 @@ - + @@ -65484,33 +65587,33 @@ - + - + - + - + - + - + - + - + - + - + @@ -66101,6 +66204,7 @@ + @@ -67506,14 +67610,7 @@ - - - - - - - - + @@ -68059,6 +68156,7 @@ + @@ -71671,6 +71769,7 @@ + @@ -72293,12 +72392,12 @@ - + - + - + @@ -72354,6 +72453,7 @@ + @@ -72817,7 +72917,7 @@ - + @@ -73063,7 +73163,7 @@ - + @@ -73331,7 +73431,7 @@ - + @@ -73549,54 +73649,54 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -74365,21 +74465,21 @@ - + - + - + - + - + - + @@ -76242,120 +76342,120 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -76782,6 +76882,7 @@ + @@ -76916,18 +77017,18 @@ - + - + - + - + - + @@ -78641,7 +78742,7 @@ - + @@ -78866,21 +78967,21 @@ - + - + - + - + - + - + @@ -80043,6 +80144,7 @@ + @@ -81279,6 +81381,10 @@ + + + + @@ -81811,24 +81917,24 @@ - + - + - + - + - + - + - + @@ -82055,6 +82161,10 @@ + + + + @@ -82417,54 +82527,54 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -82749,12 +82859,12 @@ - + - + - + @@ -85053,12 +85163,12 @@ - + - + - + @@ -85397,72 +85507,72 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -86374,6 +86484,7 @@ + @@ -87625,12 +87736,12 @@ - + - + - + @@ -88398,45 +88509,45 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -89393,6 +89504,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -90020,6 +90166,7 @@ + @@ -91742,51 +91889,51 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -92541,7 +92688,6 @@ - @@ -92681,99 +92827,99 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -93293,9 +93439,9 @@ - + - + @@ -95558,6 +95704,7 @@ + @@ -96607,6 +96754,12 @@ + + + + + + @@ -97227,51 +97380,51 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -97489,6 +97642,10 @@ + + + + @@ -97685,12 +97842,12 @@ - + - + - + @@ -99337,15 +99494,15 @@ - + - + - + - + @@ -100005,12 +100162,12 @@ - + - + - + @@ -100038,12 +100195,12 @@ - + - + - + @@ -100671,7 +100828,7 @@ - + @@ -102634,6 +102791,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -103608,21 +103815,21 @@ - + - + - + - + - + - + @@ -104310,15 +104517,15 @@ - + - + - + - + @@ -105631,92 +105838,92 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -106476,6 +106683,7 @@ + @@ -106539,66 +106747,66 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -110010,6 +110218,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -111002,6 +111230,7 @@ + @@ -111026,15 +111255,15 @@ - + - + - + - + @@ -111208,87 +111437,87 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -111852,7 +112081,7 @@ - + @@ -112397,99 +112626,99 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -113318,33 +113547,33 @@ - + - + - + - + - + - + - + - + - + - + @@ -114885,8 +115114,8 @@ - - + + @@ -114913,11 +115142,11 @@ - - - - - + + + + + @@ -115012,9 +115241,9 @@ - - - + + + @@ -115207,55 +115436,55 @@ - - - - + + + + - - - + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - + + + + - - - - + + + + - - - - + + + + @@ -115265,9 +115494,9 @@ - - - + + + @@ -115280,6 +115509,11 @@ + + + + + @@ -115401,21 +115635,21 @@ - - - - + + + + - - - - + + + + - - - + + + @@ -115542,9 +115776,9 @@ - - - + + + @@ -115597,9 +115831,9 @@ - - - + + + @@ -115913,9 +116147,9 @@ - - - + + + @@ -116017,12 +116251,12 @@ - - + + - - + + @@ -116040,8 +116274,8 @@ - - + + @@ -116092,7 +116326,7 @@ - + @@ -116110,12 +116344,16 @@ + + + + - - + + @@ -116175,34 +116413,34 @@ - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + @@ -116459,10 +116697,10 @@ - - - - + + + + @@ -116542,10 +116780,10 @@ - - - - + + + + @@ -116608,12 +116846,12 @@ - - - - - - + + + + + + @@ -116628,11 +116866,11 @@ - - - - - + + + + + @@ -116686,10 +116924,10 @@ - - - - + + + + @@ -117049,9 +117287,9 @@ - - - + + + @@ -117060,14 +117298,14 @@ - - - + + + - - - + + + @@ -117114,19 +117352,19 @@ - - - - - + + + + + - - - - - - + + + + + + @@ -117213,6 +117451,13 @@ + + + + + + + @@ -117237,6 +117482,20 @@ + + + + + + + + + + + + + + @@ -117274,148 +117533,148 @@ - - - - - + + + + + - - - - + + + + - - - + + + - - - - - + + + + + - - - - + + + + - - - - - + + + + + - - - - + + + + - - - - - - + + + + + + - - - - + + + + - - - - - - - - - - - + + - - - - - + + + + + + + + - - - - - - + + + + - - - - + + + + + + - - - - + + + + - - - - - + + + + - - - - + + + + + - - - - - - + + + + - - - + + + + + + - - - - - + + + - - - - - + + + + + + + + + + + + @@ -117438,16 +117697,16 @@ - - - - + + + + - - - - + + + + @@ -117494,25 +117753,25 @@ - - - - - - - - + + + + + + + + - - - + + + - - - - + + + + @@ -117578,6 +117837,13 @@ + + + + + + + @@ -117585,20 +117851,25 @@ + + + + + - - - - - - - - + + + + + + + + @@ -117631,10 +117902,10 @@ - - - - + + + + @@ -117643,22 +117914,22 @@ - - - + + + - - - - + + + + - - - - - + + + + + @@ -117737,11 +118008,11 @@ - - - - - + + + + + @@ -117755,11 +118026,11 @@ - - - - - + + + + + @@ -117831,11 +118102,11 @@ - - - - - + + + + + @@ -117860,6 +118131,11 @@ + + + + + @@ -117867,77 +118143,77 @@ - - - + + + - - - - + + + + - - - - + + + + - - - + + + - - - + + + - - - + + + - - - - - - - - + + + + + + + + - - - - + + + + - - - - - + + + + + - - - + + + - - - - - + + + + + - - - - + + + + @@ -117945,6 +118221,12 @@ + + + + + + @@ -117975,19 +118257,25 @@ - - - - - - - + + + + - - - - + + + + + + + + + + + + + @@ -118019,14 +118307,14 @@ - - - - - - - - + + + + + + + + @@ -118044,6 +118332,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -118059,16 +118373,23 @@ - - - - + + + + - - - - + + + + + + + + + + + @@ -118094,15 +118415,15 @@ - - - + + + - - - - + + + + @@ -118189,16 +118510,21 @@ + + + + + - - - - + + + + @@ -118206,10 +118532,10 @@ - - - - + + + + @@ -118218,10 +118544,10 @@ - - - - + + + + @@ -118251,10 +118577,10 @@ - - - - + + + + @@ -118281,12 +118607,12 @@ - - - - - - + + + + + + @@ -118305,41 +118631,41 @@ - - - - - + + + + + - - - - - + + + + + - - - - - - - - + + + + + + + + - - - - - + + + + + - - - - + + + + @@ -118408,6 +118734,15 @@ + + + + + + + + + @@ -118853,10 +119188,10 @@ - + - + @@ -118864,7 +119199,7 @@ - + @@ -118902,7 +119237,7 @@ - + @@ -118924,10 +119259,10 @@ - + - - + + @@ -118939,8 +119274,8 @@ - - + + @@ -118955,40 +119290,43 @@ + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - + + @@ -118996,9 +119334,9 @@ - - - + + + @@ -119009,19 +119347,21 @@ + + - + - + - - - + + + @@ -119035,11 +119375,11 @@ - + - + @@ -119052,32 +119392,35 @@ - + + - - - - - - - - - - - - + + + + + + + + + + + + + - + - - + + + @@ -119085,28 +119428,34 @@ - + + + + + + - - + + + - - + + @@ -119122,33 +119471,34 @@ + - + - + - + - - + + - + - - - - - + + + + + @@ -119159,13 +119509,14 @@ + - + @@ -119240,10 +119591,10 @@ - - - - + + + + @@ -119293,6 +119644,10 @@ + + + + @@ -119340,9 +119695,9 @@ - - - + + + @@ -119412,11 +119767,11 @@ - - - - - + + + + + @@ -119455,48 +119810,48 @@ - - - - - - - + - - - - - - - + - + + + + + + + + + + + + + + + + + + + - + - - - - - - @@ -119638,12 +119993,12 @@ - - - - - - + + + + + + @@ -119656,13 +120011,13 @@ - - + + - - - + + + @@ -119678,8 +120033,8 @@ - - + + @@ -119728,9 +120083,9 @@ - - - + + + @@ -119832,13 +120187,13 @@ - - - - - - - + + + + + + + @@ -119847,9 +120202,9 @@ - - - + + + @@ -119931,7 +120286,7 @@ - + @@ -120401,16 +120756,16 @@ - - + + - - + + - - + + @@ -120418,22 +120773,22 @@ - - - + + + - - - + + + - - + + - - + + @@ -120449,15 +120804,15 @@ - - + + - - - - - + + + + + @@ -120474,23 +120829,23 @@ - - - + + + - - + + - - - + + + - - - + + + @@ -120513,22 +120868,22 @@ - - + + - - - + + + - - + + - - - + + + @@ -120553,9 +120908,9 @@ - - - + + + @@ -120568,10 +120923,10 @@ - - - - + + + + @@ -120893,10 +121248,10 @@ - - - - + + + + @@ -120913,7 +121268,7 @@ - + @@ -121040,8 +121395,8 @@ - - + + @@ -121094,12 +121449,12 @@ - - + + - - + + @@ -121135,13 +121490,13 @@ - - + + - - - + + + @@ -121149,13 +121504,13 @@ - - + + - - - + + + @@ -121176,9 +121531,9 @@ - - - + + + @@ -121409,26 +121764,26 @@ - - - + + + - - - - - + + + + + - - - + + + - - - + + + @@ -122036,16 +122391,16 @@ - - + + - + - + @@ -122073,10 +122428,10 @@ - + - + @@ -122269,7 +122624,7 @@ - + @@ -122327,10 +122682,10 @@ - + - + @@ -122401,6 +122756,10 @@ + + + + @@ -122431,6 +122790,12 @@ + + + + + + @@ -122611,6 +122976,10 @@ + + + + @@ -122768,6 +123137,10 @@ + + + + @@ -122817,14 +123190,14 @@ - - - + + + - - - + + + @@ -122921,26 +123294,26 @@ - - - - + + + + - - + + - - - - + + + + - - - - + + + + @@ -123174,8 +123547,8 @@ - - + + @@ -123200,6 +123573,12 @@ + + + + + + @@ -123214,16 +123593,16 @@ - - - - + + + + - - - - + + + + @@ -123247,20 +123626,20 @@ - - + + - - - - + + + + - - - + + + @@ -123287,9 +123666,9 @@ - - - + + + @@ -123559,6 +123938,10 @@ + + + + @@ -123615,38 +123998,38 @@ - - - - + + + + - - - - + + + + - - + + - - - - + + + + - - - + + + - - - + + + @@ -123664,11 +124047,11 @@ - - - - - + + + + + @@ -123773,8 +124156,8 @@ - - + + @@ -123783,67 +124166,67 @@ - - - + + + - - + + - - + + - - - - - - + + + + + + - - - + + + - - - + + + - - - - - - - + + + + + + + - - + + - - - + + + - - - - + + + + - - - - + + + + @@ -123883,38 +124266,38 @@ - - + + - - - - + + + + - - + + - - - + + + - - - + + + - - - + + + - - - + + + @@ -123960,42 +124343,42 @@ - - + + - - + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + @@ -124008,34 +124391,34 @@ - - - - + + + + - - - - + + + + - - - - - + + + + + - - - - - + + + + + - - + + @@ -124052,6 +124435,13 @@ + + + + + + + @@ -124157,19 +124547,19 @@ - - - + + + - - - + + + - - - + + + @@ -124318,9 +124708,9 @@ - - - + + + @@ -124467,6 +124857,11 @@ + + + + + @@ -124517,6 +124912,12 @@ + + + + + + @@ -124544,9 +124945,9 @@ - - - + + + @@ -124638,20 +125039,25 @@ - - - - - - - - + + + - - - - + + + + + + + + + + + + + + @@ -124870,6 +125276,10 @@ + + + + @@ -125501,6 +125911,9 @@ + + + @@ -125560,9 +125973,9 @@ - - - + + + @@ -125574,157 +125987,157 @@ - - + + - - + + - - - + + + - - + + - - - + + + - - + + - - - + + + - - + + - - - - + + + + - - + + - - - + + + - - + + - - - - + + + + - - - - + + + + - - - + + + - - - + + + - - + + - - + + - - - - - + + + + + - - + + - - - + + + - - - - - + + + + + - - - - - + + + + + - - + + - - - + + + - - - - + + + + - - - - + + + + - - - + + + - - - + + + - - + + @@ -125831,13 +126244,13 @@ - - - - - - - + + + + + + + @@ -125868,52 +126281,52 @@ - - - + + + - - - - + + + + - - + + - - - + + + - - + + - - - + + + - - - + + + - - - - + + + + - - + + - - + + @@ -125957,45 +126370,45 @@ - - - + + + - - - + + + - - - + + + - - - + + + - - + + - - - - - - - + + + + + + + - - - - - - + + + + + + @@ -126011,77 +126424,77 @@ - - - + + + - - - + + + - - - + + + - - - + + + - - + + - - + + - - - + + + - - - + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - + + - - - - + + + + - - - + + + - - - + + + @@ -126201,6 +126614,20 @@ + + + + + + + + + + + + + + @@ -126651,6 +127078,11 @@ + + + + + @@ -126730,12 +127162,33 @@ + + + + + + + + + + + + + + + + + + + + + @@ -126865,6 +127318,12 @@ + + + + + + @@ -127383,6 +127842,11 @@ + + + + + @@ -127792,6 +128256,10 @@ + + + + @@ -127958,6 +128426,14 @@ + + + + + + + + @@ -128189,10 +128665,10 @@ - - - - + + + + @@ -128207,8 +128683,8 @@ - - + + @@ -128234,10 +128710,10 @@ - - - - + + + + @@ -128527,17 +129003,17 @@ - - + + - - - + + + - - + + @@ -128720,8 +129196,8 @@ - - + + @@ -128748,9 +129224,9 @@ - - - + + + @@ -128761,8 +129237,8 @@ - - + + @@ -128774,8 +129250,8 @@ - - + + @@ -128820,10 +129296,10 @@ - - - - + + + + @@ -128870,18 +129346,18 @@ - - + + - - - + + + - - - + + + @@ -129193,8 +129669,8 @@ - - + + @@ -129635,25 +130111,25 @@ - - - + + + - - - + + + - - + + - - - - - + + + + + @@ -129714,31 +130190,34 @@ + + + - - - + + + - - - + + + - - - + + + - + - + @@ -129754,17 +130233,17 @@ - - + + - - + + - - - + + + @@ -129826,12 +130305,12 @@ - - + + - - + + @@ -130195,8 +130674,8 @@ - - + + @@ -130265,6 +130744,12 @@ + + + + + + @@ -130454,12 +130939,12 @@ - - + + - - + + @@ -130851,8 +131336,8 @@ - - + + @@ -130862,8 +131347,8 @@ - - + + @@ -131097,6 +131582,12 @@ + + + + + + @@ -131205,8 +131696,8 @@ - - + + @@ -131217,7 +131708,7 @@ - + @@ -131553,19 +132044,19 @@ - - + + - - - + + + - - - - + + + + @@ -131598,17 +132089,17 @@ - - + + - - - + + + @@ -131676,8 +132167,8 @@ - - + + @@ -132365,25 +132856,25 @@ - - - - + + + + - - - - - + + + + + - - + + @@ -132899,51 +133390,51 @@ - + - - + + - - + + - - + + - + - + - - + + - + - - + + - + - - + + - - + + - - + + @@ -132952,8 +133443,8 @@ - - + + @@ -132961,10 +133452,10 @@ - - - - + + + + @@ -133136,14 +133627,14 @@ - - + + - + - + @@ -133434,8 +133925,8 @@ - - + + @@ -133466,7 +133957,7 @@ - + @@ -133794,6 +134285,10 @@ + + + + @@ -134266,9 +134761,9 @@ - - - + + + @@ -134276,22 +134771,22 @@ - - + + - - - + + + - - - + + + - - + + @@ -134322,9 +134817,9 @@ - - - + + + @@ -134332,88 +134827,88 @@ - - + + - - - + + + - - - - + + + + - - - + + + - - - + + + - - - - - - + + + + + + - - - - + + + + - - - - + + + + - - + + - - - + + + - - + + - - - - + + + + - - - + + + - - - + + + @@ -134433,31 +134928,31 @@ - - - - - + + + + + - - + + - - + + - - + + - - + + - - + + @@ -134474,13 +134969,13 @@ - - - + + + - - + + @@ -134854,6 +135349,12 @@ + + + + + + @@ -135606,16 +136107,16 @@ - - + + - - + + - - + + @@ -135632,6 +136133,11 @@ + + + + + @@ -135665,19 +136171,19 @@ - - - - - + + + + + - - - - - - + + + + + + @@ -135778,22 +136284,22 @@ - - - - + + + + - - + + - - + + @@ -135824,12 +136330,12 @@ - - + + - - + + @@ -135844,14 +136350,19 @@ - - + + + + + + + @@ -135860,17 +136371,17 @@ - - + + - - - + + + @@ -135892,8 +136403,8 @@ - - + + @@ -136014,9 +136525,9 @@ - - - + + + @@ -136110,13 +136621,13 @@ - - - + + + - - + + @@ -136124,9 +136635,9 @@ - - - + + + @@ -136143,29 +136654,29 @@ - - - - + + + + - - - + + + - - - - + + + + - - + + @@ -136186,17 +136697,17 @@ - - - + + + - - + + - - + + @@ -136217,8 +136728,8 @@ - - + + @@ -136273,11 +136784,11 @@ - - - - - + + + + + @@ -136299,17 +136810,17 @@ - - + + - - + + - - - + + + @@ -136342,8 +136853,8 @@ - - + + @@ -136353,21 +136864,21 @@ - - + + - - - + + + - - + + - - + + @@ -136393,12 +136904,12 @@ - - - - - - + + + + + + @@ -136442,10 +136953,10 @@ - - - - + + + + @@ -136819,14 +137330,14 @@ - - - + + + - - - + + + @@ -137251,50 +137762,50 @@ - - + + - - + + - - + + - - + + - - + + - - + + - - - + + + - - + + - - + + - - - + + + @@ -137448,7 +137959,7 @@ - + @@ -137495,36 +138006,36 @@ - - - - - + + + + + - - - - - - + + + + + + - - - - - - - + + + + + + + - - - - - - + + + + + + @@ -137559,37 +138070,37 @@ - - - + + + - - - - - + + + + + - - + + - - - + + + - - - - + + + + - - - - + + + + @@ -137681,8 +138192,8 @@ - - + + @@ -137697,8 +138208,8 @@ - - + + @@ -137924,7 +138435,7 @@ - + @@ -137973,9 +138484,9 @@ - - - + + + @@ -137991,20 +138502,20 @@ - - + + - - + + - - + + - - + + @@ -138029,8 +138540,8 @@ - - + + @@ -138156,12 +138667,12 @@ - - + + - - + + @@ -138233,13 +138744,13 @@ - - - - - - - + + + + + + + @@ -138272,9 +138783,9 @@ - - - + + + @@ -138299,13 +138810,13 @@ - - + + - - - + + + @@ -138357,6 +138868,12 @@ + + + + + + @@ -138373,29 +138890,29 @@ - - - + + + - - - + + + - - - + + + - - - - + + + + - - + + @@ -138403,86 +138920,90 @@ - - + + - - - + + + - - + + - - + + - - - + + + - - + + - - + + - - + + - - - + + + + + + + - - + + - - + + - - + + - - - - + + + + - - - + + + @@ -138524,24 +139045,24 @@ - - - - + + + + - - + + - - - + + + - - - + + + @@ -138549,10 +139070,10 @@ - - - - + + + + @@ -138561,24 +139082,24 @@ - - - + + + - - - + + + - - - - + + + + @@ -138586,38 +139107,43 @@ - - - - + + + + - - - - + + + + - - + + + - - + + + + + + - - - + + + - - - + + + @@ -138632,14 +139158,14 @@ - - - - + + + + - - + + @@ -138648,14 +139174,14 @@ - - - + + + - - - + + + @@ -138746,8 +139272,8 @@ - - + + @@ -139134,11 +139660,23 @@ - + + + + + + + + + + + + + @@ -139477,10 +140015,10 @@ - - - - + + + + @@ -140075,53 +140613,53 @@ - - - - + + + + - - - - - + + + + + - - - + + + - - - - + + + + - - + + - - + + - - + + - - - + + + - - + + - - + + @@ -140132,17 +140670,17 @@ - - + + - - + + - - - + + + @@ -140313,6 +140851,10 @@ + + + + @@ -140368,14 +140910,14 @@ - - + + - - - - + + + + @@ -140409,27 +140951,27 @@ - - - - + + + + - - - + + + - - - - + + + + - - - - + + + + @@ -140450,11 +140992,11 @@ - + - - + + @@ -141124,10 +141666,27 @@ - - - - + + + + + + + + + + + + + + + + + + + + + @@ -141520,138 +142079,143 @@ - - - - + + + + - - - - + + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - + + + + + + + - - + + - - - - - + + + + + - - - - - - + + + + + + - - - + + + - - - - + + + + - - + + - - - + + + - - - + + + - - - + + + - - + + - - + + - - - - + + + + @@ -141734,6 +142298,17 @@ + + + + + + + + + + + @@ -142266,9 +142841,9 @@ - - - + + + @@ -142313,9 +142888,9 @@ - - - + + + @@ -142544,9 +143119,9 @@ - - - + + + @@ -142597,20 +143172,20 @@ - - - + + + - - + + - + @@ -142622,7 +143197,7 @@ - + @@ -142814,8 +143389,8 @@ - - + + @@ -142849,11 +143424,11 @@ - - - - - + + + + + @@ -142887,12 +143462,12 @@ - - - - - - + + + + + + @@ -142974,6 +143549,10 @@ + + + + @@ -143097,12 +143676,12 @@ - - + + - - + + @@ -143172,8 +143751,8 @@ - - + + @@ -143351,11 +143930,11 @@ - - - - - + + + + + @@ -143363,9 +143942,9 @@ - - - + + + @@ -143622,19 +144201,19 @@ - - + + - - - - - + + + + + @@ -143786,30 +144365,30 @@ - - + + - - + + - - + + - - - + + + - - - + + + - - + + @@ -143821,9 +144400,9 @@ - - - + + + @@ -143831,9 +144410,9 @@ - - - + + + @@ -143841,9 +144420,9 @@ - - - + + + @@ -143861,8 +144440,8 @@ - - + + @@ -143870,8 +144449,8 @@ - - + + @@ -143882,111 +144461,111 @@ - - + + - - - + + + - - - + + + - - - - - + + + + + - - - - - - + + + + + + - - - + + + - - + + - - - + + + - - - + + + - - - - - - + + + + + + - - - - - - + + + + + + - - + + - - - + + + - - - + + + - - - - - - - + + + + + + + - - - + + + - - - + + + - - + + - - - - + + + + @@ -144042,48 +144621,48 @@ - - - + + + - - - + + + - - - + + + - - - + + + - - + + - - - + + + - - - - - + + + + + - - - - - - + + + + + + @@ -144093,162 +144672,162 @@ - - - + + + - - + + - - - - + + + + - - + + - - + + - - - + + + - - + + - - + + - - - - + + + + - - - + + + - - + + - - + + - - + + - - + + - - + + - - + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - - + + + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - - + + + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - - - + + + + @@ -144345,21 +144924,21 @@ - - + + - - + + - - - + + + @@ -144922,8 +145501,8 @@ - - + + @@ -145079,8 +145658,8 @@ - - + + @@ -145602,6 +146181,13 @@ + + + + + + + @@ -145900,6 +146486,13 @@ + + + + + + + @@ -145923,6 +146516,12 @@ + + + + + + @@ -145945,7 +146544,19 @@ + + + + + + + + + + + + @@ -146194,8 +146805,8 @@ - - + + @@ -146597,16 +147208,16 @@ - + - - - - - - - + + + + + + + @@ -146628,8 +147239,8 @@ - - + + @@ -146643,15 +147254,15 @@ - - + + - - - - - + + + + + @@ -146730,11 +147341,11 @@ - - - - - + + + + + @@ -146767,29 +147378,29 @@ - - - - + + + + - - - - + + + + - - + + - - + + - - - + + + @@ -146828,7 +147439,7 @@ - + @@ -146975,9 +147586,9 @@ - - - + + + @@ -147082,12 +147693,12 @@ - - - - - - + + + + + + @@ -147095,33 +147706,33 @@ - - - - + + + + - - - - - - - - - - + + + + + + + + + + - - - - + + + + - - - + + + @@ -147145,19 +147756,19 @@ - - - + + + - - - - + + + + @@ -147170,13 +147781,13 @@ - - - + + + - - + + @@ -147194,9 +147805,9 @@ - - - + + + @@ -147219,14 +147830,14 @@ - - - + + + - - - + + + @@ -147256,9 +147867,9 @@ - - - + + + @@ -147271,8 +147882,8 @@ - - + + @@ -147310,11 +147921,11 @@ - - - - - + + + + + diff --git a/android/abi_gki_aarch64_mtk b/android/abi_gki_aarch64_mtk index 807be584e15b..ee8da67b460e 100644 --- a/android/abi_gki_aarch64_mtk +++ b/android/abi_gki_aarch64_mtk @@ -371,7 +371,10 @@ device_unregister _dev_info __dev_kfree_skb_any + __dev_kfree_skb_irq + devm_add_action __devm_alloc_percpu + devm_alloc_etherdev_mqs devm_blk_ksm_init devm_clk_bulk_get devm_clk_bulk_get_optional @@ -412,11 +415,13 @@ devm_led_classdev_register_ext devm_led_classdev_unregister devm_mbox_controller_register + devm_mdiobus_alloc_size devm_memremap devm_mfd_add_devices devm_nvmem_cell_get devm_nvmem_device_get devm_nvmem_register + devm_of_mdiobus_register devm_of_phy_get_by_index __devm_of_phy_provider_register devm_of_platform_populate @@ -433,6 +438,7 @@ devm_power_supply_register devm_rc_allocate_device devm_rc_register_device + devm_register_netdev devm_regmap_add_irq_chip devm_regmap_field_alloc devm_regmap_field_bulk_alloc @@ -584,6 +590,7 @@ down_write d_path dput + dql_completed drain_workqueue driver_create_file driver_remove_file @@ -809,7 +816,13 @@ genlmsg_put genl_register_family genl_unregister_family + __genphy_config_aneg + genphy_read_abilities + genphy_read_mmd_unsupported + genphy_read_status genphy_resume + genphy_suspend + genphy_write_mmd_unsupported gen_pool_add_owner gen_pool_alloc_algo_owner gen_pool_avail @@ -835,6 +848,7 @@ get_kernel_pages get_net_ns_by_fd get_net_ns_by_pid + get_pelt_halflife get_pid_task get_random_bytes get_random_u32 @@ -957,11 +971,13 @@ init_uts_ns init_wait_entry __init_waitqueue_head + input_alloc_absinfo input_allocate_device input_event input_free_device input_mt_init_slots input_mt_report_slot_state + input_mt_sync_frame input_register_device input_set_abs_params input_set_capability @@ -1169,8 +1185,12 @@ mbox_send_message mdiobus_alloc_size mdiobus_free + __mdiobus_read + mdiobus_read __mdiobus_register mdiobus_unregister + __mdiobus_write + mdiobus_write media_create_intf_link media_create_pad_link media_device_cleanup @@ -1270,10 +1290,12 @@ mutex_lock_killable mutex_trylock mutex_unlock + napi_complete_done napi_disable napi_gro_flush napi_gro_receive __napi_schedule + __napi_schedule_irqoff napi_schedule_prep __ndelay nd_tbl @@ -1292,6 +1314,7 @@ netif_receive_skb_list netif_rx netif_rx_ni + netif_schedule_queue netif_tx_stop_all_queues netif_tx_wake_queue netlink_broadcast @@ -1372,6 +1395,7 @@ of_get_next_child of_get_next_parent of_get_parent + of_get_phy_mode of_get_property of_get_regulator_init_data of_graph_get_next_endpoint @@ -1392,6 +1416,7 @@ of_parse_phandle_with_fixed_args of_phandle_iterator_init of_phandle_iterator_next + of_phy_connect of_phy_simple_xlate of_platform_depopulate of_platform_device_create @@ -1459,19 +1484,29 @@ phy_connect phy_disconnect phy_do_ioctl_running + phy_drivers_register + phy_drivers_unregister phy_ethtool_get_link_ksettings phy_ethtool_nway_reset phy_ethtool_set_link_ksettings phy_exit phy_get phy_init + phy_mii_ioctl + __phy_modify + phy_modify + phy_modify_paged_changed phy_power_off phy_power_on phy_print_status phy_put + phy_read_paged + phy_restore_page + phy_select_page phy_set_mode_ext phy_start phy_stop + phy_write_paged pid_task pinconf_generic_parse_dt_config pinctrl_dev_get_drvdata @@ -1660,6 +1695,7 @@ regmap_raw_read regmap_raw_write regmap_read + regmap_test_bits regmap_update_bits_base regmap_write regulator_count_voltages @@ -2091,6 +2127,8 @@ timer_unstable_counter_workaround topology_set_thermal_pressure _totalram_pages + touchscreen_parse_properties + touchscreen_report_pos __trace_bprintk __trace_bputs trace_event_buffer_commit @@ -2153,6 +2191,7 @@ __traceiter_android_vh_rwsem_init __traceiter_android_vh_rwsem_wake __traceiter_android_vh_rwsem_write_finished + __traceiter_android_vh_sched_pelt_multiplier __traceiter_android_vh_scheduler_tick __traceiter_android_vh_selinux_avc_insert __traceiter_android_vh_selinux_avc_lookup @@ -2237,6 +2276,7 @@ __tracepoint_android_vh_rwsem_init __tracepoint_android_vh_rwsem_wake __tracepoint_android_vh_rwsem_write_finished + __tracepoint_android_vh_sched_pelt_multiplier __tracepoint_android_vh_scheduler_tick __tracepoint_android_vh_selinux_avc_insert __tracepoint_android_vh_selinux_avc_lookup @@ -2790,10 +2830,13 @@ fwnode_graph_parse_endpoint fwnode_property_get_reference_args fwnode_property_read_u64_array + gen_pool_avail gen_pool_dma_alloc_align gen_pool_has_addr + gen_pool_size getboottime64 get_governor_parent_kobj + get_pelt_halflife get_task_exe_file get_vaddr_frames get_zeroed_page @@ -3070,6 +3113,7 @@ __traceiter_android_vh_rwsem_init __traceiter_android_vh_rwsem_wake __traceiter_android_vh_rwsem_write_finished + __traceiter_android_vh_sched_pelt_multiplier __traceiter_android_vh_scmi_timeout_sync __traceiter_android_vh_show_resume_epoch_val __traceiter_android_vh_show_suspend_epoch_val @@ -3123,6 +3167,7 @@ __tracepoint_android_vh_rwsem_init __tracepoint_android_vh_rwsem_wake __tracepoint_android_vh_rwsem_write_finished + __tracepoint_android_vh_sched_pelt_multiplier __tracepoint_android_vh_scmi_timeout_sync __tracepoint_android_vh_show_resume_epoch_val __tracepoint_android_vh_show_suspend_epoch_val @@ -3193,6 +3238,7 @@ usb_otg_state_string usb_phy_set_charger_current usb_remove_phy + usb_role_switch_set_role v4l2_async_notifier_add_subdev v4l2_async_notifier_cleanup v4l2_async_subdev_notifier_register diff --git a/android/abi_gki_aarch64_oplus b/android/abi_gki_aarch64_oplus index 5b208407c2a5..4f25e9accef0 100644 --- a/android/abi_gki_aarch64_oplus +++ b/android/abi_gki_aarch64_oplus @@ -681,6 +681,7 @@ dma_unmap_sg_attrs do_exit do_wait_intr_irq + do_traversal_all_lruvec down down_interruptible down_read @@ -1802,10 +1803,12 @@ page_endio __page_file_index __page_file_mapping + __page_mapcount page_get_link page_mapping __page_pinner_migration_failed page_symlink + page_to_lruvec panic panic_notifier_list panic_timeout @@ -2802,6 +2805,7 @@ __traceiter_android_vh_ipi_stop __traceiter_android_vh_ipv6_gen_linklocal_addr __traceiter_android_vh_jiffies_update + __traceiter_android_vh_killed_process __traceiter_android_vh_kmalloc_slab __traceiter_android_vh_logbuf __traceiter_android_vh_mem_cgroup_alloc @@ -2810,19 +2814,33 @@ __traceiter_android_vh_mem_cgroup_free __traceiter_android_vh_mem_cgroup_id_remove __traceiter_android_vh_meminfo_proc_show + __traceiter_android_vh_alloc_pages_slowpath_begin + __traceiter_android_vh_alloc_pages_slowpath_end __traceiter_android_vh_mutex_unlock_slowpath + __traceiter_android_vh_mutex_unlock_slowpath_end __traceiter_android_vh_mutex_wait_finish __traceiter_android_vh_mutex_wait_start __traceiter_android_vh_override_creds __traceiter_android_vh_page_referenced_check_bypass + __traceiter_android_vh_page_should_be_protected + __traceiter_android_vh_mark_page_accessed + __traceiter_android_vh_show_mapcount_pages + __traceiter_android_vh_do_traversal_lruvec + __traceiter_android_vh_update_page_mapcount + __traceiter_android_vh_add_page_to_lrulist + __traceiter_android_vh_del_page_from_lrulist __traceiter_android_vh_pcplist_add_cma_pages_bypass __traceiter_android_vh_prepare_update_load_avg_se __traceiter_android_vh_printk_hotplug __traceiter_android_vh_process_killed - __traceiter_android_vh_killed_process __traceiter_android_vh_revert_creds __traceiter_android_vh_rmqueue __traceiter_android_vh_rwsem_init + __traceiter_android_vh_rwsem_mark_wake_readers + __traceiter_android_vh_rwsem_set_owner + __traceiter_android_vh_rwsem_set_reader_owned + __traceiter_android_vh_rwsem_up_read_end + __traceiter_android_vh_rwsem_up_write_end __traceiter_android_vh_rwsem_wake __traceiter_android_vh_rwsem_wake_finish __traceiter_android_vh_rwsem_write_finished @@ -3010,6 +3028,7 @@ __tracepoint_android_vh_ipi_stop __tracepoint_android_vh_ipv6_gen_linklocal_addr __tracepoint_android_vh_jiffies_update + __tracepoint_android_vh_killed_process __tracepoint_android_vh_kmalloc_slab __tracepoint_android_vh_logbuf __tracepoint_android_vh_mem_cgroup_alloc @@ -3018,19 +3037,33 @@ __tracepoint_android_vh_mem_cgroup_free __tracepoint_android_vh_mem_cgroup_id_remove __tracepoint_android_vh_meminfo_proc_show + __tracepoint_android_vh_alloc_pages_slowpath_begin + __tracepoint_android_vh_alloc_pages_slowpath_end __tracepoint_android_vh_mutex_unlock_slowpath + __tracepoint_android_vh_mutex_unlock_slowpath_end __tracepoint_android_vh_mutex_wait_finish __tracepoint_android_vh_mutex_wait_start __tracepoint_android_vh_override_creds __tracepoint_android_vh_page_referenced_check_bypass + __tracepoint_android_vh_page_should_be_protected + __tracepoint_android_vh_mark_page_accessed + __tracepoint_android_vh_show_mapcount_pages + __tracepoint_android_vh_do_traversal_lruvec + __tracepoint_android_vh_update_page_mapcount + __tracepoint_android_vh_add_page_to_lrulist + __tracepoint_android_vh_del_page_from_lrulist __tracepoint_android_vh_pcplist_add_cma_pages_bypass __tracepoint_android_vh_prepare_update_load_avg_se __tracepoint_android_vh_printk_hotplug __tracepoint_android_vh_process_killed - __tracepoint_android_vh_killed_process __tracepoint_android_vh_revert_creds __tracepoint_android_vh_rmqueue __tracepoint_android_vh_rwsem_init + __tracepoint_android_vh_rwsem_mark_wake_readers + __tracepoint_android_vh_rwsem_set_owner + __tracepoint_android_vh_rwsem_set_reader_owned + __tracepoint_android_vh_rwsem_up_read_end + __tracepoint_android_vh_rwsem_up_write_end __tracepoint_android_vh_rwsem_wake __tracepoint_android_vh_rwsem_wake_finish __tracepoint_android_vh_rwsem_write_finished diff --git a/android/abi_gki_aarch64_rockchip b/android/abi_gki_aarch64_rockchip index f048bf0063f0..2bee0c4c5eb8 100644 --- a/android/abi_gki_aarch64_rockchip +++ b/android/abi_gki_aarch64_rockchip @@ -6,7 +6,9 @@ alloc_chrdev_region __alloc_disk_node __alloc_pages_nodemask + __alloc_skb alloc_workqueue + anon_inode_getfd __arch_copy_from_user __arch_copy_to_user arm64_const_caps_ready @@ -15,9 +17,11 @@ atomic_notifier_call_chain atomic_notifier_chain_register atomic_notifier_chain_unregister + _bcd2bin + bcmp bdget_disk bdput - __bitmap_set + _bin2bcd blk_cleanup_queue blk_execute_rq_nowait blk_mq_free_request @@ -36,25 +40,58 @@ blk_queue_physical_block_size blk_rq_map_user blk_rq_unmap_user + blocking_notifier_call_chain + blocking_notifier_chain_register + blocking_notifier_chain_unregister + bpf_trace_run1 + bpf_trace_run2 + bpf_trace_run3 + bpf_trace_run4 + bpf_trace_run5 + bpf_trace_run6 + bpf_trace_run7 + bus_find_device + bus_register + bus_set_iommu + bus_unregister + cancel_delayed_work cancel_delayed_work_sync cancel_work_sync + cdev_add + cdev_del cdev_device_add cdev_device_del cdev_init + cec_allocate_adapter + cec_delete_adapter + cec_fill_conn_info_from_drm + cec_notifier_cec_adap_register + cec_notifier_cec_adap_unregister + cec_notifier_conn_register + cec_notifier_conn_unregister + cec_notifier_set_phys_addr + cec_notifier_set_phys_addr_from_edid + cec_queue_pin_hpd_event + cec_received_msg_ts + cec_register_adapter + cec_transmit_attempt_done_ts + cec_unregister_adapter __cfi_slowpath __check_object_size __class_create class_destroy class_for_each_device + __class_register + class_unregister clk_bulk_disable clk_bulk_enable clk_bulk_prepare clk_bulk_unprepare clk_disable clk_enable + clk_gate_ops clk_get __clk_get_name - clk_get_parent clk_get_rate clk_hw_get_flags clk_hw_get_name @@ -67,6 +104,7 @@ clk_put clk_register clk_round_rate + clk_set_parent clk_set_phase clk_set_rate clk_unprepare @@ -77,6 +115,7 @@ complete completion_done __const_udelay + consume_skb __cpufreq_driver_target cpufreq_generic_suspend cpufreq_register_governor @@ -87,12 +126,26 @@ __cpuhp_setup_state cpu_hwcap_keys cpu_hwcaps + cpu_latency_qos_add_request + cpu_latency_qos_update_request cpumask_next cpu_number __cpu_online_mask __cpu_possible_mask cpus_read_lock cpus_read_unlock + crc16 + crc32_le + crypto_aead_decrypt + crypto_aead_encrypt + crypto_aead_setauthsize + crypto_aead_setkey + crypto_ahash_setkey + crypto_alloc_aead + crypto_alloc_ahash + crypto_alloc_shash + crypto_alloc_skcipher + crypto_cipher_encrypt_one crypto_destroy_tfm crypto_inc __crypto_memneq @@ -100,39 +153,66 @@ crypto_register_alg crypto_register_scomp crypto_register_shash + crypto_register_template + crypto_shash_update + crypto_skcipher_decrypt + crypto_skcipher_encrypt + crypto_skcipher_setkey crypto_unregister_aead crypto_unregister_alg crypto_unregister_scomp crypto_unregister_shash + crypto_unregister_template __crypto_xor + debugfs_attr_read + debugfs_attr_write debugfs_create_dir debugfs_create_file debugfs_create_regset32 debugfs_remove + default_llseek delayed_work_timer_fn del_gendisk del_timer del_timer_sync desc_to_gpio destroy_workqueue + dev_close dev_driver_string _dev_err dev_err_probe + devfreq_add_governor devfreq_recommended_opp + devfreq_register_opp_notifier + devfreq_resume_device + devfreq_suspend_device + devfreq_unregister_opp_notifier dev_fwnode + device_add device_add_disk device_create + device_create_file + device_del device_destroy device_get_child_node_count + device_get_named_child_node device_get_next_child_node device_initialize device_init_wakeup device_link_add device_link_del + device_match_name device_property_present device_property_read_string device_property_read_u32_array + device_property_read_u8_array + device_release_driver + device_remove_file + device_set_wakeup_capable + device_set_wakeup_enable + device_wakeup_enable _dev_info + __dev_kfree_skb_any devm_add_action devm_clk_bulk_get devm_clk_bulk_get_all @@ -154,6 +234,10 @@ devm_gpiod_get_index_optional devm_gpiod_get_optional devm_gpio_request + devm_gpio_request_one + devm_iio_channel_get + devm_iio_device_alloc + __devm_iio_device_register devm_input_allocate_device devm_ioremap devm_ioremap_resource @@ -165,9 +249,11 @@ devm_mfd_add_devices devm_nvmem_register devm_of_clk_add_hw_provider + devm_of_phy_get __devm_of_phy_provider_register devm_phy_create devm_phy_get + devm_phy_optional_get devm_pinctrl_get devm_pinctrl_register devm_platform_get_and_ioremap_resource @@ -183,42 +269,71 @@ devm_regulator_get devm_regulator_get_optional devm_regulator_register + devm_remove_action devm_request_threaded_irq devm_reset_control_array_get __devm_reset_control_get devm_snd_dmaengine_pcm_register + devm_snd_soc_register_card devm_snd_soc_register_component + devm_usb_get_phy + _dev_notice + dev_pm_domain_detach dev_pm_opp_find_freq_ceil + dev_pm_opp_find_freq_floor dev_pm_opp_get_opp_count + dev_pm_opp_get_opp_table dev_pm_opp_get_voltage dev_pm_opp_of_get_sharing_cpus + dev_pm_opp_of_remove_table dev_pm_opp_put - dev_pm_opp_remove + dev_pm_opp_put_opp_table + dev_pm_opp_put_regulators + dev_pm_opp_register_set_opp_helper + dev_pm_opp_set_rate + dev_pm_opp_set_regulators + dev_pm_opp_unregister_set_opp_helper + dev_printk devres_add devres_alloc_node devres_free dev_set_name _dev_warn disable_irq + disable_irq_nosync dma_alloc_attrs dma_buf_attach + dma_buf_begin_cpu_access dma_buf_detach + dma_buf_end_cpu_access dma_buf_export dma_buf_fd + dma_buf_get dma_buf_map_attachment + dma_buf_mmap dma_buf_put dma_buf_unmap_attachment dma_buf_vmap dma_buf_vunmap + dma_fence_context_alloc + dma_fence_init + dma_fence_release + dma_fence_signal dma_free_attrs dma_get_sgtable_attrs dma_heap_add + dma_heap_get_dev dma_heap_get_name dmam_alloc_attrs dma_map_page_attrs + dma_map_resource dma_map_sg_attrs dmam_free_coherent dma_mmap_attrs + dma_pool_alloc + dma_pool_create + dma_pool_destroy + dma_pool_free dma_release_channel dma_request_chan dma_set_coherent_mask @@ -228,9 +343,11 @@ dma_sync_single_for_cpu dma_sync_single_for_device dma_unmap_page_attrs + dma_unmap_resource dma_unmap_sg_attrs down_read down_write + driver_register driver_unregister drm_add_edid_modes drm_atomic_get_crtc_state @@ -243,12 +360,16 @@ drm_atomic_helper_connector_reset drm_bridge_add drm_bridge_attach + drm_bridge_detect + drm_bridge_get_modes + drm_bridge_hpd_notify drm_bridge_remove drm_compat_ioctl drm_connector_attach_encoder drm_connector_cleanup drm_connector_init drm_connector_init_with_ddc + drm_connector_unregister drm_connector_update_edid_property __drm_dbg drm_detect_hdmi_monitor @@ -260,9 +381,22 @@ drm_dev_register drm_dev_unregister drm_display_info_set_bus_formats + drm_display_mode_from_videomode + drm_display_mode_to_videomode + drm_dp_aux_register + drm_dp_aux_unregister drm_dp_bw_code_to_link_rate + drm_dp_dpcd_read + drm_dp_dpcd_write + drm_dp_get_phy_test_pattern + drm_dp_link_rate_to_bw_code + drm_dp_link_train_channel_eq_delay + drm_dp_link_train_clock_recovery_delay + drm_dp_read_dpcd_caps + drm_dp_set_phy_test_pattern __drm_err drm_gem_dumb_map_offset + drm_gem_get_pages drm_gem_handle_create drm_gem_mmap drm_gem_mmap_obj @@ -272,59 +406,97 @@ drm_gem_object_release drm_gem_prime_fd_to_handle drm_gem_prime_handle_to_fd + drm_gem_put_pages drm_gem_vm_close drm_get_edid drm_hdmi_avi_infoframe_from_display_mode + drm_hdmi_avi_infoframe_quant_range + drm_hdmi_infoframe_set_hdr_metadata drm_hdmi_vendor_infoframe_from_display_mode drm_helper_hpd_irq_event drm_helper_probe_single_connector_modes drm_ioctl + drm_kms_helper_hotplug_event drm_match_cea_mode drm_mode_copy drm_mode_create drm_mode_duplicate + drm_mode_is_420_also + drm_mode_is_420_only drm_mode_probed_add + drm_modeset_acquire_fini + drm_modeset_acquire_init + drm_modeset_backoff + drm_modeset_drop_locks + drm_modeset_lock drm_mode_set_name + drm_mode_validate_driver drm_mode_vrefresh drm_object_attach_property drm_of_find_panel_or_bridge drm_open + drm_panel_add drm_panel_disable drm_panel_enable drm_panel_get_modes + drm_panel_init drm_panel_prepare drm_panel_unprepare drm_poll - drm_prime_gem_destroy drm_prime_pages_to_sg drm_prime_sg_to_page_addr_arrays + drm_property_replace_global_blob drm_read drm_release - dummy_irq_chip + drm_scdc_read + drm_scdc_set_high_tmds_clock_ratio + drm_scdc_set_scrambling + drm_scdc_write enable_irq + eth_mac_addr + eth_platform_get_mac_address + eth_type_trans + eth_validate_addr + event_triggers_call extcon_get_edev_by_phandle extcon_get_state extcon_register_notifier + extcon_set_property_capability extcon_set_state_sync extcon_unregister_notifier failure_tracking + fd_install find_next_bit find_next_zero_bit + find_vma finish_wait + flush_dcache_page flush_delayed_work flush_work flush_workqueue fpsimd_context_busy + fput frame_vector_to_pages free_irq __free_pages free_pages + free_percpu + freq_qos_add_request + freq_qos_remove_request + freq_qos_update_request + fwnode_get_name fwnode_handle_put fwnode_property_present fwnode_property_read_string fwnode_property_read_u32_array gcd generic_handle_irq + generic_mii_ioctl + __genphy_config_aneg + genphy_read_status + genphy_resume + genphy_soft_reset + genphy_suspend gen_pool_add_owner gen_pool_alloc_algo_owner gen_pool_create @@ -332,6 +504,10 @@ gen_pool_free_owner get_cpu_device get_device + __get_free_pages + get_random_bytes + get_unused_fd_flags + get_zeroed_page gic_nonsecure_priorities gpiochip_add_pin_range gpiochip_generic_free @@ -340,17 +516,24 @@ gpiod_cansleep gpiod_direction_input gpiod_direction_output + gpiod_direction_output_raw gpiod_get_optional gpiod_get_raw_value gpiod_get_value gpiod_get_value_cansleep gpiod_set_consumer_name + gpiod_set_raw_value gpiod_set_value gpiod_set_value_cansleep gpiod_to_irq gpio_to_desc handle_nested_irq handle_simple_irq + hdmi_audio_infoframe_init + hdmi_audio_infoframe_pack + hdmi_drm_infoframe_pack + hdmi_infoframe_pack + hdmi_vendor_infoframe_pack hid_debug hid_hw_close hid_hw_open @@ -361,6 +544,10 @@ __hid_request hid_unregister_driver hid_validate_values + hrtimer_cancel + hrtimer_forward + hrtimer_init + hrtimer_start_range_ns i2c_adapter_type i2c_add_adapter i2c_del_adapter @@ -369,6 +556,9 @@ i2c_put_adapter i2c_register_driver i2c_smbus_read_byte_data + i2c_smbus_read_i2c_block_data + i2c_smbus_write_byte_data + i2c_smbus_write_i2c_block_data __i2c_smbus_xfer i2c_smbus_xfer i2c_transfer @@ -376,22 +566,43 @@ idr_alloc idr_destroy idr_find + idr_for_each + idr_get_next idr_preload idr_remove iio_buffer_init iio_buffer_put + iio_device_attach_buffer + iio_push_to_buffers + iio_read_channel_processed __init_rwsem __init_swait_queue_head init_timer_key init_wait_entry __init_waitqueue_head + input_allocate_device input_event input_ff_create_memless + input_free_device + input_mt_init_slots + input_mt_report_slot_state input_register_device input_set_abs_params + input_set_capability iommu_attach_device iommu_detach_device + iommu_device_register + iommu_device_sysfs_add + iommu_device_sysfs_remove + iommu_get_dma_cookie iommu_get_domain_for_dev + iommu_group_alloc + iommu_group_put + iommu_group_ref_get + iommu_map + iommu_put_dma_cookie + iommu_set_fault_handler + iommu_unmap __ioremap iounmap irq_create_mapping_affinity @@ -400,6 +611,8 @@ irq_find_mapping irq_get_irq_data irq_modify_status + irq_of_parse_and_map + irq_set_affinity_hint irq_set_chained_handler_and_data irq_set_chip irq_set_chip_and_handler_name @@ -419,22 +632,36 @@ __kfifo_out kfree kfree_const + kfree_sensitive + kfree_skb + kimage_voffset __kmalloc kmalloc_caches + kmalloc_order_trace kmem_cache_alloc kmem_cache_alloc_trace kmem_cache_create kmem_cache_destroy kmem_cache_free kmemdup + kobject_create_and_add + kobject_put + kobject_uevent_env + kstrdup kstrdup_const kstrtoint kstrtouint + kstrtouint_from_user kstrtoull + kthread_create_on_node + kthread_should_stop + kthread_stop ktime_get ktime_get_mono_fast_ns + ktime_get_real_ts64 ktime_get_with_offset kvfree + kvfree_call_rcu kvmalloc_node led_classdev_register_ext led_classdev_unregister @@ -447,6 +674,8 @@ __log_read_mmio __log_write_mmio lzo1x_decompress_safe + mdiobus_read + mdiobus_write media_create_pad_link media_device_init __media_device_register @@ -461,24 +690,47 @@ media_pipeline_stop memcpy memdup_user + memmove memset memstart_addr + mfd_add_devices mfd_remove_devices + mii_check_media + mii_ethtool_gset + mii_nway_restart + mipi_dsi_attach + mipi_dsi_create_packet + mipi_dsi_detach + mipi_dsi_host_register + mipi_dsi_host_unregister + misc_deregister + misc_register mmc_of_parse mod_delayed_work_on mod_timer + __module_get module_layout module_put __msecs_to_jiffies msleep + msleep_interruptible __mutex_init mutex_is_locked mutex_lock + mutex_lock_interruptible + mutex_trylock mutex_unlock + __netdev_alloc_skb + netdev_err + netdev_info + netdev_warn no_llseek + nonseekable_open noop_llseek nr_cpu_ids + ns_to_kernel_old_timeval ns_to_timespec64 + nvmem_cell_get nvmem_cell_put nvmem_cell_read of_address_to_resource @@ -487,6 +739,8 @@ of_clk_del_provider of_clk_get of_clk_get_by_name + of_clk_get_parent_count + of_clk_set_defaults of_clk_src_onecell_get of_clk_src_simple_get of_count_phandle_with_args @@ -494,17 +748,27 @@ of_device_get_match_data of_device_is_available of_device_is_compatible + of_drm_find_bridge + of_find_compatible_node of_find_device_by_node + of_find_i2c_device_by_node + of_find_matching_node_and_match of_find_node_by_name + of_find_node_opts_by_path of_find_property of_get_child_by_name + of_get_compatible_child + of_get_drm_display_mode + of_get_i2c_adapter_by_node of_get_named_gpio_flags of_get_next_available_child of_get_next_child of_get_parent of_get_property of_get_regulator_init_data + of_graph_get_next_endpoint of_graph_get_remote_node + of_graph_get_remote_port_parent of_graph_parse_endpoint of_iomap of_irq_get_byname @@ -514,26 +778,37 @@ of_node_name_eq of_nvmem_cell_get of_parse_phandle + of_parse_phandle_with_args of_phy_simple_xlate of_property_count_elems_of_size of_property_match_string of_property_read_string of_property_read_string_helper of_property_read_u32_index + of_property_read_u64 of_property_read_variable_u32_array + of_property_read_variable_u8_array of_regulator_match of_reserved_mem_device_init_by_idx + __of_reset_control_get of_usb_get_dr_mode_by_phy __page_pinner_migration_failed panic_notifier_list + param_array_ops param_ops_bool + param_ops_byte + param_ops_charp param_ops_int param_ops_string param_ops_uint PDE_DATA __per_cpu_offset + perf_trace_buf_alloc + perf_trace_run_bpf_submit pfn_valid phy_configure + phy_drivers_register + phy_drivers_unregister phy_exit phy_init phy_power_off @@ -559,6 +834,9 @@ platform_get_irq_byname platform_get_resource platform_get_resource_byname + platform_irq_count + pm_clk_create + pm_clk_destroy pm_power_off __pm_relax __pm_runtime_disable @@ -574,15 +852,27 @@ __pm_runtime_use_autosuspend __pm_stay_awake pm_wakeup_ws_event + power_supply_am_i_supplied power_supply_changed power_supply_class + power_supply_get_battery_info + power_supply_get_by_phandle power_supply_get_drvdata + power_supply_get_property + power_supply_put_battery_info + power_supply_register + power_supply_reg_notifier + power_supply_unregister preempt_schedule preempt_schedule_notrace prepare_to_wait_event print_hex_dump printk + proc_create proc_create_data + proc_mkdir + pskb_expand_head + __pskb_pull_tail put_device put_disk __put_page @@ -601,6 +891,11 @@ _raw_spin_unlock_bh _raw_spin_unlock_irq _raw_spin_unlock_irqrestore + rb_erase + rb_insert_color + rb_next + __rcu_read_lock + __rcu_read_unlock rdev_get_drvdata rdev_get_id refcount_warn_saturate @@ -609,13 +904,18 @@ regcache_sync __register_chrdev register_chrdev_region + register_netdevice_notifier + register_pm_notifier register_reboot_notifier + register_shrinker regmap_bulk_read regmap_bulk_write regmap_field_read regmap_field_update_bits_base regmap_irq_get_domain regmap_irq_get_virq + regmap_multi_reg_write + regmap_raw_read regmap_raw_write regmap_read regmap_update_bits_base @@ -626,6 +926,8 @@ regulator_disable_regmap regulator_enable regulator_enable_regmap + regulator_get + regulator_get_optional regulator_get_voltage regulator_get_voltage_sel_regmap regulator_is_enabled @@ -634,19 +936,33 @@ regulator_list_voltage_linear_range regulator_map_voltage_linear regulator_map_voltage_linear_range + regulator_put regulator_set_voltage regulator_set_voltage_sel_regmap regulator_set_voltage_time_sel + regulator_unregister + release_firmware remap_pfn_range remove_proc_entry + report_iommu_fault + request_firmware request_threaded_irq reset_control_assert reset_control_deassert revalidate_disk_size + rfkill_alloc + rfkill_destroy + rfkill_register + rfkill_set_hw_state + rfkill_unregister + round_jiffies_relative rtc_class_open rtc_read_time rtc_tm_to_time64 rtc_valid_tm + rtnl_is_locked + rtnl_lock + rtnl_unlock scatterwalk_map_and_copy sched_clock schedule @@ -670,36 +986,73 @@ sdhci_suspend_host seq_lseek seq_printf + seq_putc seq_puts seq_read set_page_dirty_lock sg_alloc_table sg_alloc_table_from_pages sg_free_table + sg_init_one + sg_init_table + sg_nents sg_next + __sg_page_iter_next + __sg_page_iter_start + simple_attr_open + simple_attr_release + simple_read_from_buffer simple_strtol single_open single_release + skb_clone + skb_copy_bits + skb_copy_expand + skb_pull + skb_push + skb_put + skb_trim + skcipher_alloc_instance_simple + skcipher_register_instance skcipher_walk_aead_decrypt skcipher_walk_aead_encrypt skcipher_walk_done + skcipher_walk_virt snd_pcm_format_width + snd_soc_add_component_controls + snd_soc_card_jack_new snd_soc_component_read + snd_soc_component_set_jack snd_soc_component_update_bits snd_soc_component_write + snd_soc_dai_set_sysclk + snd_soc_dapm_add_routes + snd_soc_dapm_disable_pin_unlocked snd_soc_dapm_force_enable_pin_unlocked snd_soc_dapm_get_enum_double + snd_soc_dapm_get_pin_switch snd_soc_dapm_get_volsw + snd_soc_dapm_info_pin_switch + snd_soc_dapm_new_controls snd_soc_dapm_put_enum_double + snd_soc_dapm_put_pin_switch snd_soc_dapm_put_volsw + snd_soc_dapm_sync_unlocked + snd_soc_get_dai_name snd_soc_get_enum_double snd_soc_get_volsw snd_soc_info_enum_double snd_soc_info_volsw snd_soc_jack_add_gpios snd_soc_jack_report + snd_soc_of_parse_audio_routing + snd_soc_of_parse_card_name + snd_soc_of_parse_daifmt + snd_soc_params_to_frame_size + snd_soc_pm_ops snd_soc_put_enum_double snd_soc_put_volsw + snd_soc_unregister_component snprintf __spi_register_driver spi_sync @@ -708,73 +1061,180 @@ __stack_chk_fail __stack_chk_guard strcmp + strcpy strlcpy strlen + strncasecmp strncmp strncpy strnlen strscpy strstr + __sw_hweight16 + __sw_hweight32 + __sw_hweight64 + __sw_hweight8 + sync_file_create synchronize_irq + synchronize_rcu syscon_node_to_regmap syscon_regmap_lookup_by_phandle sysfs_create_file_ns sysfs_create_group sysfs_create_link __sysfs_match_string + sysfs_remove_file_ns sysfs_remove_group sysfs_remove_link + sysfs_streq + system_freezable_wq + system_long_wq + system_power_efficient_wq + system_state system_unbound_wq system_wq tasklet_init tasklet_kill __tasklet_schedule + tcpm_tcpc_reset thermal_zone_get_zone_by_name + trace_event_buffer_commit + trace_event_buffer_reserve + trace_event_ignore_this_pid + trace_event_raw_init + trace_event_reg + trace_handle_return __traceiter_rwmmio_post_read __traceiter_rwmmio_read __traceiter_rwmmio_write __tracepoint_rwmmio_post_read __tracepoint_rwmmio_read __tracepoint_rwmmio_write + trace_print_array_seq + trace_print_symbols_seq + trace_raw_output_prep + trace_seq_printf + try_module_get + tty_termios_baud_rate + typec_switch_get_drvdata + typec_switch_register + typec_switch_unregister + __udelay __unregister_chrdev unregister_chrdev_region + unregister_netdevice_notifier unregister_reboot_notifier + unregister_shrinker + up update_devfreq up_read up_write + usb_add_hcd + usb_alloc_urb + usb_autopm_get_interface + usb_autopm_put_interface + usb_calc_bus_time + usb_control_msg + usb_create_hcd usb_debug_root + usb_deregister + usb_deregister_dev + usb_disabled + usb_free_urb + usb_get_dev + usb_get_intf + usb_hcd_check_unlink_urb + usb_hcd_giveback_urb + usb_hcd_link_urb_to_ep + usb_hcd_resume_root_hub + usb_hcd_unlink_urb_from_ep + usb_hid_driver + usb_match_id + usbnet_change_mtu + usbnet_defer_kevent + usbnet_disconnect + usbnet_get_drvinfo + usbnet_get_endpoints + usbnet_get_link + usbnet_get_link_ksettings + usbnet_get_msglevel + usbnet_get_stats64 + usbnet_link_change + usbnet_nway_reset + usbnet_open + usbnet_probe + usbnet_read_cmd + usbnet_read_cmd_nopm + usbnet_resume + usbnet_set_link_ksettings + usbnet_set_msglevel + usbnet_skb_return + usbnet_start_xmit + usbnet_stop + usbnet_suspend + usbnet_tx_timeout + usbnet_write_cmd + usbnet_write_cmd_async + usbnet_write_cmd_nopm + usb_poison_urb + usb_put_dev + usb_put_hcd + usb_put_intf + usb_register_dev + usb_register_driver + usb_remove_hcd + usb_set_interface + usb_submit_urb + usb_unpoison_urb + __usecs_to_jiffies usleep_range uuid_null v4l2_async_notifier_cleanup v4l2_async_notifier_init v4l2_async_notifier_register + v4l2_async_notifier_unregister v4l2_async_register_subdev v4l2_async_subdev_notifier_register v4l2_async_unregister_subdev v4l2_ctrl_find v4l2_ctrl_g_ctrl + v4l2_ctrl_g_ctrl_int64 v4l2_ctrl_handler_free v4l2_ctrl_handler_init_class + __v4l2_ctrl_handler_setup v4l2_ctrl_handler_setup + __v4l2_ctrl_modify_range + v4l2_ctrl_new_custom + v4l2_ctrl_new_int_menu v4l2_ctrl_new_std + v4l2_ctrl_new_std_menu v4l2_ctrl_new_std_menu_items + __v4l2_ctrl_s_ctrl + __v4l2_ctrl_s_ctrl_int64 + v4l2_ctrl_subdev_subscribe_event v4l2_device_register v4l2_device_register_subdev __v4l2_device_register_subdev_nodes v4l2_device_unregister v4l2_device_unregister_subdev + v4l2_enum_dv_timings_cap v4l2_event_queue v4l2_event_subdev_unsubscribe v4l2_event_subscribe v4l2_fh_open v4l2_i2c_subdev_init + v4l2_match_dv_timings v4l2_pipeline_pm_get v4l2_pipeline_pm_put + v4l2_print_dv_timings v4l2_querymenu + v4l2_src_change_event_subdev_subscribe v4l2_subdev_call_wrappers v4l2_subdev_init v4l2_subdev_link_validate + v4l2_subdev_notify_event v4l2_type_names + v4l2_valid_dv_timings vabits_actual vb2_buffer_done vb2_common_vm_ops @@ -813,10 +1273,13 @@ vm_map_ram vm_unmap_ram vunmap + vzalloc wait_for_completion wait_for_completion_timeout __wake_up + wake_up_process wakeup_source_add + wakeup_source_remove __warn_printk # required by 8250_dw.ko @@ -833,15 +1296,12 @@ serial8250_suspend_port serial8250_unregister_port serial8250_update_uartclk - tty_termios_baud_rate # required by act8865-regulator.ko regulator_set_pull_down_regmap # required by adc-keys.ko - devm_iio_channel_get iio_get_channel_type - iio_read_channel_processed input_set_poll_interval input_setup_polling @@ -849,20 +1309,160 @@ ce_aes_expandkey # required by analogix_dp.ko - drm_dp_aux_register - drm_dp_aux_unregister - drm_dp_dpcd_read - drm_dp_dpcd_write drm_dp_start_crc drm_dp_stop_crc +# required by bifrost_kbase.ko + __arch_clear_user + __bitmap_andnot + __bitmap_equal + __bitmap_or + __bitmap_weight + cache_line_size + clear_page + complete_all + debugfs_create_bool + devfreq_add_device + devfreq_cooling_unregister + devfreq_remove_device + dev_pm_opp_find_freq_exact + dma_fence_add_callback + dma_fence_default_wait + dma_fence_get_status + dma_fence_remove_callback + downgrade_write + down_read_trylock + dump_stack + find_get_pid + freezing_slow_path + generic_file_llseek + get_user_pages + get_user_pages_fast + hrtimer_active + iomem_resource + kobject_del + kobject_init_and_add + kstrndup + kstrtobool_from_user + ktime_get_raw + ktime_get_raw_ts64 + memchr + __mmdrop + of_dma_is_coherent + of_property_read_variable_u64_array + pid_task + pin_user_pages + pin_user_pages_remote + put_pid + rb_first + rb_prev + rb_replace_node + __refrigerator + register_oom_notifier + __release_region + remap_vmalloc_range + __request_region + seq_open + __seq_open_private + seq_release + seq_release_private + seq_write + set_freezable + shmem_file_setup + simple_open + strcspn + sync_file_get_fence + system_freezing_cnt + system_highpri_wq + _totalram_pages + __traceiter_gpu_mem_total + trace_output_call + __tracepoint_gpu_mem_total + trace_print_flags_seq + unmap_mapping_range + unpin_user_page + unregister_oom_notifier + vmalloc_user + vmf_insert_pfn_prot + +# required by bq25700_charger.ko + power_supply_get_by_name + +# required by cdc-wdm.ko + cdc_parse_cdc_header + +# required by cdc_mbim.ko + cdc_ncm_bind_common + cdc_ncm_change_mtu + cdc_ncm_fill_tx_frame + cdc_ncm_rx_verify_ndp16 + cdc_ncm_rx_verify_nth16 + cdc_ncm_select_altsetting + cdc_ncm_unbind + in6_dev_finish_destroy + __ipv6_addr_type + ipv6_stub + +# required by cfg80211.ko + bpf_trace_run10 + _ctype + debugfs_rename + dev_change_net_namespace + __dev_get_by_index + dev_get_by_index + device_rename + genlmsg_multicast_allns + genlmsg_put + genl_register_family + genl_unregister_family + get_net_ns_by_fd + get_net_ns_by_pid + inet_csk_get_port + init_net + init_uts_ns + key_create_or_update + key_put + keyring_alloc + ktime_get_coarse_with_offset + memcmp + netif_rx_ni + netlink_broadcast + netlink_register_notifier + netlink_unicast + netlink_unregister_notifier + net_ns_type_operations + nla_find + nla_memcpy + __nla_parse + nla_put_64bit + nla_put + nla_reserve + __nla_validate + of_prop_next_u32 + __put_net + register_pernet_device + request_firmware_nowait + rfkill_blocked + rfkill_pause_polling + rfkill_resume_polling + skb_add_rx_frag + __sock_create + sock_release + unregister_pernet_device + verify_pkcs7_signature + wireless_nlevent_flush + # required by ch.ko - param_array_ops scsi_device_lookup __scsi_execute scsi_print_sense_hdr scsi_register_driver +# required by clk-link.ko + pm_clk_add + pm_clk_resume + pm_clk_suspend + # required by clk-pwm.ko of_clk_add_hw_provider of_clk_hw_simple_get @@ -881,22 +1481,19 @@ clk_divider_ro_ops clk_fixed_factor_ops clk_fractional_divider_ops - clk_gate_ops __clk_get_hw + clk_get_parent clk_hw_register_composite clk_hw_round_rate clk_mux_ops clk_mux_ro_ops - clk_register_composite clk_register_divider_table clk_register_fixed_factor clk_register_gate clk_register_mux_table - divider_get_val match_string register_restart_handler reset_controller_register - __udelay # required by clk-scmi.ko clk_hw_set_rate_range @@ -908,6 +1505,7 @@ cma_get_name dma_contiguous_default_area dma_heap_get_drvdata + dma_heap_put # required by cpufreq-dt.ko cpufreq_enable_boost_support @@ -925,9 +1523,6 @@ dev_pm_opp_of_cpumask_add_table dev_pm_opp_of_cpumask_remove_table dev_pm_opp_of_register_em - dev_pm_opp_put_regulators - dev_pm_opp_set_rate - dev_pm_opp_set_regulators dev_pm_opp_set_sharing_cpus policy_has_boost_freq @@ -948,71 +1543,42 @@ devm_blk_ksm_init mmc_cqe_request_done -# required by cw2015_battery.ko - device_property_read_u8_array - power_supply_am_i_supplied - power_supply_get_battery_info - power_supply_put_battery_info - regmap_raw_read +# required by cryptodev.ko + __close_fd + crypto_ahash_final + crypto_alloc_akcipher + get_user_pages_remote + krealloc + proc_dointvec + register_sysctl_table + sg_last + unregister_sysctl_table -# required by dw-hdmi-cec.ko - cec_allocate_adapter - cec_delete_adapter - cec_notifier_cec_adap_register - cec_notifier_cec_adap_unregister - cec_received_msg_ts - cec_register_adapter - cec_transmit_attempt_done_ts - cec_unregister_adapter - devm_remove_action +# required by display-connector.ko + drm_atomic_get_new_bridge_state + drm_probe_ddc + +# required by dm9601.ko + mii_link_ok # required by dw-hdmi-hdcp.ko - device_create_file - device_remove_file kstrtobool - misc_deregister - misc_register sha1_init sha1_transform +# required by dw-hdmi-qp.ko + drm_mode_equal + hdmi_avi_infoframe_pack_only + # required by dw-hdmi.ko - bcmp - cancel_delayed_work - cec_fill_conn_info_from_drm - cec_notifier_conn_register - cec_notifier_conn_unregister - cec_notifier_set_phys_addr - cec_notifier_set_phys_addr_from_edid - cec_queue_pin_hpd_event - drm_bridge_hpd_notify drm_connector_attach_max_bpc_property drm_default_rgb_quant_range - drm_hdmi_avi_infoframe_quant_range - drm_hdmi_infoframe_set_hdr_metadata - drm_mode_is_420_also - drm_mode_is_420_only - drm_property_replace_global_blob - drm_scdc_read - drm_scdc_set_high_tmds_clock_ratio - drm_scdc_set_scrambling - drm_scdc_write - extcon_set_property_capability - hdmi_drm_infoframe_pack - hdmi_vendor_infoframe_pack - of_get_i2c_adapter_by_node + of_graph_get_endpoint_by_regs # required by dw-mipi-dsi.ko - debugfs_attr_read - debugfs_attr_write drm_panel_bridge_add_typed drm_panel_bridge_connector drm_panel_bridge_remove - mipi_dsi_create_packet - mipi_dsi_host_register - mipi_dsi_host_unregister - of_drm_find_bridge - simple_attr_open - simple_attr_release # required by dw_mmc-rockchip.ko clk_get_phase @@ -1049,54 +1615,30 @@ # required by dwc2.ko __bitmap_clear bitmap_find_next_zero_area_off - device_set_wakeup_capable - device_wakeup_enable - devm_usb_get_phy - hrtimer_cancel - hrtimer_init - hrtimer_start_range_ns + __bitmap_set phy_reset _raw_spin_trylock usb_add_gadget_udc - usb_add_hcd - usb_calc_bus_time - usb_create_hcd usb_del_gadget_udc - usb_disabled usb_ep_set_maxpacket_limit usb_gadget_giveback_request usb_gadget_map_request usb_gadget_set_state usb_gadget_unmap_request usb_get_dr_mode - usb_hcd_check_unlink_urb - usb_hcd_giveback_urb - usb_hcd_link_urb_to_ep usb_hcd_map_urb_for_dma - usb_hcd_resume_root_hub - usb_hcd_unlink_urb_from_ep usb_hcd_unmap_urb_for_dma usb_hub_clear_tt_buffer usb_phy_set_charger_current - usb_put_hcd - usb_remove_hcd usb_role_switch_get_drvdata usb_role_switch_register usb_role_switch_unregister usb_speed_string usb_wakeup_enabled_descendants -# required by fan53555.ko - gpiod_set_raw_value - # required by fusb302.ko - device_get_named_child_node - disable_irq_nosync extcon_get_extcon_dev fwnode_create_software_node - i2c_smbus_read_i2c_block_data - i2c_smbus_write_byte_data - i2c_smbus_write_i2c_block_data tcpm_cc_change tcpm_pd_hard_reset tcpm_pd_receive @@ -1106,6 +1648,9 @@ tcpm_vbus_change vsnprintf +# required by gc2145.ko + v4l2_ctrl_subdev_log_status + # required by ghash-ce.ko aes_expandkey gf128mul_lle @@ -1125,28 +1670,22 @@ irq_gc_set_wake irq_generic_chip_ops irq_get_domain_generic_chip - irq_of_parse_and_map of_pinctrl_get # required by grf.ko of_find_matching_node_and_match +# required by gslx680-pad.ko + input_unregister_device + # required by hid-alps.ko down input_alloc_absinfo - input_allocate_device - input_free_device - input_mt_init_slots - input_mt_report_slot_state input_mt_sync_frame - up # required by hid-holtek-kbd.ko usb_ifnum_to_if -# required by hid-ntrig.ko - usb_control_msg - # required by hid-primax.ko hid_report_raw_event @@ -1162,7 +1701,6 @@ i2c_bit_add_numbered_bus # required by i2c-hid.ko - dev_printk hid_add_device hid_allocate_device hid_destroy_device @@ -1190,19 +1728,21 @@ # required by industrialio-triggered-buffer.ko iio_alloc_pollfunc iio_dealloc_pollfunc - iio_device_attach_buffer # required by io-domain.ko _dev_crit regulator_register_notifier regulator_unregister_notifier +# required by kalmia.ko + usb_bulk_msg + # required by kfifo_buf.ko __kfifo_to_user - mutex_lock_interruptible -# required by leds-gpio.ko - devm_gpio_request_one +# required by leds-rgb13h.ko + led_classdev_flash_register_ext + led_classdev_flash_unregister # required by ledtrig-heartbeat.ko avenrun @@ -1213,6 +1753,73 @@ # required by lzo.ko lzo1x_1_compress +# required by mac80211.ko + alloc_netdev_mqs + __alloc_percpu_gfp + arc4_crypt + arc4_setkey + call_rcu + crc32_be + crypto_shash_digest + crypto_shash_finup + crypto_shash_setkey + dev_alloc_name + dev_fetch_sw_netstats + dev_queue_xmit + ether_setup + ethtool_op_get_link + free_netdev + get_random_u32 + __hw_addr_init + __hw_addr_sync + __hw_addr_unsync + kernel_param_lock + kernel_param_unlock + kfree_skb_list + ktime_get_seconds + __local_bh_enable_ip + napi_gro_receive + netdev_set_default_ethtool_ops + netif_carrier_off + netif_carrier_on + netif_receive_skb + netif_receive_skb_list + netif_rx + netif_tx_stop_all_queues + netif_tx_wake_queue + net_ratelimit + prandom_bytes + prandom_u32 + ___pskb_trim + rcu_barrier + register_inet6addr_notifier + register_inetaddr_notifier + register_netdevice + rhashtable_free_and_destroy + rhashtable_insert_slow + rhltable_init + __rht_bucket_nested + rht_bucket_nested + rht_bucket_nested_insert + round_jiffies + round_jiffies_up + skb_checksum_help + skb_clone_sk + skb_complete_wifi_ack + skb_copy + skb_dequeue + skb_ensure_writable + __skb_get_hash + __skb_gso_segment + skb_queue_head + skb_queue_purge + skb_queue_tail + synchronize_net + unregister_inet6addr_notifier + unregister_inetaddr_notifier + unregister_netdevice_many + unregister_netdevice_queue + # required by nvme-core.ko bd_set_nr_sectors blk_execute_rq @@ -1241,45 +1848,23 @@ blk_set_queue_dying blk_status_to_errno blk_sync_queue - bpf_trace_run1 - bpf_trace_run2 - bpf_trace_run3 capable cleanup_srcu_struct - device_add - device_del device_remove_file_self dev_pm_qos_expose_latency_tolerance dev_pm_qos_hide_latency_tolerance dev_pm_qos_update_user_latency_tolerance - event_triggers_call ida_alloc_range ida_destroy ida_free init_srcu_struct - kobject_uevent_env - list_sort memchr_inv - param_ops_byte param_ops_ulong - perf_trace_buf_alloc - perf_trace_run_bpf_submit set_capacity_revalidate_and_notify set_disk_ro __srcu_read_unlock - synchronize_rcu synchronize_srcu - trace_event_buffer_commit - trace_event_buffer_reserve - trace_event_ignore_this_pid - trace_event_raw_init - trace_event_reg - trace_handle_return - trace_print_symbols_seq - trace_raw_output_prep - trace_seq_printf trace_seq_putc - try_module_get xa_destroy xa_erase xa_find @@ -1300,12 +1885,7 @@ blk_mq_update_nr_hw_queues blk_put_queue __blk_rq_map_sg - device_release_driver dma_max_mapping_size - dma_pool_alloc - dma_pool_create - dma_pool_destroy - dma_pool_free __do_once_done __do_once_start mempool_alloc @@ -1340,60 +1920,63 @@ pci_sriov_configure_simple pci_unregister_driver pm_suspend_global_flags - sg_init_table - __sw_hweight64 sysfs_remove_file_from_group wait_for_completion_io_timeout +# required by ohci-hcd.ko + gen_pool_dma_alloc_align + gen_pool_dma_zalloc_align + sb800_prefetch + schedule_timeout_uninterruptible + usb_amd_dev_put + usb_amd_quirk_pll_disable + usb_amd_quirk_pll_enable + usb_hc_died + usb_hcd_poll_rh_status + usb_hcds_loaded + usb_root_hub_lost_power + +# required by ohci-platform.ko + usb_hcd_platform_shutdown + # required by optee-rng.ko - driver_register hwrng_register hwrng_unregister # required by optee.ko alloc_pages_exact __arm_smccc_hvc + bus_for_each_dev device_register - find_vma + device_unregister free_pages_exact - idr_get_next - kimage_voffset - ktime_get_real_ts64 memremap memunmap - msleep_interruptible wait_for_completion_interruptible -# required by ov2680.ko - v4l2_ctrl_auto_cluster - v4l2_ctrl_new_std_menu - __v4l2_find_nearest_size - -# required by ov5695.ko - __v4l2_ctrl_modify_range - v4l2_ctrl_new_int_menu - # required by panel-simple.ko + devm_backlight_device_register drm_bus_flags_from_videomode drm_connector_set_panel_orientation - drm_display_mode_from_videomode - drm_panel_add - drm_panel_init drm_panel_of_backlight drm_panel_remove - mipi_dsi_attach + mipi_dsi_compression_mode + mipi_dsi_dcs_get_display_brightness + mipi_dsi_dcs_set_display_brightness mipi_dsi_dcs_write_buffer - mipi_dsi_detach mipi_dsi_driver_register_full mipi_dsi_driver_unregister mipi_dsi_generic_write + mipi_dsi_picture_parameter_set of_drm_get_panel_orientation of_find_i2c_adapter_by_node of_get_display_timing - of_get_drm_display_mode videomode_from_timing # required by pcie-dw-rockchip.ko + cpu_bit_bitmap + cpumask_next_and + dw_pcie_find_ext_capability dw_pcie_host_init dw_pcie_link_up dw_pcie_read @@ -1401,14 +1984,16 @@ dw_pcie_setup_rc dw_pcie_write dw_pcie_write_dbi - kthread_create_on_node - of_prop_next_string - wake_up_process + pci_disable_link_state + pcie_capability_clear_and_set_word + pci_read_config_dword + pci_set_power_state + pci_write_config_dword # required by pcierockchiphost.ko - devm_of_phy_get devm_pci_alloc_host_bridge devm_pci_remap_cfg_resource + dummy_irq_chip jiffies_to_usecs of_pci_get_max_link_speed pci_host_probe @@ -1419,24 +2004,26 @@ # required by phy-rockchip-inno-dsidphy.ko phy_mipi_dphy_config_validate -# required by phy-rockchip-inno-hdmi-phy.ko - nvmem_cell_get - # required by phy-rockchip-inno-usb2.ko devm_extcon_register_notifier extcon_set_state extcon_sync - wakeup_source_remove # required by phy-rockchip-inno-usb3.ko strcasecmp usb_add_phy +# required by phy-rockchip-samsung-hdptx-hdmi.ko + of_platform_device_create + # required by phy-rockchip-typec.ko extcon_get_property -# required by phy-rockchip-usb.ko - __of_reset_control_get +# required by phy-rockchip-usbdp.ko + typec_mux_get_drvdata + typec_mux_register + typec_mux_unregister + usb_get_maximum_speed # required by pinctrl-rk628.ko irq_domain_xlate_twocell @@ -1445,6 +2032,7 @@ # required by pinctrl-rockchip.ko of_find_node_by_phandle + of_platform_depopulate of_platform_populate pinconf_generic_parse_dt_config pinctrl_force_default @@ -1459,8 +2047,6 @@ dma_async_tx_descriptor_init dmaengine_unmap_put dma_get_slave_channel - dma_map_resource - dma_unmap_resource loops_per_jiffy of_dma_controller_free of_dma_controller_register @@ -1469,12 +2055,9 @@ # required by pm_domains.ko clk_bulk_put - of_clk_get_parent_count of_genpd_add_provider_onecell panic pm_clk_add_clk - pm_clk_create - pm_clk_destroy pm_genpd_add_subdomain pm_genpd_init pm_genpd_remove @@ -1499,15 +2082,23 @@ devres_release kernel_kobj +# required by rfkill-rk.ko + gpio_free + gpio_request + kstrtoll + rfkill_init_sw_state + rfkill_set_sw_state + # required by rk628.ko irq_dispose_mapping irq_domain_xlate_onetwocell irq_set_parent - mfd_add_devices + +# required by rk628_dsi.ko + of_drm_find_panel # required by rk805-pwrkey.ko devm_request_any_context_irq - input_set_capability # required by rk806-core.ko devm_regmap_add_irq_chip @@ -1519,14 +2110,12 @@ gpiod_is_active_low # required by rk808.ko - kobject_create_and_add platform_device_add platform_device_alloc pm_power_off_prepare register_syscore_ops regmap_add_irq_chip regmap_del_irq_chip - system_state unregister_syscore_ops # required by rk818_battery.ko @@ -1534,57 +2123,85 @@ blocking_notifier_chain_register blocking_notifier_chain_unregister +# required by rk860x-regulator.ko + regulator_suspend_enable + +# required by rk_crypto.ko + crypto_ahash_digest + crypto_dequeue_request + crypto_enqueue_request + crypto_init_queue + crypto_register_ahash + crypto_register_akcipher + crypto_register_skcipher + crypto_req_done + crypto_unregister_ahash + crypto_unregister_akcipher + crypto_unregister_skcipher + des_expand_key + rsa_parse_priv_key + rsa_parse_pub_key + scatterwalk_ffwd + sg_copy_from_buffer + sg_copy_to_buffer + sg_nents_for_len + sg_pcopy_from_buffer + sg_pcopy_to_buffer + +# required by rk_headset_irq_hook_adc.ko + iio_read_channel_raw + +# required by rk_vcodec.ko + devfreq_remove_governor + devm_iounmap + dev_pm_domain_attach + dev_pm_opp_get_freq + disable_hardirq + dma_buf_begin_cpu_access_partial + dma_buf_end_cpu_access_partial + __fdget + iommu_attach_group + iommu_detach_group + iommu_device_unregister + iommu_dma_reserve_iova + iommu_group_get + kthread_flush_worker + __kthread_init_worker + kthread_queue_work + kthread_worker_fn + of_device_alloc + of_dma_configure_id + platform_device_del + pm_generic_runtime_resume + pm_generic_runtime_suspend + pm_relax + pm_stay_awake + proc_create_single_data + proc_remove + strncat + # required by rknpu.ko - dma_buf_mmap - dma_fence_context_alloc - dma_fence_init - dma_fence_release - dma_fence_signal + dev_pm_domain_attach_by_name drm_gem_create_mmap_offset drm_gem_dumb_destroy drm_gem_handle_delete drm_gem_prime_export drm_gem_prime_import_dev drm_gem_vm_open - fd_install - get_unused_fd_flags - of_dma_configure_id + drm_prime_gem_destroy set_user_nice - sync_file_create vmf_insert_mixed + vm_insert_page # required by rockchip-cpufreq.ko + cpufreq_unregister_notifier dev_pm_opp_put_prop_name - dev_pm_opp_register_set_opp_helper - -# required by rockchip-iommu.ko - bus_set_iommu - get_zeroed_page - iommu_device_register - iommu_device_sysfs_add - iommu_device_sysfs_remove - iommu_get_dma_cookie - iommu_group_alloc - iommu_group_put - iommu_group_ref_get - iommu_put_dma_cookie - platform_irq_count - report_iommu_fault + dev_pm_opp_set_supported_hw # required by rockchip-rng.ko devm_hwrng_register devm_of_iomap -# required by rockchip.ko - __genphy_config_aneg - genphy_resume - genphy_soft_reset - genphy_suspend - mdiobus_read - mdiobus_write - phy_drivers_register - phy_drivers_unregister - # required by rockchip_bus.ko cpu_topology @@ -1592,9 +2209,6 @@ cpufreq_cpu_get cpufreq_cpu_put cpufreq_quick_get - cpu_latency_qos_add_request - cpu_latency_qos_update_request - devfreq_add_governor devfreq_event_disable_edev devfreq_event_enable_edev devfreq_event_get_edev_by_phandle @@ -1604,11 +2218,7 @@ devfreq_monitor_start devfreq_monitor_stop devfreq_monitor_suspend - devfreq_resume_device - devfreq_suspend_device devfreq_update_interval - _dev_notice - dev_pm_opp_add input_close_device input_open_device input_register_handle @@ -1619,22 +2229,36 @@ # required by rockchip_dmc_common.ko down_write_trylock +# required by rockchip_headset_core.ko + iio_channel_get + # required by rockchip_opp_select.ko - dev_pm_opp_get_opp_table + dev_pm_opp_disable dev_pm_opp_of_add_table - dev_pm_opp_put_opp_table dev_pm_opp_set_prop_name - of_find_node_opts_by_path - regulator_get_optional - regulator_put + regulator_get_linear_step + +# required by rockchip_pwm_remotectl.ko + irq_to_desc + __tasklet_hi_schedule # required by rockchip_saradc.ko - devm_iio_device_alloc - __devm_iio_device_register iio_get_time_ns - iio_push_to_buffers iio_trigger_notify_done +# required by rockchip_system_monitor.ko + add_cpu + bitmap_parselist + compat_only_sysfs_link_entry_to_kobj + dev_pm_qos_add_request + dev_pm_qos_remove_request + dev_pm_qos_update_request + regulator_get + remove_cpu + strchr + strsep + thermal_zone_get_temp + # required by rockchip_thermal.ko devm_thermal_zone_of_sensor_register thermal_zone_device_disable @@ -1643,8 +2267,6 @@ # required by rockchipdrm.ko adjust_managed_page_count - clk_is_match - clk_set_parent component_add component_bind_all component_del @@ -1653,11 +2275,12 @@ component_match_add_release component_unbind_all devm_of_phy_get_by_index - devm_phy_optional_get + driver_find_device drm_add_modes_noedid drm_atomic_commit drm_atomic_get_connector_state drm_atomic_get_plane_state + drm_atomic_helper_bridge_propagate_bus_fmt drm_atomic_helper_check drm_atomic_helper_check_plane_state drm_atomic_helper_cleanup_planes @@ -1671,13 +2294,13 @@ __drm_atomic_helper_connector_reset __drm_atomic_helper_crtc_destroy_state __drm_atomic_helper_crtc_duplicate_state - drm_atomic_helper_dirtyfb __drm_atomic_helper_disable_plane drm_atomic_helper_duplicate_state drm_atomic_helper_fake_vblank drm_atomic_helper_page_flip __drm_atomic_helper_plane_destroy_state __drm_atomic_helper_plane_duplicate_state + __drm_atomic_helper_plane_reset drm_atomic_helper_set_config drm_atomic_helper_shutdown drm_atomic_helper_swap_state @@ -1688,11 +2311,12 @@ drm_atomic_set_mode_for_crtc drm_atomic_state_alloc __drm_atomic_state_free + drm_bridge_get_edid + drm_connector_has_possible_encoder drm_connector_list_iter_begin drm_connector_list_iter_end drm_connector_list_iter_next drm_connector_list_update - drm_connector_unregister drm_crtc_cleanup drm_crtc_enable_color_mgmt drm_crtc_from_index @@ -1706,6 +2330,12 @@ drm_debugfs_create_files drm_do_get_edid drm_dp_channel_eq_ok + drm_dp_clock_recovery_ok + drm_dp_dpcd_read_link_status + drm_dp_get_adjust_request_pre_emphasis + drm_dp_get_adjust_request_voltage + drm_dp_read_desc + drm_dp_read_sink_count drm_encoder_cleanup drm_encoder_init drm_event_reserve_init_locked @@ -1714,6 +2344,7 @@ drm_flip_work_init drm_flip_work_queue drm_format_info + drm_format_info_min_pitch drm_framebuffer_cleanup drm_framebuffer_init drm_gem_cma_vm_ops @@ -1726,17 +2357,13 @@ drm_gem_fb_afbc_init drm_gem_fb_create_handle drm_gem_fb_init_with_funcs - drm_gem_get_pages drm_gem_map_attach drm_gem_map_detach drm_gem_map_dma_buf - drm_gem_object_put_locked - drm_gem_put_pages drm_gem_unmap_dma_buf drm_get_format_info drm_get_format_name drm_helper_mode_fill_fb_struct - drm_kms_helper_hotplug_event drm_kms_helper_poll_enable drm_kms_helper_poll_fini drm_kms_helper_poll_init @@ -1745,11 +2372,13 @@ drmm_mode_config_init drm_mm_print drm_mm_remove_node + drm_mm_reserve_node drm_mm_takedown drm_mode_config_cleanup drm_mode_config_helper_resume drm_mode_config_helper_suspend drm_mode_config_reset + drm_mode_create_hdmi_colorspace_property drm_mode_create_tv_properties drm_mode_crtc_set_gamma_size drm_mode_debug_printmodeline @@ -1761,7 +2390,6 @@ drm_modeset_lock_all drm_modeset_unlock_all drm_mode_sort - drm_mode_validate_driver drm_mode_validate_size drm_mode_validate_ycbcr420 drm_of_crtc_port_mask @@ -1775,12 +2403,15 @@ __drm_printfn_seq_file drm_property_create drm_property_create_bitmask + drm_property_create_bool drm_property_create_enum drm_property_create_object drm_property_create_range drm_property_destroy __drm_puts_seq_file drm_rect_calc_hscale + drm_self_refresh_helper_cleanup + drm_self_refresh_helper_init drm_send_event_locked drm_simple_encoder_init drm_universal_plane_init @@ -1788,32 +2419,31 @@ drm_writeback_connector_init drm_writeback_queue_job drm_writeback_signal_completion - hdmi_infoframe_pack iommu_domain_alloc iommu_domain_free - iommu_map iommu_map_sg - iommu_set_fault_handler - iommu_unmap memblock_free - of_graph_get_next_endpoint + mipi_dsi_packet_format_is_short + of_find_backlight_by_node + of_fwnode_ops of_graph_get_port_by_id of_graph_get_remote_port - of_graph_get_remote_port_parent phy_mipi_dphy_get_default_config platform_find_device_by_driver __platform_register_drivers platform_unregister_drivers - release_firmware - request_firmware sort - __sw_hweight32 - __sw_hweight8 __vmalloc +# required by rohm-bu18tl82.ko + mipi_dsi_device_register_full + mipi_dsi_device_unregister + of_find_mipi_dsi_host_by_node + +# required by rtc-hym8563.ko + devm_rtc_device_register + # required by rtc-rk808.ko - _bcd2bin - _bin2bcd devm_rtc_allocate_device __rtc_register_device rtc_time64_to_tm @@ -1845,16 +2475,12 @@ blk_put_request blk_rq_map_user_iov blk_verify_command - cdev_add cdev_alloc - cdev_del class_interface_unregister fasync_helper get_sg_io_hdr import_iovec kill_fasync - __module_get - nonseekable_open put_sg_io_hdr _raw_read_lock_irqsave _raw_read_unlock_irqrestore @@ -1872,65 +2498,88 @@ sg_scsi_ioctl __task_pid_nr_ns +# required by sgm41542_charger.ko + regulator_unregister + # required by sha1-ce.ko crypto_sha1_finup crypto_sha1_update irq_stat # required by sii902x.ko - drm_display_mode_to_videomode - hdmi_audio_infoframe_pack hdmi_avi_infoframe_pack - of_property_read_variable_u8_array -# required by snd-soc-cx2072x.ko - regmap_multi_reg_write - snd_soc_params_to_frame_size +# required by smsc95xx.ko + csum_partial + ethtool_op_get_ts_info + mdiobus_alloc_size + mdiobus_free + __mdiobus_register + mdiobus_unregister + phy_attached_info + phy_connect_direct + phy_disconnect + phy_ethtool_get_link_ksettings + phy_ethtool_nway_reset + phy_ethtool_set_link_ksettings + phy_find_first + phy_get_pause + phy_init_hw + phy_mii_ioctl + phy_print_status + phy_start + phy_stop + usb_autopm_get_interface_no_resume # required by snd-soc-es8316.ko snd_pcm_hw_constraint_list - snd_soc_dapm_disable_pin_unlocked - snd_soc_dapm_sync_unlocked # required by snd-soc-hdmi-codec.ko - hdmi_audio_infoframe_init snd_ctl_add snd_ctl_new1 snd_pcm_add_chmap_ctls - snd_pcm_create_iec958_consumer_hw_params + snd_pcm_create_iec958_consumer_default + snd_pcm_fill_iec958_consumer + snd_pcm_fill_iec958_consumer_hw_params snd_pcm_hw_constraint_eld - snd_soc_dapm_add_routes # required by snd-soc-rk817.ko - snd_soc_add_component_controls snd_soc_component_exit_regmap snd_soc_component_init_regmap - snd_soc_unregister_component + +# required by snd-soc-rockchip-hdmi.ko + snd_soc_dapm_new_widgets + +# required by snd-soc-rockchip-i2s-tdm.ko + clk_is_match + snd_soc_add_dai_controls + +# required by snd-soc-rockchip-i2s.ko + of_prop_next_string + +# required by snd-soc-rockchip-multicodecs.ko + of_parse_phandle_with_fixed_args + snd_soc_jack_add_zones + snd_soc_jack_get_type + +# required by snd-soc-rt5640.ko + gpiod_set_raw_value_cansleep + regmap_register_patch + snd_soc_dapm_force_bias_level # required by snd-soc-simple-card-utils.ko devm_kasprintf devm_kvasprintf - snd_soc_card_jack_new - snd_soc_dai_set_sysclk snd_soc_dai_set_tdm_slot - snd_soc_dapm_get_pin_switch - snd_soc_dapm_info_pin_switch - snd_soc_dapm_put_pin_switch - snd_soc_of_parse_audio_routing snd_soc_of_parse_audio_simple_widgets - snd_soc_of_parse_card_name - snd_soc_of_parse_daifmt snd_soc_runtime_calc_hw # required by snd-soc-simple-card.ko - devm_snd_soc_register_card - of_parse_phandle_with_args snd_soc_dai_link_set_capabilities snd_soc_of_get_dai_name snd_soc_of_parse_aux_devs snd_soc_of_parse_node_prefix snd_soc_of_parse_tdm_slot - snd_soc_pm_ops # required by spi-rockchip.ko devm_spi_register_controller @@ -1943,30 +2592,30 @@ spi_setup stream_open +# required by sw_sync.ko + dma_fence_free + dma_fence_signal_locked + __get_task_comm + put_unused_fd + # required by system_heap.ko deferred_free dmabuf_page_pool_alloc dmabuf_page_pool_create dmabuf_page_pool_destroy dmabuf_page_pool_free - dma_heap_get_dev - __sg_page_iter_next - __sg_page_iter_start swiotlb_max_segment # required by tcpci_husb311.ko i2c_smbus_read_word_data + tcpci_get_tcpm_port tcpci_irq tcpci_register_port tcpci_unregister_port # required by tee.ko - bus_register - bus_unregister class_find_device - crypto_alloc_shash crypto_shash_final - crypto_shash_update gen_pool_best_fit gen_pool_set_algo gen_pool_virt_to_phys @@ -1977,9 +2626,9 @@ # required by test_power.ko param_get_int - power_supply_register - power_supply_unregister - strncasecmp + +# required by timer-rockchip.ko + clockevents_config_and_register # required by tps65132-regulator.ko regulator_set_active_discharge_regmap @@ -1997,9 +2646,54 @@ typec_altmode_vdm typec_get_negotiated_svdm_version +# required by usblp.ko + add_wait_queue + default_wake_function + remove_wait_queue + stpcpy + usb_anchor_urb + usb_find_common_endpoints + usb_find_interface + usb_kill_anchored_urbs + usb_poison_anchored_urbs + usb_unanchor_urb + +# required by usbserial.ko + driver_attach + param_ops_ushort + put_tty_driver + schedule_timeout_interruptible + __tty_alloc_driver + tty_flip_buffer_push + tty_hangup + __tty_insert_flip_char + tty_insert_flip_string_fixed_flag + tty_kref_put + tty_ldisc_deref + tty_ldisc_ref + tty_port_close + tty_port_destroy + tty_port_hangup + tty_port_init + tty_port_open + tty_port_register_device + tty_port_tty_get + tty_port_tty_wakeup + tty_register_driver + tty_set_operations + tty_standard_install + tty_std_termios + tty_termios_copy_hw + tty_unregister_device + tty_unregister_driver + tty_vhangup + usb_kill_urb + usb_match_one_id + usb_show_dynids + usb_store_new_id + # required by v4l2-fwnode.ko fwnode_device_is_available - fwnode_get_name fwnode_graph_get_next_endpoint fwnode_graph_get_port_parent fwnode_graph_get_remote_endpoint @@ -2009,31 +2703,29 @@ fwnode_property_read_u64_array v4l2_async_notifier_add_fwnode_subdev v4l2_async_notifier_add_subdev - v4l2_async_notifier_unregister # required by video_rkcif.ko media_entity_setup_link + work_busy # required by video_rkisp.ko - kmalloc_order_trace media_device_cleanup __memcpy_fromio __memcpy_toio - of_property_read_u64 param_ops_ullong - v4l2_ctrl_g_ctrl_int64 v4l2_event_unsubscribe v4l2_pipeline_link_notify # required by videobuf2-dma-sg.ko split_page +# required by vl6180.ko + iio_read_const_attr + # required by zram.ko __alloc_percpu bio_endio blk_alloc_queue - __class_register - class_unregister __cpuhp_state_add_instance __cpuhp_state_remove_instance crypto_alloc_base @@ -2042,21 +2734,14 @@ crypto_has_alg disk_end_io_acct disk_start_io_acct - flush_dcache_page - free_percpu fsync_bdev - __get_free_pages - idr_for_each kstrtou16 memparse memset64 __num_online_cpus page_endio register_blkdev - strcpy - sysfs_streq unregister_blkdev - vzalloc # required by zsmalloc.ko alloc_anon_inode @@ -2069,14 +2754,11 @@ kern_mount kern_unmount kill_anon_super - kstrdup __lock_page page_mapping _raw_read_lock _raw_read_unlock _raw_write_lock _raw_write_unlock - register_shrinker __SetPageMovable unlock_page - unregister_shrinker diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c index 0e86e8b9cedd..c5da9d1e954a 100644 --- a/arch/arm64/kernel/armv8_deprecated.c +++ b/arch/arm64/kernel/armv8_deprecated.c @@ -59,6 +59,7 @@ struct insn_emulation { static LIST_HEAD(insn_emulation); static int nr_insn_emulated __initdata; static DEFINE_RAW_SPINLOCK(insn_emulation_lock); +static DEFINE_MUTEX(insn_emulation_mutex); static void register_emulation_hooks(struct insn_emulation_ops *ops) { @@ -207,10 +208,10 @@ static int emulation_proc_handler(struct ctl_table *table, int write, loff_t *ppos) { int ret = 0; - struct insn_emulation *insn = (struct insn_emulation *) table->data; + struct insn_emulation *insn = container_of(table->data, struct insn_emulation, current_mode); enum insn_emulation_mode prev_mode = insn->current_mode; - table->data = &insn->current_mode; + mutex_lock(&insn_emulation_mutex); ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); if (ret || !write || prev_mode == insn->current_mode) @@ -223,7 +224,7 @@ static int emulation_proc_handler(struct ctl_table *table, int write, update_insn_emulation_mode(insn, INSN_UNDEF); } ret: - table->data = insn; + mutex_unlock(&insn_emulation_mutex); return ret; } @@ -247,7 +248,7 @@ static void __init register_insn_emulation_sysctl(void) sysctl->maxlen = sizeof(int); sysctl->procname = insn->ops->name; - sysctl->data = insn; + sysctl->data = &insn->current_mode; sysctl->extra1 = &insn->min; sysctl->extra2 = &insn->max; sysctl->proc_handler = emulation_proc_handler; diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c index cdb3d4549b3a..e41cee4e1bb9 100644 --- a/arch/arm64/kernel/perf_event.c +++ b/arch/arm64/kernel/perf_event.c @@ -1116,17 +1116,32 @@ static int armv8_pmu_init_nogroups(struct arm_pmu *cpu_pmu, char *name, return armv8_pmu_init(cpu_pmu, name, map_event, NULL, NULL, NULL); } -static int armv8_pmuv3_init(struct arm_pmu *cpu_pmu) -{ - return armv8_pmu_init_nogroups(cpu_pmu, "armv8_pmuv3", - armv8_pmuv3_map_event); +#define PMUV3_INIT_SIMPLE(name) \ +static int name##_pmu_init(struct arm_pmu *cpu_pmu) \ +{ \ + return armv8_pmu_init_nogroups(cpu_pmu, #name, armv8_pmuv3_map_event);\ } -static int armv8_a34_pmu_init(struct arm_pmu *cpu_pmu) -{ - return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a34", - armv8_pmuv3_map_event); -} +PMUV3_INIT_SIMPLE(armv8_pmuv3) + +PMUV3_INIT_SIMPLE(armv8_cortex_a34) +PMUV3_INIT_SIMPLE(armv8_cortex_a55) +PMUV3_INIT_SIMPLE(armv8_cortex_a65) +PMUV3_INIT_SIMPLE(armv8_cortex_a75) +PMUV3_INIT_SIMPLE(armv8_cortex_a76) +PMUV3_INIT_SIMPLE(armv8_cortex_a77) +PMUV3_INIT_SIMPLE(armv8_cortex_a78) +PMUV3_INIT_SIMPLE(armv9_cortex_a510) +PMUV3_INIT_SIMPLE(armv9_cortex_a710) +PMUV3_INIT_SIMPLE(armv8_cortex_x1) +PMUV3_INIT_SIMPLE(armv9_cortex_x2) +PMUV3_INIT_SIMPLE(armv8_neoverse_e1) +PMUV3_INIT_SIMPLE(armv8_neoverse_n1) +PMUV3_INIT_SIMPLE(armv9_neoverse_n2) +PMUV3_INIT_SIMPLE(armv8_neoverse_v1) + +PMUV3_INIT_SIMPLE(armv8_nvidia_carmel) +PMUV3_INIT_SIMPLE(armv8_nvidia_denver) static int armv8_a35_pmu_init(struct arm_pmu *cpu_pmu) { @@ -1140,24 +1155,12 @@ static int armv8_a53_pmu_init(struct arm_pmu *cpu_pmu) armv8_a53_map_event); } -static int armv8_a55_pmu_init(struct arm_pmu *cpu_pmu) -{ - return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a55", - armv8_pmuv3_map_event); -} - static int armv8_a57_pmu_init(struct arm_pmu *cpu_pmu) { return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a57", armv8_a57_map_event); } -static int armv8_a65_pmu_init(struct arm_pmu *cpu_pmu) -{ - return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a65", - armv8_pmuv3_map_event); -} - static int armv8_a72_pmu_init(struct arm_pmu *cpu_pmu) { return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a72", @@ -1170,36 +1173,6 @@ static int armv8_a73_pmu_init(struct arm_pmu *cpu_pmu) armv8_a73_map_event); } -static int armv8_a75_pmu_init(struct arm_pmu *cpu_pmu) -{ - return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a75", - armv8_pmuv3_map_event); -} - -static int armv8_a76_pmu_init(struct arm_pmu *cpu_pmu) -{ - return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a76", - armv8_pmuv3_map_event); -} - -static int armv8_a77_pmu_init(struct arm_pmu *cpu_pmu) -{ - return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a77", - armv8_pmuv3_map_event); -} - -static int armv8_e1_pmu_init(struct arm_pmu *cpu_pmu) -{ - return armv8_pmu_init_nogroups(cpu_pmu, "armv8_neoverse_e1", - armv8_pmuv3_map_event); -} - -static int armv8_n1_pmu_init(struct arm_pmu *cpu_pmu) -{ - return armv8_pmu_init_nogroups(cpu_pmu, "armv8_neoverse_n1", - armv8_pmuv3_map_event); -} - static int armv8_thunder_pmu_init(struct arm_pmu *cpu_pmu) { return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cavium_thunder", @@ -1213,22 +1186,31 @@ static int armv8_vulcan_pmu_init(struct arm_pmu *cpu_pmu) } static const struct of_device_id armv8_pmu_of_device_ids[] = { - {.compatible = "arm,armv8-pmuv3", .data = armv8_pmuv3_init}, - {.compatible = "arm,cortex-a34-pmu", .data = armv8_a34_pmu_init}, + {.compatible = "arm,armv8-pmuv3", .data = armv8_pmuv3_pmu_init}, + {.compatible = "arm,cortex-a34-pmu", .data = armv8_cortex_a34_pmu_init}, {.compatible = "arm,cortex-a35-pmu", .data = armv8_a35_pmu_init}, {.compatible = "arm,cortex-a53-pmu", .data = armv8_a53_pmu_init}, - {.compatible = "arm,cortex-a55-pmu", .data = armv8_a55_pmu_init}, + {.compatible = "arm,cortex-a55-pmu", .data = armv8_cortex_a55_pmu_init}, {.compatible = "arm,cortex-a57-pmu", .data = armv8_a57_pmu_init}, - {.compatible = "arm,cortex-a65-pmu", .data = armv8_a65_pmu_init}, + {.compatible = "arm,cortex-a65-pmu", .data = armv8_cortex_a65_pmu_init}, {.compatible = "arm,cortex-a72-pmu", .data = armv8_a72_pmu_init}, {.compatible = "arm,cortex-a73-pmu", .data = armv8_a73_pmu_init}, - {.compatible = "arm,cortex-a75-pmu", .data = armv8_a75_pmu_init}, - {.compatible = "arm,cortex-a76-pmu", .data = armv8_a76_pmu_init}, - {.compatible = "arm,cortex-a77-pmu", .data = armv8_a77_pmu_init}, - {.compatible = "arm,neoverse-e1-pmu", .data = armv8_e1_pmu_init}, - {.compatible = "arm,neoverse-n1-pmu", .data = armv8_n1_pmu_init}, + {.compatible = "arm,cortex-a75-pmu", .data = armv8_cortex_a75_pmu_init}, + {.compatible = "arm,cortex-a76-pmu", .data = armv8_cortex_a76_pmu_init}, + {.compatible = "arm,cortex-a77-pmu", .data = armv8_cortex_a77_pmu_init}, + {.compatible = "arm,cortex-a78-pmu", .data = armv8_cortex_a78_pmu_init}, + {.compatible = "arm,cortex-a510-pmu", .data = armv9_cortex_a510_pmu_init}, + {.compatible = "arm,cortex-a710-pmu", .data = armv9_cortex_a710_pmu_init}, + {.compatible = "arm,cortex-x1-pmu", .data = armv8_cortex_x1_pmu_init}, + {.compatible = "arm,cortex-x2-pmu", .data = armv9_cortex_x2_pmu_init}, + {.compatible = "arm,neoverse-e1-pmu", .data = armv8_neoverse_e1_pmu_init}, + {.compatible = "arm,neoverse-n1-pmu", .data = armv8_neoverse_n1_pmu_init}, + {.compatible = "arm,neoverse-n2-pmu", .data = armv9_neoverse_n2_pmu_init}, + {.compatible = "arm,neoverse-v1-pmu", .data = armv8_neoverse_v1_pmu_init}, {.compatible = "cavium,thunder-pmu", .data = armv8_thunder_pmu_init}, {.compatible = "brcm,vulcan-pmu", .data = armv8_vulcan_pmu_init}, + {.compatible = "nvidia,carmel-pmu", .data = armv8_nvidia_carmel_pmu_init}, + {.compatible = "nvidia,denver-pmu", .data = armv8_nvidia_denver_pmu_init}, {}, }; @@ -1251,7 +1233,7 @@ static int __init armv8_pmu_driver_init(void) if (acpi_disabled) return platform_driver_register(&armv8_pmu_driver); else - return arm_pmu_acpi_probe(armv8_pmuv3_init); + return arm_pmu_acpi_probe(armv8_pmuv3_pmu_init); } device_initcall(armv8_pmu_driver_init) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 052a1e590e9f..ba7d6a96514f 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -173,8 +173,32 @@ static inline void binder_stats_created(enum binder_stat_types type) atomic_inc(&binder_stats.obj_created[type]); } -struct binder_transaction_log binder_transaction_log; -struct binder_transaction_log binder_transaction_log_failed; +struct binder_transaction_log_entry { + int debug_id; + int debug_id_done; + int call_type; + int from_proc; + int from_thread; + int target_handle; + int to_proc; + int to_thread; + int to_node; + int data_size; + int offsets_size; + int return_error_line; + uint32_t return_error; + uint32_t return_error_param; + char context_name[BINDERFS_MAX_NAME + 1]; +}; + +struct binder_transaction_log { + atomic_t cur; + bool full; + struct binder_transaction_log_entry entry[32]; +}; + +static struct binder_transaction_log binder_transaction_log; +static struct binder_transaction_log binder_transaction_log_failed; static struct binder_transaction_log_entry *binder_transaction_log_add( struct binder_transaction_log *log) @@ -1480,6 +1504,18 @@ static int binder_inc_ref_for_node(struct binder_proc *proc, } ret = binder_inc_ref_olocked(ref, strong, target_list); *rdata = ref->data; + if (ret && ref == new_ref) { + /* + * Cleanup the failed reference here as the target + * could now be dead and have already released its + * references by now. Calling on the new reference + * with strong=0 and a tmp_refs will not decrement + * the node. The new_ref gets kfree'd below. + */ + binder_cleanup_ref_olocked(new_ref); + ref = NULL; + } + binder_proc_unlock(proc); if (new_ref && ref != new_ref) /* @@ -2464,6 +2500,56 @@ static int binder_fixup_parent(struct binder_transaction *t, return 0; } +/** + * binder_can_update_transaction() - Can a txn be superseded by an updated one? + * @t1: the pending async txn in the frozen process + * @t2: the new async txn to supersede the outdated pending one + * + * Return: true if t2 can supersede t1 + * false if t2 can not supersede t1 + */ +static bool binder_can_update_transaction(struct binder_transaction *t1, + struct binder_transaction *t2) +{ + if ((t1->flags & t2->flags & (TF_ONE_WAY | TF_UPDATE_TXN)) != + (TF_ONE_WAY | TF_UPDATE_TXN) || !t1->to_proc || !t2->to_proc) + return false; + if (t1->to_proc->tsk == t2->to_proc->tsk && t1->code == t2->code && + t1->flags == t2->flags && t1->buffer->pid == t2->buffer->pid && + t1->buffer->target_node->ptr == t2->buffer->target_node->ptr && + t1->buffer->target_node->cookie == t2->buffer->target_node->cookie) + return true; + return false; +} + +/** + * binder_find_outdated_transaction_ilocked() - Find the outdated transaction + * @t: new async transaction + * @target_list: list to find outdated transaction + * + * Return: the outdated transaction if found + * NULL if no outdated transacton can be found + * + * Requires the proc->inner_lock to be held. + */ +static struct binder_transaction * +binder_find_outdated_transaction_ilocked(struct binder_transaction *t, + struct list_head *target_list) +{ + struct binder_work *w; + + list_for_each_entry(w, target_list, entry) { + struct binder_transaction *t_queued; + + if (w->type != BINDER_WORK_TRANSACTION) + continue; + t_queued = container_of(w, struct binder_transaction, work); + if (binder_can_update_transaction(t_queued, t)) + return t_queued; + } + return NULL; +} + /** * binder_proc_transaction() - sends a transaction to a process and wakes it up * @t: transaction to send @@ -2491,6 +2577,7 @@ static int binder_proc_transaction(struct binder_transaction *t, bool oneway = !!(t->flags & TF_ONE_WAY); bool pending_async = false; bool skip = false; + struct binder_transaction *t_outdated = NULL; BUG_ON(!node); binder_node_lock(node); @@ -2534,6 +2621,17 @@ static int binder_proc_transaction(struct binder_transaction *t, } else if (!pending_async) { binder_enqueue_work_ilocked(&t->work, &proc->todo); } else { + if ((t->flags & TF_UPDATE_TXN) && proc->is_frozen) { + t_outdated = binder_find_outdated_transaction_ilocked(t, + &node->async_todo); + if (t_outdated) { + binder_debug(BINDER_DEBUG_TRANSACTION, + "txn %d supersedes %d\n", + t->debug_id, t_outdated->debug_id); + list_del_init(&t_outdated->work.entry); + proc->outstanding_txns--; + } + } binder_enqueue_work_ilocked(&t->work, &node->async_todo); } @@ -2547,6 +2645,22 @@ static int binder_proc_transaction(struct binder_transaction *t, binder_inner_proc_unlock(proc); binder_node_unlock(node); + /* + * To reduce potential contention, free the outdated transaction and + * buffer after releasing the locks. + */ + if (t_outdated) { + struct binder_buffer *buffer = t_outdated->buffer; + + t_outdated->buffer = NULL; + buffer->transaction = NULL; + trace_binder_transaction_update_buffer_release(buffer); + binder_transaction_buffer_release(proc, NULL, buffer, 0, 0); + binder_alloc_free_buf(&proc->alloc, buffer); + kfree(t_outdated); + binder_stats_deleted(BINDER_STAT_TRANSACTION); + } + return 0; } @@ -5950,8 +6064,7 @@ static void print_binder_proc_stats(struct seq_file *m, print_binder_stats(m, " ", &proc->stats); } - -int binder_state_show(struct seq_file *m, void *unused) +static int state_show(struct seq_file *m, void *unused) { struct binder_proc *proc; struct binder_node *node; @@ -5990,7 +6103,7 @@ int binder_state_show(struct seq_file *m, void *unused) return 0; } -int binder_stats_show(struct seq_file *m, void *unused) +static int stats_show(struct seq_file *m, void *unused) { struct binder_proc *proc; @@ -6006,7 +6119,7 @@ int binder_stats_show(struct seq_file *m, void *unused) return 0; } -int binder_transactions_show(struct seq_file *m, void *unused) +static int transactions_show(struct seq_file *m, void *unused) { struct binder_proc *proc; @@ -6062,7 +6175,7 @@ static void print_binder_transaction_log_entry(struct seq_file *m, "\n" : " (incomplete)\n"); } -int binder_transaction_log_show(struct seq_file *m, void *unused) +static int transaction_log_show(struct seq_file *m, void *unused) { struct binder_transaction_log *log = m->private; unsigned int log_cur = atomic_read(&log->cur); @@ -6094,6 +6207,45 @@ const struct file_operations binder_fops = { .release = binder_release, }; +DEFINE_SHOW_ATTRIBUTE(state); +DEFINE_SHOW_ATTRIBUTE(stats); +DEFINE_SHOW_ATTRIBUTE(transactions); +DEFINE_SHOW_ATTRIBUTE(transaction_log); + +const struct binder_debugfs_entry binder_debugfs_entries[] = { + { + .name = "state", + .mode = 0444, + .fops = &state_fops, + .data = NULL, + }, + { + .name = "stats", + .mode = 0444, + .fops = &stats_fops, + .data = NULL, + }, + { + .name = "transactions", + .mode = 0444, + .fops = &transactions_fops, + .data = NULL, + }, + { + .name = "transaction_log", + .mode = 0444, + .fops = &transaction_log_fops, + .data = &binder_transaction_log, + }, + { + .name = "failed_transaction_log", + .mode = 0444, + .fops = &transaction_log_fops, + .data = &binder_transaction_log_failed, + }, + {} /* terminator */ +}; + static int __init init_binder_device(const char *name) { int ret; @@ -6139,36 +6291,18 @@ static int __init binder_init(void) atomic_set(&binder_transaction_log_failed.cur, ~0U); binder_debugfs_dir_entry_root = debugfs_create_dir("binder", NULL); - if (binder_debugfs_dir_entry_root) + if (binder_debugfs_dir_entry_root) { + const struct binder_debugfs_entry *db_entry; + + binder_for_each_debugfs_entry(db_entry) + debugfs_create_file(db_entry->name, + db_entry->mode, + binder_debugfs_dir_entry_root, + db_entry->data, + db_entry->fops); + binder_debugfs_dir_entry_proc = debugfs_create_dir("proc", binder_debugfs_dir_entry_root); - - if (binder_debugfs_dir_entry_root) { - debugfs_create_file("state", - 0444, - binder_debugfs_dir_entry_root, - NULL, - &binder_state_fops); - debugfs_create_file("stats", - 0444, - binder_debugfs_dir_entry_root, - NULL, - &binder_stats_fops); - debugfs_create_file("transactions", - 0444, - binder_debugfs_dir_entry_root, - NULL, - &binder_transactions_fops); - debugfs_create_file("transaction_log", - 0444, - binder_debugfs_dir_entry_root, - &binder_transaction_log, - &binder_transaction_log_fops); - debugfs_create_file("failed_transaction_log", - 0444, - binder_debugfs_dir_entry_root, - &binder_transaction_log_failed, - &binder_transaction_log_fops); } if (!IS_ENABLED(CONFIG_ANDROID_BINDERFS) && diff --git a/drivers/android/binder_internal.h b/drivers/android/binder_internal.h index 93f02395b0d7..00010c2e3e3c 100644 --- a/drivers/android/binder_internal.h +++ b/drivers/android/binder_internal.h @@ -107,41 +107,19 @@ static inline int __init init_binderfs(void) } #endif -int binder_stats_show(struct seq_file *m, void *unused); -DEFINE_SHOW_ATTRIBUTE(binder_stats); - -int binder_state_show(struct seq_file *m, void *unused); -DEFINE_SHOW_ATTRIBUTE(binder_state); - -int binder_transactions_show(struct seq_file *m, void *unused); -DEFINE_SHOW_ATTRIBUTE(binder_transactions); - -int binder_transaction_log_show(struct seq_file *m, void *unused); -DEFINE_SHOW_ATTRIBUTE(binder_transaction_log); - -struct binder_transaction_log_entry { - int debug_id; - int debug_id_done; - int call_type; - int from_proc; - int from_thread; - int target_handle; - int to_proc; - int to_thread; - int to_node; - int data_size; - int offsets_size; - int return_error_line; - uint32_t return_error; - uint32_t return_error_param; - char context_name[BINDERFS_MAX_NAME + 1]; +struct binder_debugfs_entry { + const char *name; + umode_t mode; + const struct file_operations *fops; + void *data; }; -struct binder_transaction_log { - atomic_t cur; - bool full; - struct binder_transaction_log_entry entry[32]; -}; +extern const struct binder_debugfs_entry binder_debugfs_entries[]; + +#define binder_for_each_debugfs_entry(entry) \ + for ((entry) = binder_debugfs_entries; \ + (entry)->name; \ + (entry)++) enum binder_stat_types { BINDER_STAT_PROC, @@ -620,6 +598,4 @@ struct binder_object { }; }; -extern struct binder_transaction_log binder_transaction_log; -extern struct binder_transaction_log binder_transaction_log_failed; #endif /* _LINUX_BINDER_INTERNAL_H */ diff --git a/drivers/android/binder_trace.h b/drivers/android/binder_trace.h index a70e23716ad0..8c4a6c3774a1 100644 --- a/drivers/android/binder_trace.h +++ b/drivers/android/binder_trace.h @@ -306,6 +306,10 @@ DEFINE_EVENT(binder_buffer_class, binder_transaction_failed_buffer_release, TP_PROTO(struct binder_buffer *buffer), TP_ARGS(buffer)); +DEFINE_EVENT(binder_buffer_class, binder_transaction_update_buffer_release, + TP_PROTO(struct binder_buffer *buffer), + TP_ARGS(buffer)); + TRACE_EVENT(binder_update_page_range, TP_PROTO(struct binder_alloc *alloc, bool allocate, void __user *start, void __user *end), diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 7b4f154f07e6..2e5fbb3adb09 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -584,6 +584,7 @@ out: static int init_binder_logs(struct super_block *sb) { struct dentry *binder_logs_root_dir, *dentry, *proc_log_dir; + const struct binder_debugfs_entry *db_entry; struct binderfs_info *info; int ret = 0; @@ -594,43 +595,15 @@ static int init_binder_logs(struct super_block *sb) goto out; } - dentry = binderfs_create_file(binder_logs_root_dir, "stats", - &binder_stats_fops, NULL); - if (IS_ERR(dentry)) { - ret = PTR_ERR(dentry); - goto out; - } - - dentry = binderfs_create_file(binder_logs_root_dir, "state", - &binder_state_fops, NULL); - if (IS_ERR(dentry)) { - ret = PTR_ERR(dentry); - goto out; - } - - dentry = binderfs_create_file(binder_logs_root_dir, "transactions", - &binder_transactions_fops, NULL); - if (IS_ERR(dentry)) { - ret = PTR_ERR(dentry); - goto out; - } - - dentry = binderfs_create_file(binder_logs_root_dir, - "transaction_log", - &binder_transaction_log_fops, - &binder_transaction_log); - if (IS_ERR(dentry)) { - ret = PTR_ERR(dentry); - goto out; - } - - dentry = binderfs_create_file(binder_logs_root_dir, - "failed_transaction_log", - &binder_transaction_log_fops, - &binder_transaction_log_failed); - if (IS_ERR(dentry)) { - ret = PTR_ERR(dentry); - goto out; + binder_for_each_debugfs_entry(db_entry) { + dentry = binderfs_create_file(binder_logs_root_dir, + db_entry->name, + db_entry->fops, + db_entry->data); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto out; + } } proc_log_dir = binderfs_create_dir(binder_logs_root_dir, "proc"); diff --git a/drivers/android/vendor_hooks.c b/drivers/android/vendor_hooks.c index a6c589b266da..128f63a76938 100644 --- a/drivers/android/vendor_hooks.c +++ b/drivers/android/vendor_hooks.c @@ -271,7 +271,11 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_exit_mm); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_get_from_fragment_pool); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_exclude_reserved_zone); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_include_reserved_zone); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_alloc_pages_slowpath_begin); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_alloc_pages_slowpath_end); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_show_mem); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_show_mapcount_pages); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_do_traversal_lruvec); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_typec_tcpci_override_toggling); EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_typec_tcpci_chk_contaminant); EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_typec_tcpci_get_vbus); @@ -300,6 +304,11 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_logbuf_pr_cont); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_tune_scan_type); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_tune_swappiness); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_shrink_slab_bypass); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_handle_failed_page_trylock); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_page_trylock_set); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_page_trylock_clear); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_page_trylock_get_result); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_do_page_trylock); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_page_referenced_check_bypass); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_drain_all_pages_bypass); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_cma_drain_all_pages_bypass); @@ -336,6 +345,7 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_mmc_attach_sd); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_sdhci_get_cd); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_mmc_gpio_cd_irqt); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_save_vmalloc_stack); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_remove_vmalloc_stack); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_show_stack_hash); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_save_track_hash); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_vmpressure); @@ -390,6 +400,11 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_tcp_recvmsg_stat); EXPORT_TRACEPOINT_SYMBOL_GPL(android_rvh_pci_d3_sleep); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_kmalloc_slab); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_mmap_region); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_update_page_mapcount); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_add_page_to_lrulist); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_del_page_from_lrulist); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_page_should_be_protected); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_mark_page_accessed); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_try_to_unmap_one); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_mem_cgroup_id_remove); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_mem_cgroup_css_offline); @@ -430,3 +445,7 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_init_swap_info_struct); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_si_swapinfo); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_alloc_si); EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_free_pages); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_set_shmem_page_flag); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_pidfd_open); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_mmput); +EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_sched_pelt_multiplier); diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index 2591b973a31b..6f0ba38aaeea 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -50,6 +50,11 @@ struct iommu_dma_cookie { struct iommu_domain *fq_domain; }; +struct iommu_dma_cookie_ext { + struct iommu_dma_cookie cookie; + struct mutex mutex; +}; + static inline size_t cookie_msi_granule(struct iommu_dma_cookie *cookie) { if (cookie->type == IOMMU_DMA_IOVA_COOKIE) @@ -59,14 +64,15 @@ static inline size_t cookie_msi_granule(struct iommu_dma_cookie *cookie) static struct iommu_dma_cookie *cookie_alloc(enum iommu_dma_cookie_type type) { - struct iommu_dma_cookie *cookie; + struct iommu_dma_cookie_ext *cookie; cookie = kzalloc(sizeof(*cookie), GFP_KERNEL); if (cookie) { - INIT_LIST_HEAD(&cookie->msi_page_list); - cookie->type = type; + INIT_LIST_HEAD(&cookie->cookie.msi_page_list); + cookie->cookie.type = type; + mutex_init(&cookie->mutex); } - return cookie; + return &cookie->cookie; } /** @@ -305,9 +311,11 @@ static int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base, u64 size, struct device *dev) { struct iommu_dma_cookie *cookie = domain->iova_cookie; + struct iommu_dma_cookie_ext *cookie_ext; unsigned long order, base_pfn; struct iova_domain *iovad; int attr; + int ret; if (!cookie || cookie->type != IOMMU_DMA_IOVA_COOKIE) return -EINVAL; @@ -331,14 +339,18 @@ static int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base, } /* start_pfn is always nonzero for an already-initialised domain */ + cookie_ext = container_of(cookie, struct iommu_dma_cookie_ext, cookie); + mutex_lock(&cookie_ext->mutex); if (iovad->start_pfn) { if (1UL << order != iovad->granule || base_pfn != iovad->start_pfn) { pr_warn("Incompatible range for DMA domain\n"); - return -EFAULT; + ret = -EFAULT; + goto done_unlock; } - return 0; + ret = 0; + goto done_unlock; } init_iova_domain(iovad, 1UL << order, base_pfn); @@ -352,10 +364,16 @@ static int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base, cookie->fq_domain = domain; } - if (!dev) - return 0; + if (!dev) { + ret = 0; + goto done_unlock; + } - return iova_reserve_iommu_regions(dev, domain); + ret = iova_reserve_iommu_regions(dev, domain); + +done_unlock: + mutex_unlock(&cookie_ext->mutex); + return ret; } static int iommu_dma_deferred_attach(struct device *dev, diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index acea970df067..cd34f1c4f77d 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -466,9 +466,7 @@ static void __iomem *dw_pcie_other_conf_map_bus(struct pci_bus *bus, type = PCIE_ATU_TYPE_CFG1; - dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1, - type, pp->cfg0_base, - busdev, pp->cfg0_size); + dw_pcie_prog_outbound_atu(pci, 0, type, pp->cfg0_base, busdev, pp->cfg0_size); return pp->va_cfg0_base + where; } @@ -482,9 +480,8 @@ static int dw_pcie_rd_other_conf(struct pci_bus *bus, unsigned int devfn, ret = pci_generic_config_read(bus, devfn, where, size, val); - if (!ret && pci->num_viewport <= 2) - dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1, - PCIE_ATU_TYPE_IO, pp->io_base, + if (!ret && (pci->iatu_unroll_enabled & DWC_IATU_IOCFG_SHARED)) + dw_pcie_prog_outbound_atu(pci, 0, PCIE_ATU_TYPE_IO, pp->io_base, pp->io_bus_addr, pp->io_size); return ret; @@ -499,9 +496,8 @@ static int dw_pcie_wr_other_conf(struct pci_bus *bus, unsigned int devfn, ret = pci_generic_config_write(bus, devfn, where, size, val); - if (!ret && pci->num_viewport <= 2) - dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1, - PCIE_ATU_TYPE_IO, pp->io_base, + if (!ret && (pci->iatu_unroll_enabled & DWC_IATU_IOCFG_SHARED)) + dw_pcie_prog_outbound_atu(pci, 0, PCIE_ATU_TYPE_IO, pp->io_base, pp->io_bus_addr, pp->io_size); return ret; @@ -588,21 +584,35 @@ void dw_pcie_setup_rc(struct pcie_port *pp) * ATU, so we should not program the ATU here. */ if (pp->bridge->child_ops == &dw_child_pcie_ops) { - struct resource_entry *tmp, *entry = NULL; + int atu_idx = 0; + struct resource_entry *entry; /* Get last memory resource entry */ - resource_list_for_each_entry(tmp, &pp->bridge->windows) - if (resource_type(tmp->res) == IORESOURCE_MEM) - entry = tmp; + resource_list_for_each_entry(entry, &pp->bridge->windows) { + if (resource_type(entry->res) != IORESOURCE_MEM) + continue; - dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0, - PCIE_ATU_TYPE_MEM, entry->res->start, - entry->res->start - entry->offset, - resource_size(entry->res)); - if (pci->num_viewport > 2) - dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX2, - PCIE_ATU_TYPE_IO, pp->io_base, - pp->io_bus_addr, pp->io_size); + if (pci->num_viewport <= ++atu_idx) + break; + + dw_pcie_prog_outbound_atu(pci, atu_idx, + PCIE_ATU_TYPE_MEM, entry->res->start, + entry->res->start - entry->offset, + resource_size(entry->res)); + } + + if (pp->io_size) { + if (pci->num_viewport > ++atu_idx) + dw_pcie_prog_outbound_atu(pci, atu_idx, + PCIE_ATU_TYPE_IO, pp->io_base, + pp->io_bus_addr, pp->io_size); + else + pci->iatu_unroll_enabled |= DWC_IATU_IOCFG_SHARED; + } + + if (pci->num_viewport <= atu_idx) + dev_warn(pci->dev, "Resources exceed number of ATU entries (%d)", + pci->num_viewport); } dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0); diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index c85e128bc0ea..5c6c3a986600 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -274,7 +274,7 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no, if (pci->ops->cpu_addr_fixup) cpu_addr = pci->ops->cpu_addr_fixup(pci, cpu_addr); - if (pci->iatu_unroll_enabled) { + if (pci->iatu_unroll_enabled & DWC_IATU_UNROLL_EN) { dw_pcie_prog_outbound_atu_unroll(pci, func_no, index, type, cpu_addr, pci_addr, size); return; @@ -394,7 +394,7 @@ int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index, int type; u32 retries, val; - if (pci->iatu_unroll_enabled) + if (pci->iatu_unroll_enabled & DWC_IATU_UNROLL_EN) return dw_pcie_prog_inbound_atu_unroll(pci, func_no, index, bar, cpu_addr, as_type); @@ -554,14 +554,15 @@ void dw_pcie_setup(struct dw_pcie *pci) if (pci->version >= 0x480A || (!pci->version && dw_pcie_iatu_unroll_enabled(pci))) { - pci->iatu_unroll_enabled = true; + pci->iatu_unroll_enabled |= DWC_IATU_UNROLL_EN; if (!pci->atu_base) pci->atu_base = devm_platform_ioremap_resource_byname(pdev, "atu"); if (IS_ERR(pci->atu_base)) pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET; } - dev_dbg(pci->dev, "iATU unroll: %s\n", pci->iatu_unroll_enabled ? + dev_dbg(pci->dev, "iATU unroll: %s\n", + pci->iatu_unroll_enabled & DWC_IATU_UNROLL_EN ? "enabled" : "disabled"); if (pci->link_gen > 0) diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 9d2f511f13fa..98084e8489ec 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -80,9 +80,6 @@ #define PCIE_ATU_VIEWPORT 0x900 #define PCIE_ATU_REGION_INBOUND BIT(31) #define PCIE_ATU_REGION_OUTBOUND 0 -#define PCIE_ATU_REGION_INDEX2 0x2 -#define PCIE_ATU_REGION_INDEX1 0x1 -#define PCIE_ATU_REGION_INDEX0 0x0 #define PCIE_ATU_CR1 0x904 #define PCIE_ATU_TYPE_MEM 0x0 #define PCIE_ATU_TYPE_IO 0x2 @@ -259,6 +256,8 @@ struct dw_pcie_ops { void (*stop_link)(struct dw_pcie *pcie); }; +#define DWC_IATU_UNROLL_EN BIT(0) +#define DWC_IATU_IOCFG_SHARED BIT(1) struct dw_pcie { struct device *dev; void __iomem *dbi_base; diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index fb6de3cde2ab..a0316033197d 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -156,8 +156,13 @@ static void __dwc3_set_mode(struct work_struct *work) break; } - /* For DRD host or device mode only */ - if (dwc->desired_dr_role != DWC3_GCTL_PRTCAP_OTG) { + /* + * When current_dr_role is not set, there's no role switching. + * Only perform GCTL.CoreSoftReset when there's DRD role switching. + */ + if (dwc->current_dr_role && ((DWC3_IP_IS(DWC3) || + DWC3_VER_IS_PRIOR(DWC31, 190A)) && + dwc->desired_dr_role != DWC3_GCTL_PRTCAP_OTG)) { reg = dwc3_readl(dwc->regs, DWC3_GCTL); reg |= DWC3_GCTL_CORESOFTRESET; dwc3_writel(dwc->regs, DWC3_GCTL, reg); diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 0dad4b1405ae..7377d1a599ea 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2471,6 +2471,10 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) int ret; is_on = !!is_on; + + if (dwc->pullups_connected == is_on) + return 0; + vdwc->softconnect = is_on; /* diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c index e65f474ad7b3..6f0e1d803dc2 100644 --- a/drivers/usb/gadget/function/f_uac1.c +++ b/drivers/usb/gadget/function/f_uac1.c @@ -3,6 +3,7 @@ * f_uac1.c -- USB Audio Class 1.0 Function (using u_audio API) * * Copyright (C) 2016 Ruslan Bilovol + * Copyright (C) 2021 Julian Scheel * * This driver doesn't expect any real Audio codec to be present * on the device - the audio streams are simply sinked to and @@ -22,10 +23,29 @@ /* UAC1 spec: 3.7.2.3 Audio Channel Cluster Format */ #define UAC1_CHANNEL_MASK 0x0FFF +#define USB_OUT_FU_ID (out_feature_unit_desc->bUnitID) +#define USB_IN_FU_ID (in_feature_unit_desc->bUnitID) + +#define EPIN_EN(_opts) ((_opts)->p_chmask != 0) +#define EPOUT_EN(_opts) ((_opts)->c_chmask != 0) +#define FUIN_EN(_opts) ((_opts)->p_mute_present \ + || (_opts)->p_volume_present) +#define FUOUT_EN(_opts) ((_opts)->c_mute_present \ + || (_opts)->c_volume_present) + struct f_uac1 { struct g_audio g_audio; u8 ac_intf, as_in_intf, as_out_intf; u8 ac_alt, as_in_alt, as_out_alt; /* needed for get_alt() */ + + struct usb_ctrlrequest setup_cr; /* will be used in data stage */ + + /* Interrupt IN endpoint of AC interface */ + struct usb_ep *int_ep; + atomic_t int_count; + int ctl_id; /* EP id */ + int c_srate; /* current capture srate */ + int p_srate; /* current playback prate */ }; static inline struct f_uac1 *func_to_uac1(struct usb_function *f) @@ -50,88 +70,70 @@ static inline struct f_uac1_opts *g_audio_to_uac1_opts(struct g_audio *audio) * USB-OUT -> IT_1 -> OT_2 -> ALSA_Capture * ALSA_Playback -> IT_3 -> OT_4 -> USB-IN */ -#define F_AUDIO_AC_INTERFACE 0 -#define F_AUDIO_AS_OUT_INTERFACE 1 -#define F_AUDIO_AS_IN_INTERFACE 2 -/* Number of streaming interfaces */ -#define F_AUDIO_NUM_INTERFACES 2 /* B.3.1 Standard AC Interface Descriptor */ static struct usb_interface_descriptor ac_interface_desc = { .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, - .bNumEndpoints = 0, + /* .bNumEndpoints = DYNAMIC */ .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, }; -/* - * The number of AudioStreaming and MIDIStreaming interfaces - * in the Audio Interface Collection - */ -DECLARE_UAC_AC_HEADER_DESCRIPTOR(2); - -#define UAC_DT_AC_HEADER_LENGTH UAC_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES) -/* 2 input terminals and 2 output terminals */ -#define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH \ - + 2*UAC_DT_INPUT_TERMINAL_SIZE + 2*UAC_DT_OUTPUT_TERMINAL_SIZE) /* B.3.2 Class-Specific AC Interface Descriptor */ -static struct uac1_ac_header_descriptor_2 ac_header_desc = { - .bLength = UAC_DT_AC_HEADER_LENGTH, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubtype = UAC_HEADER, - .bcdADC = cpu_to_le16(0x0100), - .wTotalLength = cpu_to_le16(UAC_DT_TOTAL_LENGTH), - .bInCollection = F_AUDIO_NUM_INTERFACES, - .baInterfaceNr = { - /* Interface number of the AudioStream interfaces */ - [0] = 1, - [1] = 2, - } -}; +static struct uac1_ac_header_descriptor *ac_header_desc; -#define USB_OUT_IT_ID 1 static struct uac_input_terminal_descriptor usb_out_it_desc = { .bLength = UAC_DT_INPUT_TERMINAL_SIZE, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_INPUT_TERMINAL, - .bTerminalID = USB_OUT_IT_ID, + /* .bTerminalID = DYNAMIC */ .wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING), .bAssocTerminal = 0, .wChannelConfig = cpu_to_le16(0x3), }; -#define IO_OUT_OT_ID 2 static struct uac1_output_terminal_descriptor io_out_ot_desc = { .bLength = UAC_DT_OUTPUT_TERMINAL_SIZE, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, - .bTerminalID = IO_OUT_OT_ID, + /* .bTerminalID = DYNAMIC */ .wTerminalType = cpu_to_le16(UAC_OUTPUT_TERMINAL_SPEAKER), .bAssocTerminal = 0, - .bSourceID = USB_OUT_IT_ID, + /* .bSourceID = DYNAMIC */ }; -#define IO_IN_IT_ID 3 static struct uac_input_terminal_descriptor io_in_it_desc = { .bLength = UAC_DT_INPUT_TERMINAL_SIZE, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_INPUT_TERMINAL, - .bTerminalID = IO_IN_IT_ID, + /* .bTerminalID = DYNAMIC */ .wTerminalType = cpu_to_le16(UAC_INPUT_TERMINAL_MICROPHONE), .bAssocTerminal = 0, .wChannelConfig = cpu_to_le16(0x3), }; -#define USB_IN_OT_ID 4 static struct uac1_output_terminal_descriptor usb_in_ot_desc = { .bLength = UAC_DT_OUTPUT_TERMINAL_SIZE, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, - .bTerminalID = USB_IN_OT_ID, + /* .bTerminalID = DYNAMIC */ .wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING), .bAssocTerminal = 0, - .bSourceID = IO_IN_IT_ID, + /* .bSourceID = DYNAMIC */ +}; + +static struct uac_feature_unit_descriptor *in_feature_unit_desc; +static struct uac_feature_unit_descriptor *out_feature_unit_desc; + +/* AC IN Interrupt Endpoint */ +static struct usb_endpoint_descriptor ac_int_ep_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = cpu_to_le16(2), + .bInterval = 4, }; /* B.4.1 Standard AS Interface Descriptor */ @@ -176,7 +178,7 @@ static struct uac1_as_header_descriptor as_out_header_desc = { .bLength = UAC_DT_AS_HEADER_SIZE, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_AS_GENERAL, - .bTerminalLink = USB_OUT_IT_ID, + /* .bTerminalLink = DYNAMIC */ .bDelay = 1, .wFormatTag = cpu_to_le16(UAC_FORMAT_TYPE_I_PCM), }; @@ -185,21 +187,23 @@ static struct uac1_as_header_descriptor as_in_header_desc = { .bLength = UAC_DT_AS_HEADER_SIZE, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_AS_GENERAL, - .bTerminalLink = USB_IN_OT_ID, + /* .bTerminalLink = DYNAMIC */ .bDelay = 1, .wFormatTag = cpu_to_le16(UAC_FORMAT_TYPE_I_PCM), }; -DECLARE_UAC_FORMAT_TYPE_I_DISCRETE_DESC(1); +DECLARE_UAC_FORMAT_TYPE_I_DISCRETE_DESC(UAC_MAX_RATES); +#define uac_format_type_i_discrete_descriptor \ + uac_format_type_i_discrete_descriptor_##UAC_MAX_RATES -static struct uac_format_type_i_discrete_descriptor_1 as_out_type_i_desc = { - .bLength = UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1), +static struct uac_format_type_i_discrete_descriptor as_out_type_i_desc = { + .bLength = 0, /* filled on rate setup */ .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_FORMAT_TYPE, .bFormatType = UAC_FORMAT_TYPE_I, .bSubframeSize = 2, .bBitResolution = 16, - .bSamFreqType = 1, + .bSamFreqType = 0, /* filled on rate setup */ }; /* Standard ISO OUT Endpoint Descriptor */ @@ -223,14 +227,14 @@ static struct uac_iso_endpoint_descriptor as_iso_out_desc = { .wLockDelay = cpu_to_le16(1), }; -static struct uac_format_type_i_discrete_descriptor_1 as_in_type_i_desc = { - .bLength = UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1), +static struct uac_format_type_i_discrete_descriptor as_in_type_i_desc = { + .bLength = 0, /* filled on rate setup */ .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_FORMAT_TYPE, .bFormatType = UAC_FORMAT_TYPE_I, .bSubframeSize = 2, .bBitResolution = 16, - .bSamFreqType = 1, + .bSamFreqType = 0, /* filled on rate setup */ }; /* Standard ISO OUT Endpoint Descriptor */ @@ -260,8 +264,13 @@ static struct usb_descriptor_header *f_audio_desc[] = { (struct usb_descriptor_header *)&usb_out_it_desc, (struct usb_descriptor_header *)&io_out_ot_desc, + (struct usb_descriptor_header *)&out_feature_unit_desc, + (struct usb_descriptor_header *)&io_in_it_desc, (struct usb_descriptor_header *)&usb_in_ot_desc, + (struct usb_descriptor_header *)&in_feature_unit_desc, + + (struct usb_descriptor_header *)&ac_int_ep_desc, (struct usb_descriptor_header *)&as_out_interface_alt_0_desc, (struct usb_descriptor_header *)&as_out_interface_alt_1_desc, @@ -291,6 +300,8 @@ enum { STR_IO_IN_IT, STR_IO_IN_IT_CH_NAMES, STR_USB_IN_OT, + STR_FU_IN, + STR_FU_OUT, STR_AS_OUT_IF_ALT0, STR_AS_OUT_IF_ALT1, STR_AS_IN_IF_ALT0, @@ -298,13 +309,15 @@ enum { }; static struct usb_string strings_uac1[] = { - [STR_AC_IF].s = "AC Interface", + /* [STR_AC_IF].s = DYNAMIC, */ [STR_USB_OUT_IT].s = "Playback Input terminal", [STR_USB_OUT_IT_CH_NAMES].s = "Playback Channels", [STR_IO_OUT_OT].s = "Playback Output terminal", [STR_IO_IN_IT].s = "Capture Input terminal", [STR_IO_IN_IT_CH_NAMES].s = "Capture Channels", [STR_USB_IN_OT].s = "Capture Output terminal", + [STR_FU_IN].s = "Capture Volume", + [STR_FU_OUT].s = "Playback Volume", [STR_AS_OUT_IF_ALT0].s = "Playback Inactive", [STR_AS_OUT_IF_ALT1].s = "Playback Active", [STR_AS_IN_IF_ALT0].s = "Capture Inactive", @@ -326,22 +339,425 @@ static struct usb_gadget_strings *uac1_strings[] = { * This function is an ALSA sound card following USB Audio Class Spec 1.0. */ -static int audio_set_endpoint_req(struct usb_function *f, +static void uac_cs_attr_sample_rate(struct usb_ep *ep, struct usb_request *req) +{ + struct usb_function *fn = ep->driver_data; + struct usb_composite_dev *cdev = fn->config->cdev; + struct g_audio *agdev = func_to_g_audio(fn); + struct f_uac1 *uac1 = func_to_uac1(fn); + u8 *buf = (u8 *)req->buf; + u32 val = 0; + + if (req->actual != 3) { + WARN(cdev, "Invalid data size for UAC_EP_CS_ATTR_SAMPLE_RATE.\n"); + return; + } + + val = buf[0] | (buf[1] << 8) | (buf[2] << 16); + if (uac1->ctl_id == (USB_DIR_IN | 2)) { + uac1->p_srate = val; + u_audio_set_playback_srate(agdev, uac1->p_srate); + } else if (uac1->ctl_id == (USB_DIR_OUT | 1)) { + uac1->c_srate = val; + u_audio_set_capture_srate(agdev, uac1->c_srate); + } +} + +static void audio_notify_complete(struct usb_ep *_ep, struct usb_request *req) +{ + struct g_audio *audio = req->context; + struct f_uac1 *uac1 = func_to_uac1(&audio->func); + + atomic_dec(&uac1->int_count); + kfree(req->buf); + usb_ep_free_request(_ep, req); +} + +static int audio_notify(struct g_audio *audio, int unit_id, int cs) +{ + struct f_uac1 *uac1 = func_to_uac1(&audio->func); + struct usb_request *req; + struct uac1_status_word *msg; + int ret; + + if (!uac1->int_ep->enabled) + return 0; + + if (atomic_inc_return(&uac1->int_count) > UAC1_DEF_INT_REQ_NUM) { + atomic_dec(&uac1->int_count); + return 0; + } + + req = usb_ep_alloc_request(uac1->int_ep, GFP_ATOMIC); + if (req == NULL) { + ret = -ENOMEM; + goto err_dec_int_count; + } + + msg = kmalloc(sizeof(*msg), GFP_ATOMIC); + if (msg == NULL) { + ret = -ENOMEM; + goto err_free_request; + } + + msg->bStatusType = UAC1_STATUS_TYPE_IRQ_PENDING + | UAC1_STATUS_TYPE_ORIG_AUDIO_CONTROL_IF; + msg->bOriginator = unit_id; + + req->length = sizeof(*msg); + req->buf = msg; + req->context = audio; + req->complete = audio_notify_complete; + + ret = usb_ep_queue(uac1->int_ep, req, GFP_ATOMIC); + + if (ret) + goto err_free_msg; + + return 0; + +err_free_msg: + kfree(msg); +err_free_request: + usb_ep_free_request(uac1->int_ep, req); +err_dec_int_count: + atomic_dec(&uac1->int_count); + + return ret; +} + +static int +in_rq_cur(struct usb_function *fn, const struct usb_ctrlrequest *cr) +{ + struct usb_request *req = fn->config->cdev->req; + struct g_audio *audio = func_to_g_audio(fn); + struct f_uac1_opts *opts = g_audio_to_uac1_opts(audio); + u16 w_length = le16_to_cpu(cr->wLength); + u16 w_index = le16_to_cpu(cr->wIndex); + u16 w_value = le16_to_cpu(cr->wValue); + u8 entity_id = (w_index >> 8) & 0xff; + u8 control_selector = w_value >> 8; + int value = -EOPNOTSUPP; + + if ((FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) || + (FUOUT_EN(opts) && (entity_id == USB_OUT_FU_ID))) { + unsigned int is_playback = 0; + + if (FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) + is_playback = 1; + + if (control_selector == UAC_FU_MUTE) { + unsigned int mute; + + u_audio_get_mute(audio, is_playback, &mute); + + *(u8 *)req->buf = mute; + value = min_t(unsigned int, w_length, 1); + } else if (control_selector == UAC_FU_VOLUME) { + __le16 c; + s16 volume; + + u_audio_get_volume(audio, is_playback, &volume); + + c = cpu_to_le16(volume); + + value = min_t(unsigned int, w_length, sizeof(c)); + memcpy(req->buf, &c, value); + } else { + dev_err(&audio->gadget->dev, + "%s:%d control_selector=%d TODO!\n", + __func__, __LINE__, control_selector); + } + } else { + dev_err(&audio->gadget->dev, + "%s:%d entity_id=%d control_selector=%d TODO!\n", + __func__, __LINE__, entity_id, control_selector); + } + + return value; +} + +static int +in_rq_min(struct usb_function *fn, const struct usb_ctrlrequest *cr) +{ + struct usb_request *req = fn->config->cdev->req; + struct g_audio *audio = func_to_g_audio(fn); + struct f_uac1_opts *opts = g_audio_to_uac1_opts(audio); + u16 w_length = le16_to_cpu(cr->wLength); + u16 w_index = le16_to_cpu(cr->wIndex); + u16 w_value = le16_to_cpu(cr->wValue); + u8 entity_id = (w_index >> 8) & 0xff; + u8 control_selector = w_value >> 8; + int value = -EOPNOTSUPP; + + if ((FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) || + (FUOUT_EN(opts) && (entity_id == USB_OUT_FU_ID))) { + unsigned int is_playback = 0; + + if (FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) + is_playback = 1; + + if (control_selector == UAC_FU_VOLUME) { + __le16 r; + s16 min_db; + + if (is_playback) + min_db = opts->p_volume_min; + else + min_db = opts->c_volume_min; + + r = cpu_to_le16(min_db); + + value = min_t(unsigned int, w_length, sizeof(r)); + memcpy(req->buf, &r, value); + } else { + dev_err(&audio->gadget->dev, + "%s:%d control_selector=%d TODO!\n", + __func__, __LINE__, control_selector); + } + } else { + dev_err(&audio->gadget->dev, + "%s:%d entity_id=%d control_selector=%d TODO!\n", + __func__, __LINE__, entity_id, control_selector); + } + + return value; +} + +static int +in_rq_max(struct usb_function *fn, const struct usb_ctrlrequest *cr) +{ + struct usb_request *req = fn->config->cdev->req; + struct g_audio *audio = func_to_g_audio(fn); + struct f_uac1_opts *opts = g_audio_to_uac1_opts(audio); + u16 w_length = le16_to_cpu(cr->wLength); + u16 w_index = le16_to_cpu(cr->wIndex); + u16 w_value = le16_to_cpu(cr->wValue); + u8 entity_id = (w_index >> 8) & 0xff; + u8 control_selector = w_value >> 8; + int value = -EOPNOTSUPP; + + if ((FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) || + (FUOUT_EN(opts) && (entity_id == USB_OUT_FU_ID))) { + unsigned int is_playback = 0; + + if (FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) + is_playback = 1; + + if (control_selector == UAC_FU_VOLUME) { + __le16 r; + s16 max_db; + + if (is_playback) + max_db = opts->p_volume_max; + else + max_db = opts->c_volume_max; + + r = cpu_to_le16(max_db); + + value = min_t(unsigned int, w_length, sizeof(r)); + memcpy(req->buf, &r, value); + } else { + dev_err(&audio->gadget->dev, + "%s:%d control_selector=%d TODO!\n", + __func__, __LINE__, control_selector); + } + } else { + dev_err(&audio->gadget->dev, + "%s:%d entity_id=%d control_selector=%d TODO!\n", + __func__, __LINE__, entity_id, control_selector); + } + + return value; +} + +static int +in_rq_res(struct usb_function *fn, const struct usb_ctrlrequest *cr) +{ + struct usb_request *req = fn->config->cdev->req; + struct g_audio *audio = func_to_g_audio(fn); + struct f_uac1_opts *opts = g_audio_to_uac1_opts(audio); + u16 w_length = le16_to_cpu(cr->wLength); + u16 w_index = le16_to_cpu(cr->wIndex); + u16 w_value = le16_to_cpu(cr->wValue); + u8 entity_id = (w_index >> 8) & 0xff; + u8 control_selector = w_value >> 8; + int value = -EOPNOTSUPP; + + if ((FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) || + (FUOUT_EN(opts) && (entity_id == USB_OUT_FU_ID))) { + unsigned int is_playback = 0; + + if (FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) + is_playback = 1; + + if (control_selector == UAC_FU_VOLUME) { + __le16 r; + s16 res_db; + + if (is_playback) + res_db = opts->p_volume_res; + else + res_db = opts->c_volume_res; + + r = cpu_to_le16(res_db); + + value = min_t(unsigned int, w_length, sizeof(r)); + memcpy(req->buf, &r, value); + } else { + dev_err(&audio->gadget->dev, + "%s:%d control_selector=%d TODO!\n", + __func__, __LINE__, control_selector); + } + } else { + dev_err(&audio->gadget->dev, + "%s:%d entity_id=%d control_selector=%d TODO!\n", + __func__, __LINE__, entity_id, control_selector); + } + + return value; +} + +static void +out_rq_cur_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct g_audio *audio = req->context; + struct usb_composite_dev *cdev = audio->func.config->cdev; + struct f_uac1_opts *opts = g_audio_to_uac1_opts(audio); + struct f_uac1 *uac1 = func_to_uac1(&audio->func); + struct usb_ctrlrequest *cr = &uac1->setup_cr; + u16 w_index = le16_to_cpu(cr->wIndex); + u16 w_value = le16_to_cpu(cr->wValue); + u8 entity_id = (w_index >> 8) & 0xff; + u8 control_selector = w_value >> 8; + + if (req->status != 0) { + dev_dbg(&cdev->gadget->dev, "completion err %d\n", req->status); + return; + } + + if ((FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) || + (FUOUT_EN(opts) && (entity_id == USB_OUT_FU_ID))) { + unsigned int is_playback = 0; + + if (FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) + is_playback = 1; + + if (control_selector == UAC_FU_MUTE) { + u8 mute = *(u8 *)req->buf; + + u_audio_set_mute(audio, is_playback, mute); + + return; + } else if (control_selector == UAC_FU_VOLUME) { + __le16 *c = req->buf; + s16 volume; + + volume = le16_to_cpu(*c); + u_audio_set_volume(audio, is_playback, volume); + + return; + } else { + dev_err(&audio->gadget->dev, + "%s:%d control_selector=%d TODO!\n", + __func__, __LINE__, control_selector); + usb_ep_set_halt(ep); + } + } else { + dev_err(&audio->gadget->dev, + "%s:%d entity_id=%d control_selector=%d TODO!\n", + __func__, __LINE__, entity_id, control_selector); + usb_ep_set_halt(ep); + + } +} + +static int +out_rq_cur(struct usb_function *fn, const struct usb_ctrlrequest *cr) +{ + struct usb_request *req = fn->config->cdev->req; + struct g_audio *audio = func_to_g_audio(fn); + struct f_uac1_opts *opts = g_audio_to_uac1_opts(audio); + struct f_uac1 *uac1 = func_to_uac1(&audio->func); + u16 w_length = le16_to_cpu(cr->wLength); + u16 w_index = le16_to_cpu(cr->wIndex); + u16 w_value = le16_to_cpu(cr->wValue); + u8 entity_id = (w_index >> 8) & 0xff; + u8 control_selector = w_value >> 8; + + if ((FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) || + (FUOUT_EN(opts) && (entity_id == USB_OUT_FU_ID))) { + memcpy(&uac1->setup_cr, cr, sizeof(*cr)); + req->context = audio; + req->complete = out_rq_cur_complete; + + return w_length; + } else { + dev_err(&audio->gadget->dev, + "%s:%d entity_id=%d control_selector=%d TODO!\n", + __func__, __LINE__, entity_id, control_selector); + } + return -EOPNOTSUPP; +} + +static int ac_rq_in(struct usb_function *f, const struct usb_ctrlrequest *ctrl) { struct usb_composite_dev *cdev = f->config->cdev; - int value = -EOPNOTSUPP; - u16 ep = le16_to_cpu(ctrl->wIndex); - u16 len = le16_to_cpu(ctrl->wLength); - u16 w_value = le16_to_cpu(ctrl->wValue); + int value = -EOPNOTSUPP; + u8 ep = ((le16_to_cpu(ctrl->wIndex) >> 8) & 0xFF); + u16 len = le16_to_cpu(ctrl->wLength); + u16 w_value = le16_to_cpu(ctrl->wValue); DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n", ctrl->bRequest, w_value, len, ep); switch (ctrl->bRequest) { - case UAC_SET_CUR: + case UAC_GET_CUR: + return in_rq_cur(f, ctrl); + case UAC_GET_MIN: + return in_rq_min(f, ctrl); + case UAC_GET_MAX: + return in_rq_max(f, ctrl); + case UAC_GET_RES: + return in_rq_res(f, ctrl); + case UAC_GET_MEM: + break; + case UAC_GET_STAT: value = len; break; + default: + break; + } + + return value; +} + +static int audio_set_endpoint_req(struct usb_function *f, + const struct usb_ctrlrequest *ctrl) +{ + struct usb_composite_dev *cdev = f->config->cdev; + struct usb_request *req = f->config->cdev->req; + struct f_uac1 *uac1 = func_to_uac1(f); + int value = -EOPNOTSUPP; + u16 ep = le16_to_cpu(ctrl->wIndex); + u16 len = le16_to_cpu(ctrl->wLength); + u16 w_value = le16_to_cpu(ctrl->wValue); + u8 cs = w_value >> 8; + + DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n", + ctrl->bRequest, w_value, len, ep); + + switch (ctrl->bRequest) { + case UAC_SET_CUR: { + if (cs == UAC_EP_CS_ATTR_SAMPLE_RATE) { + cdev->gadget->ep0->driver_data = f; + uac1->ctl_id = ep; + req->complete = uac_cs_attr_sample_rate; + } + value = len; + break; + } case UAC_SET_MIN: break; @@ -366,16 +782,33 @@ static int audio_get_endpoint_req(struct usb_function *f, const struct usb_ctrlrequest *ctrl) { struct usb_composite_dev *cdev = f->config->cdev; + struct usb_request *req = f->config->cdev->req; + struct f_uac1 *uac1 = func_to_uac1(f); + u8 *buf = (u8 *)req->buf; int value = -EOPNOTSUPP; - u8 ep = ((le16_to_cpu(ctrl->wIndex) >> 8) & 0xFF); + u8 ep = le16_to_cpu(ctrl->wIndex); u16 len = le16_to_cpu(ctrl->wLength); u16 w_value = le16_to_cpu(ctrl->wValue); + u8 cs = w_value >> 8; + u32 val = 0; DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n", ctrl->bRequest, w_value, len, ep); switch (ctrl->bRequest) { - case UAC_GET_CUR: + case UAC_GET_CUR: { + if (cs == UAC_EP_CS_ATTR_SAMPLE_RATE) { + if (ep == (USB_DIR_IN | 2)) + val = uac1->p_srate; + else if (ep == (USB_DIR_OUT | 1)) + val = uac1->c_srate; + buf[2] = (val >> 16) & 0xff; + buf[1] = (val >> 8) & 0xff; + buf[0] = val & 0xff; + } + value = len; + break; + } case UAC_GET_MIN: case UAC_GET_MAX: case UAC_GET_RES: @@ -411,7 +844,13 @@ f_audio_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT: value = audio_get_endpoint_req(f, ctrl); break; - + case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE: + if (ctrl->bRequest == UAC_SET_CUR) + value = out_rq_cur(f, ctrl); + break; + case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE: + value = ac_rq_in(f, ctrl); + break; default: ERROR(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n", ctrl->bRequestType, ctrl->bRequest, @@ -439,6 +878,7 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt) struct usb_composite_dev *cdev = f->config->cdev; struct usb_gadget *gadget = cdev->gadget; struct device *dev = &gadget->dev; + struct g_audio *audio = func_to_g_audio(f); struct f_uac1 *uac1 = func_to_uac1(f); int ret = 0; @@ -454,6 +894,14 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt) dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); return -EINVAL; } + + /* restart interrupt endpoint */ + if (uac1->int_ep) { + usb_ep_disable(uac1->int_ep); + config_ep_by_speed(gadget, &audio->func, uac1->int_ep); + usb_ep_enable(uac1->int_ep); + } + return 0; } @@ -509,9 +957,167 @@ static void f_audio_disable(struct usb_function *f) u_audio_stop_playback(&uac1->g_audio); u_audio_stop_capture(&uac1->g_audio); + if (uac1->int_ep) + usb_ep_disable(uac1->int_ep); +} + +static void +f_audio_suspend(struct usb_function *f) +{ + struct f_uac1 *uac1 = func_to_uac1(f); + + u_audio_suspend(&uac1->g_audio); } /*-------------------------------------------------------------------------*/ +static struct uac_feature_unit_descriptor *build_fu_desc(int chmask) +{ + struct uac_feature_unit_descriptor *fu_desc; + int channels = num_channels(chmask); + int fu_desc_size = UAC_DT_FEATURE_UNIT_SIZE(channels); + + fu_desc = kzalloc(fu_desc_size, GFP_KERNEL); + if (!fu_desc) + return NULL; + + fu_desc->bLength = fu_desc_size; + fu_desc->bDescriptorType = USB_DT_CS_INTERFACE; + + fu_desc->bDescriptorSubtype = UAC_FEATURE_UNIT; + fu_desc->bControlSize = 2; + + /* bUnitID, bSourceID and bmaControls will be defined later */ + + return fu_desc; +} + +/* B.3.2 Class-Specific AC Interface Descriptor */ +static struct +uac1_ac_header_descriptor *build_ac_header_desc(struct f_uac1_opts *opts) +{ + struct uac1_ac_header_descriptor *ac_desc; + int ac_header_desc_size; + int num_ifaces = 0; + + if (EPOUT_EN(opts)) + num_ifaces++; + if (EPIN_EN(opts)) + num_ifaces++; + + ac_header_desc_size = UAC_DT_AC_HEADER_SIZE(num_ifaces); + + ac_desc = kzalloc(ac_header_desc_size, GFP_KERNEL); + if (!ac_desc) + return NULL; + + ac_desc->bLength = ac_header_desc_size; + ac_desc->bDescriptorType = USB_DT_CS_INTERFACE; + ac_desc->bDescriptorSubtype = UAC_HEADER; + ac_desc->bcdADC = cpu_to_le16(0x0100); + ac_desc->bInCollection = num_ifaces; + + /* wTotalLength and baInterfaceNr will be defined later */ + + return ac_desc; +} + +/* Use macro to overcome line length limitation */ +#define USBDHDR(p) (struct usb_descriptor_header *)(p) + +static void setup_descriptor(struct f_uac1_opts *opts) +{ + /* patch descriptors */ + int i = 1; /* ID's start with 1 */ + + if (EPOUT_EN(opts)) + usb_out_it_desc.bTerminalID = i++; + if (EPIN_EN(opts)) + io_in_it_desc.bTerminalID = i++; + if (EPOUT_EN(opts)) + io_out_ot_desc.bTerminalID = i++; + if (EPIN_EN(opts)) + usb_in_ot_desc.bTerminalID = i++; + if (FUOUT_EN(opts)) + out_feature_unit_desc->bUnitID = i++; + if (FUIN_EN(opts)) + in_feature_unit_desc->bUnitID = i++; + + if (FUIN_EN(opts)) { + usb_in_ot_desc.bSourceID = in_feature_unit_desc->bUnitID; + in_feature_unit_desc->bSourceID = io_in_it_desc.bTerminalID; + } else { + usb_in_ot_desc.bSourceID = io_in_it_desc.bTerminalID; + } + if (FUOUT_EN(opts)) { + io_out_ot_desc.bSourceID = out_feature_unit_desc->bUnitID; + out_feature_unit_desc->bSourceID = usb_out_it_desc.bTerminalID; + } else { + io_out_ot_desc.bSourceID = usb_out_it_desc.bTerminalID; + } + + as_out_header_desc.bTerminalLink = usb_out_it_desc.bTerminalID; + as_in_header_desc.bTerminalLink = usb_in_ot_desc.bTerminalID; + + ac_header_desc->wTotalLength = cpu_to_le16(ac_header_desc->bLength); + + if (EPIN_EN(opts)) { + u16 len = le16_to_cpu(ac_header_desc->wTotalLength); + + len += sizeof(usb_in_ot_desc); + len += sizeof(io_in_it_desc); + if (FUIN_EN(opts)) + len += in_feature_unit_desc->bLength; + ac_header_desc->wTotalLength = cpu_to_le16(len); + } + if (EPOUT_EN(opts)) { + u16 len = le16_to_cpu(ac_header_desc->wTotalLength); + + len += sizeof(usb_out_it_desc); + len += sizeof(io_out_ot_desc); + if (FUOUT_EN(opts)) + len += out_feature_unit_desc->bLength; + ac_header_desc->wTotalLength = cpu_to_le16(len); + } + + i = 0; + f_audio_desc[i++] = USBDHDR(&ac_interface_desc); + f_audio_desc[i++] = USBDHDR(ac_header_desc); + + if (EPOUT_EN(opts)) { + f_audio_desc[i++] = USBDHDR(&usb_out_it_desc); + f_audio_desc[i++] = USBDHDR(&io_out_ot_desc); + if (FUOUT_EN(opts)) + f_audio_desc[i++] = USBDHDR(out_feature_unit_desc); + } + + if (EPIN_EN(opts)) { + f_audio_desc[i++] = USBDHDR(&io_in_it_desc); + f_audio_desc[i++] = USBDHDR(&usb_in_ot_desc); + if (FUIN_EN(opts)) + f_audio_desc[i++] = USBDHDR(in_feature_unit_desc); + } + + if (FUOUT_EN(opts) || FUIN_EN(opts)) + f_audio_desc[i++] = USBDHDR(&ac_int_ep_desc); + + if (EPOUT_EN(opts)) { + f_audio_desc[i++] = USBDHDR(&as_out_interface_alt_0_desc); + f_audio_desc[i++] = USBDHDR(&as_out_interface_alt_1_desc); + f_audio_desc[i++] = USBDHDR(&as_out_header_desc); + f_audio_desc[i++] = USBDHDR(&as_out_type_i_desc); + f_audio_desc[i++] = USBDHDR(&as_out_ep_desc); + f_audio_desc[i++] = USBDHDR(&as_iso_out_desc); + } + if (EPIN_EN(opts)) { + f_audio_desc[i++] = USBDHDR(&as_in_interface_alt_0_desc); + f_audio_desc[i++] = USBDHDR(&as_in_interface_alt_1_desc); + f_audio_desc[i++] = USBDHDR(&as_in_header_desc); + f_audio_desc[i++] = USBDHDR(&as_in_type_i_desc); + f_audio_desc[i++] = USBDHDR(&as_in_ep_desc); + f_audio_desc[i++] = USBDHDR(&as_iso_in_desc); + } + f_audio_desc[i] = NULL; +} static int f_audio_validate_opts(struct g_audio *audio, struct device *dev) { @@ -532,14 +1138,36 @@ static int f_audio_validate_opts(struct g_audio *audio, struct device *dev) } else if ((opts->c_ssize < 1) || (opts->c_ssize > 4)) { dev_err(dev, "Error: incorrect capture sample size\n"); return -EINVAL; - } else if (!opts->p_srate) { + } else if (!opts->p_srates[0]) { dev_err(dev, "Error: incorrect playback sampling rate\n"); return -EINVAL; - } else if (!opts->c_srate) { + } else if (!opts->c_srates[0]) { dev_err(dev, "Error: incorrect capture sampling rate\n"); return -EINVAL; } + if (opts->p_volume_max <= opts->p_volume_min) { + dev_err(dev, "Error: incorrect playback volume max/min\n"); + return -EINVAL; + } else if (opts->c_volume_max <= opts->c_volume_min) { + dev_err(dev, "Error: incorrect capture volume max/min\n"); + return -EINVAL; + } else if (opts->p_volume_res <= 0) { + dev_err(dev, "Error: negative/zero playback volume resolution\n"); + return -EINVAL; + } else if (opts->c_volume_res <= 0) { + dev_err(dev, "Error: negative/zero capture volume resolution\n"); + return -EINVAL; + } + + if ((opts->p_volume_max - opts->p_volume_min) % opts->p_volume_res) { + dev_err(dev, "Error: incorrect playback volume resolution\n"); + return -EINVAL; + } else if ((opts->c_volume_max - opts->c_volume_min) % opts->c_volume_res) { + dev_err(dev, "Error: incorrect capture volume resolution\n"); + return -EINVAL; + } + return 0; } @@ -554,9 +1182,9 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) struct f_uac1_opts *audio_opts; struct usb_ep *ep = NULL; struct usb_string *us; - u8 *sam_freq; - int rate; + int ba_iface_id; int status; + int idx, i; status = f_audio_validate_opts(audio, dev); if (status) @@ -564,9 +1192,31 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) audio_opts = container_of(f->fi, struct f_uac1_opts, func_inst); + strings_uac1[STR_AC_IF].s = audio_opts->function_name; + us = usb_gstrings_attach(cdev, uac1_strings, ARRAY_SIZE(strings_uac1)); if (IS_ERR(us)) return PTR_ERR(us); + + ac_header_desc = build_ac_header_desc(audio_opts); + if (!ac_header_desc) + return -ENOMEM; + + if (FUOUT_EN(audio_opts)) { + out_feature_unit_desc = build_fu_desc(audio_opts->c_chmask); + if (!out_feature_unit_desc) { + status = -ENOMEM; + goto fail; + } + } + if (FUIN_EN(audio_opts)) { + in_feature_unit_desc = build_fu_desc(audio_opts->p_chmask); + if (!in_feature_unit_desc) { + status = -ENOMEM; + goto err_free_fu; + } + } + ac_interface_desc.iInterface = us[STR_AC_IF].id; usb_out_it_desc.iTerminal = us[STR_USB_OUT_IT].id; usb_out_it_desc.iChannelNames = us[STR_USB_OUT_IT_CH_NAMES].id; @@ -579,6 +1229,21 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) as_in_interface_alt_0_desc.iInterface = us[STR_AS_IN_IF_ALT0].id; as_in_interface_alt_1_desc.iInterface = us[STR_AS_IN_IF_ALT1].id; + if (FUOUT_EN(audio_opts)) { + u8 *i_feature; + + i_feature = (u8 *)out_feature_unit_desc + + out_feature_unit_desc->bLength - 1; + *i_feature = us[STR_FU_OUT].id; + } + if (FUIN_EN(audio_opts)) { + u8 *i_feature; + + i_feature = (u8 *)in_feature_unit_desc + + in_feature_unit_desc->bLength - 1; + *i_feature = us[STR_FU_IN].id; + } + /* Set channel numbers */ usb_out_it_desc.bNrChannels = num_channels(audio_opts->c_chmask); usb_out_it_desc.wChannelConfig = cpu_to_le16(audio_opts->c_chmask); @@ -591,72 +1256,154 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) as_in_type_i_desc.bSubframeSize = audio_opts->p_ssize; as_in_type_i_desc.bBitResolution = audio_opts->p_ssize * 8; + if (FUOUT_EN(audio_opts)) { + __le16 *bma = (__le16 *)&out_feature_unit_desc->bmaControls[0]; + u32 control = 0; + + if (audio_opts->c_mute_present) + control |= UAC_FU_MUTE; + if (audio_opts->c_volume_present) + control |= UAC_FU_VOLUME; + *bma = cpu_to_le16(control); + } + if (FUIN_EN(audio_opts)) { + __le16 *bma = (__le16 *)&in_feature_unit_desc->bmaControls[0]; + u32 control = 0; + + if (audio_opts->p_mute_present) + control |= UAC_FU_MUTE; + if (audio_opts->p_volume_present) + control |= UAC_FU_VOLUME; + *bma = cpu_to_le16(control); + } + /* Set sample rates */ - rate = audio_opts->c_srate; - sam_freq = as_out_type_i_desc.tSamFreq[0]; - memcpy(sam_freq, &rate, 3); - rate = audio_opts->p_srate; - sam_freq = as_in_type_i_desc.tSamFreq[0]; - memcpy(sam_freq, &rate, 3); + for (i = 0, idx = 0; i < UAC_MAX_RATES; i++) { + if (audio_opts->c_srates[i] == 0) + break; + memcpy(as_out_type_i_desc.tSamFreq[idx++], + &audio_opts->c_srates[i], 3); + } + as_out_type_i_desc.bLength = UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(idx); + as_out_type_i_desc.bSamFreqType = idx; + + for (i = 0, idx = 0; i < UAC_MAX_RATES; i++) { + if (audio_opts->p_srates[i] == 0) + break; + memcpy(as_in_type_i_desc.tSamFreq[idx++], + &audio_opts->p_srates[i], 3); + } + as_in_type_i_desc.bLength = UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(idx); + as_in_type_i_desc.bSamFreqType = idx; + uac1->p_srate = audio_opts->p_srates[0]; + uac1->c_srate = audio_opts->c_srates[0]; /* allocate instance-specific interface IDs, and patch descriptors */ status = usb_interface_id(c, f); if (status < 0) - goto fail; + goto err_free_fu; ac_interface_desc.bInterfaceNumber = status; uac1->ac_intf = status; uac1->ac_alt = 0; - status = usb_interface_id(c, f); - if (status < 0) - goto fail; - as_out_interface_alt_0_desc.bInterfaceNumber = status; - as_out_interface_alt_1_desc.bInterfaceNumber = status; - ac_header_desc.baInterfaceNr[0] = status; - uac1->as_out_intf = status; - uac1->as_out_alt = 0; + ba_iface_id = 0; - status = usb_interface_id(c, f); - if (status < 0) - goto fail; - as_in_interface_alt_0_desc.bInterfaceNumber = status; - as_in_interface_alt_1_desc.bInterfaceNumber = status; - ac_header_desc.baInterfaceNr[1] = status; - uac1->as_in_intf = status; - uac1->as_in_alt = 0; + if (EPOUT_EN(audio_opts)) { + status = usb_interface_id(c, f); + if (status < 0) + goto err_free_fu; + as_out_interface_alt_0_desc.bInterfaceNumber = status; + as_out_interface_alt_1_desc.bInterfaceNumber = status; + ac_header_desc->baInterfaceNr[ba_iface_id++] = status; + uac1->as_out_intf = status; + uac1->as_out_alt = 0; + } + + if (EPIN_EN(audio_opts)) { + status = usb_interface_id(c, f); + if (status < 0) + goto err_free_fu; + as_in_interface_alt_0_desc.bInterfaceNumber = status; + as_in_interface_alt_1_desc.bInterfaceNumber = status; + ac_header_desc->baInterfaceNr[ba_iface_id++] = status; + uac1->as_in_intf = status; + uac1->as_in_alt = 0; + } audio->gadget = gadget; status = -ENODEV; - /* allocate instance-specific endpoints */ - ep = usb_ep_autoconfig(cdev->gadget, &as_out_ep_desc); - if (!ep) - goto fail; - audio->out_ep = ep; - audio->out_ep->desc = &as_out_ep_desc; + ac_interface_desc.bNumEndpoints = 0; - ep = usb_ep_autoconfig(cdev->gadget, &as_in_ep_desc); - if (!ep) - goto fail; - audio->in_ep = ep; - audio->in_ep->desc = &as_in_ep_desc; + /* allocate AC interrupt endpoint */ + if (FUOUT_EN(audio_opts) || FUIN_EN(audio_opts)) { + ep = usb_ep_autoconfig(cdev->gadget, &ac_int_ep_desc); + if (!ep) + goto err_free_fu; + uac1->int_ep = ep; + uac1->int_ep->desc = &ac_int_ep_desc; + + ac_interface_desc.bNumEndpoints = 1; + } + + /* allocate instance-specific endpoints */ + if (EPOUT_EN(audio_opts)) { + ep = usb_ep_autoconfig(cdev->gadget, &as_out_ep_desc); + if (!ep) + goto err_free_fu; + audio->out_ep = ep; + audio->out_ep->desc = &as_out_ep_desc; + } + + if (EPIN_EN(audio_opts)) { + ep = usb_ep_autoconfig(cdev->gadget, &as_in_ep_desc); + if (!ep) + goto err_free_fu; + audio->in_ep = ep; + audio->in_ep->desc = &as_in_ep_desc; + } + + setup_descriptor(audio_opts); /* copy descriptors, and track endpoint copies */ status = usb_assign_descriptors(f, f_audio_desc, f_audio_desc, NULL, NULL); if (status) - goto fail; + goto err_free_fu; audio->out_ep_maxpsize = le16_to_cpu(as_out_ep_desc.wMaxPacketSize); audio->in_ep_maxpsize = le16_to_cpu(as_in_ep_desc.wMaxPacketSize); audio->params.c_chmask = audio_opts->c_chmask; - audio->params.c_srate = audio_opts->c_srate; + memcpy(audio->params.c_srates, audio_opts->c_srates, + sizeof(audio->params.c_srates)); audio->params.c_ssize = audio_opts->c_ssize; + if (FUIN_EN(audio_opts)) { + audio->params.p_fu.id = USB_IN_FU_ID; + audio->params.p_fu.mute_present = audio_opts->p_mute_present; + audio->params.p_fu.volume_present = + audio_opts->p_volume_present; + audio->params.p_fu.volume_min = audio_opts->p_volume_min; + audio->params.p_fu.volume_max = audio_opts->p_volume_max; + audio->params.p_fu.volume_res = audio_opts->p_volume_res; + } audio->params.p_chmask = audio_opts->p_chmask; - audio->params.p_srate = audio_opts->p_srate; + memcpy(audio->params.p_srates, audio_opts->p_srates, + sizeof(audio->params.p_srates)); audio->params.p_ssize = audio_opts->p_ssize; + if (FUOUT_EN(audio_opts)) { + audio->params.c_fu.id = USB_OUT_FU_ID; + audio->params.c_fu.mute_present = audio_opts->c_mute_present; + audio->params.c_fu.volume_present = + audio_opts->c_volume_present; + audio->params.c_fu.volume_min = audio_opts->c_volume_min; + audio->params.c_fu.volume_max = audio_opts->c_volume_max; + audio->params.c_fu.volume_res = audio_opts->c_volume_res; + } audio->params.req_number = audio_opts->req_number; + audio->params.fb_max = FBACK_FAST_MAX; + if (FUOUT_EN(audio_opts) || FUIN_EN(audio_opts)) + audio->notify = audio_notify; status = g_audio_setup(audio, "UAC1_PCM", "UAC1_Gadget"); if (status) @@ -666,7 +1413,14 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f) err_card_register: usb_free_all_descriptors(f); +err_free_fu: + kfree(out_feature_unit_desc); + out_feature_unit_desc = NULL; + kfree(in_feature_unit_desc); + in_feature_unit_desc = NULL; fail: + kfree(ac_header_desc); + ac_header_desc = NULL; return status; } @@ -689,7 +1443,15 @@ static struct configfs_item_operations f_uac1_item_ops = { .release = f_uac1_attr_release, }; -#define UAC1_ATTRIBUTE(name) \ +#define uac1_kstrtou32 kstrtou32 +#define uac1_kstrtos16 kstrtos16 +#define uac1_kstrtobool(s, base, res) kstrtobool((s), (res)) + +static const char *u32_fmt = "%u\n"; +static const char *s16_fmt = "%hd\n"; +static const char *bool_fmt = "%u\n"; + +#define UAC1_ATTRIBUTE(type, name) \ static ssize_t f_uac1_opts_##name##_show( \ struct config_item *item, \ char *page) \ @@ -698,7 +1460,7 @@ static ssize_t f_uac1_opts_##name##_show( \ int result; \ \ mutex_lock(&opts->lock); \ - result = sprintf(page, "%u\n", opts->name); \ + result = sprintf(page, type##_fmt, opts->name); \ mutex_unlock(&opts->lock); \ \ return result; \ @@ -710,7 +1472,7 @@ static ssize_t f_uac1_opts_##name##_store( \ { \ struct f_uac1_opts *opts = to_f_uac1_opts(item); \ int ret; \ - u32 num; \ + type num; \ \ mutex_lock(&opts->lock); \ if (opts->refcnt) { \ @@ -718,7 +1480,7 @@ static ssize_t f_uac1_opts_##name##_store( \ goto end; \ } \ \ - ret = kstrtou32(page, 0, &num); \ + ret = uac1_kstrto##type(page, 0, &num); \ if (ret) \ goto end; \ \ @@ -732,13 +1494,121 @@ end: \ \ CONFIGFS_ATTR(f_uac1_opts_, name) -UAC1_ATTRIBUTE(c_chmask); -UAC1_ATTRIBUTE(c_srate); -UAC1_ATTRIBUTE(c_ssize); -UAC1_ATTRIBUTE(p_chmask); -UAC1_ATTRIBUTE(p_srate); -UAC1_ATTRIBUTE(p_ssize); -UAC1_ATTRIBUTE(req_number); +#define UAC1_RATE_ATTRIBUTE(name) \ +static ssize_t f_uac1_opts_##name##_show(struct config_item *item, \ + char *page) \ +{ \ + struct f_uac1_opts *opts = to_f_uac1_opts(item); \ + int result = 0; \ + int i; \ + \ + mutex_lock(&opts->lock); \ + page[0] = '\0'; \ + for (i = 0; i < UAC_MAX_RATES; i++) { \ + if (opts->name##s[i] == 0) \ + break; \ + result += sprintf(page + strlen(page), "%u,", \ + opts->name##s[i]); \ + } \ + if (strlen(page) > 0) \ + page[strlen(page) - 1] = '\n'; \ + mutex_unlock(&opts->lock); \ + \ + return result; \ +} \ + \ +static ssize_t f_uac1_opts_##name##_store(struct config_item *item, \ + const char *page, size_t len) \ +{ \ + struct f_uac1_opts *opts = to_f_uac1_opts(item); \ + char *split_page = NULL; \ + int ret = -EINVAL; \ + char *token; \ + u32 num; \ + int i; \ + \ + mutex_lock(&opts->lock); \ + if (opts->refcnt) { \ + ret = -EBUSY; \ + goto end; \ + } \ + \ + i = 0; \ + memset(opts->name##s, 0x00, sizeof(opts->name##s)); \ + split_page = kstrdup(page, GFP_KERNEL); \ + while ((token = strsep(&split_page, ",")) != NULL) { \ + ret = kstrtou32(token, 0, &num); \ + if (ret) \ + goto end; \ + \ + opts->name##s[i++] = num; \ + ret = len; \ + }; \ + \ +end: \ + kfree(split_page); \ + mutex_unlock(&opts->lock); \ + return ret; \ +} \ + \ +CONFIGFS_ATTR(f_uac1_opts_, name) + +#define UAC1_ATTRIBUTE_STRING(name) \ +static ssize_t f_uac1_opts_##name##_show(struct config_item *item, \ + char *page) \ +{ \ + struct f_uac1_opts *opts = to_f_uac1_opts(item); \ + int result; \ + \ + mutex_lock(&opts->lock); \ + result = snprintf(page, sizeof(opts->name), "%s", opts->name); \ + mutex_unlock(&opts->lock); \ + \ + return result; \ +} \ + \ +static ssize_t f_uac1_opts_##name##_store(struct config_item *item, \ + const char *page, size_t len) \ +{ \ + struct f_uac1_opts *opts = to_f_uac1_opts(item); \ + int ret = 0; \ + \ + mutex_lock(&opts->lock); \ + if (opts->refcnt) { \ + ret = -EBUSY; \ + goto end; \ + } \ + \ + ret = snprintf(opts->name, min(sizeof(opts->name), len), \ + "%s", page); \ + \ +end: \ + mutex_unlock(&opts->lock); \ + return ret; \ +} \ + \ +CONFIGFS_ATTR(f_uac1_opts_, name) + +UAC1_ATTRIBUTE(u32, c_chmask); +UAC1_RATE_ATTRIBUTE(c_srate); +UAC1_ATTRIBUTE(u32, c_ssize); +UAC1_ATTRIBUTE(u32, p_chmask); +UAC1_RATE_ATTRIBUTE(p_srate); +UAC1_ATTRIBUTE(u32, p_ssize); +UAC1_ATTRIBUTE(u32, req_number); + +UAC1_ATTRIBUTE(bool, p_mute_present); +UAC1_ATTRIBUTE(bool, p_volume_present); +UAC1_ATTRIBUTE(s16, p_volume_min); +UAC1_ATTRIBUTE(s16, p_volume_max); +UAC1_ATTRIBUTE(s16, p_volume_res); + +UAC1_ATTRIBUTE(bool, c_mute_present); +UAC1_ATTRIBUTE(bool, c_volume_present); +UAC1_ATTRIBUTE(s16, c_volume_min); +UAC1_ATTRIBUTE(s16, c_volume_max); +UAC1_ATTRIBUTE(s16, c_volume_res); +UAC1_ATTRIBUTE_STRING(function_name); static struct configfs_attribute *f_uac1_attrs[] = { &f_uac1_opts_attr_c_chmask, @@ -748,6 +1618,21 @@ static struct configfs_attribute *f_uac1_attrs[] = { &f_uac1_opts_attr_p_srate, &f_uac1_opts_attr_p_ssize, &f_uac1_opts_attr_req_number, + + &f_uac1_opts_attr_p_mute_present, + &f_uac1_opts_attr_p_volume_present, + &f_uac1_opts_attr_p_volume_min, + &f_uac1_opts_attr_p_volume_max, + &f_uac1_opts_attr_p_volume_res, + + &f_uac1_opts_attr_c_mute_present, + &f_uac1_opts_attr_c_volume_present, + &f_uac1_opts_attr_c_volume_min, + &f_uac1_opts_attr_c_volume_max, + &f_uac1_opts_attr_c_volume_res, + + &f_uac1_opts_attr_function_name, + NULL, }; @@ -780,12 +1665,28 @@ static struct usb_function_instance *f_audio_alloc_inst(void) &f_uac1_func_type); opts->c_chmask = UAC1_DEF_CCHMASK; - opts->c_srate = UAC1_DEF_CSRATE; + opts->c_srates[0] = UAC1_DEF_CSRATE; opts->c_ssize = UAC1_DEF_CSSIZE; opts->p_chmask = UAC1_DEF_PCHMASK; - opts->p_srate = UAC1_DEF_PSRATE; + opts->p_srates[0] = UAC1_DEF_PSRATE; opts->p_ssize = UAC1_DEF_PSSIZE; + + opts->p_mute_present = UAC1_DEF_MUTE_PRESENT; + opts->p_volume_present = UAC1_DEF_VOLUME_PRESENT; + opts->p_volume_min = UAC1_DEF_MIN_DB; + opts->p_volume_max = UAC1_DEF_MAX_DB; + opts->p_volume_res = UAC1_DEF_RES_DB; + + opts->c_mute_present = UAC1_DEF_MUTE_PRESENT; + opts->c_volume_present = UAC1_DEF_VOLUME_PRESENT; + opts->c_volume_min = UAC1_DEF_MIN_DB; + opts->c_volume_max = UAC1_DEF_MAX_DB; + opts->c_volume_res = UAC1_DEF_RES_DB; + opts->req_number = UAC1_DEF_REQ_NUM; + + snprintf(opts->function_name, sizeof(opts->function_name), "AC Interface"); + return &opts->func_inst; } @@ -809,6 +1710,14 @@ static void f_audio_unbind(struct usb_configuration *c, struct usb_function *f) g_audio_cleanup(audio); usb_free_all_descriptors(f); + kfree(out_feature_unit_desc); + out_feature_unit_desc = NULL; + kfree(in_feature_unit_desc); + in_feature_unit_desc = NULL; + + kfree(ac_header_desc); + ac_header_desc = NULL; + audio->gadget = NULL; } @@ -834,6 +1743,7 @@ static struct usb_function *f_audio_alloc(struct usb_function_instance *fi) uac1->g_audio.func.get_alt = f_audio_get_alt; uac1->g_audio.func.setup = f_audio_setup; uac1->g_audio.func.disable = f_audio_disable; + uac1->g_audio.func.suspend = f_audio_suspend; uac1->g_audio.func.free_func = f_audio_free; return &uac1->g_audio.func; diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index f1ba000ac3f7..da5250a415d5 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -5,6 +5,9 @@ * Copyright (C) 2011 * Yadwinder Singh (yadi.brar01@gmail.com) * Jaswinder Singh (jaswinder.singh@linaro.org) + * + * Copyright (C) 2020 + * Ruslan Bilovol (ruslan.bilovol@gmail.com) */ #include @@ -12,6 +15,7 @@ #include #include "u_audio.h" + #include "u_uac2.h" /* UAC2 spec: 4.1 Audio Channel Cluster Descriptor */ @@ -19,14 +23,16 @@ /* * The driver implements a simple UAC_2 topology. - * USB-OUT -> IT_1 -> OT_3 -> ALSA_Capture - * ALSA_Playback -> IT_2 -> OT_4 -> USB-IN + * USB-OUT -> IT_1 -> FU -> OT_3 -> ALSA_Capture + * ALSA_Playback -> IT_2 -> FU -> OT_4 -> USB-IN * Capture and Playback sampling rates are independently * controlled by two clock sources : * CLK_5 := c_srate, and CLK_6 := p_srate */ #define USB_OUT_CLK_ID (out_clk_src_desc.bClockID) #define USB_IN_CLK_ID (in_clk_src_desc.bClockID) +#define USB_OUT_FU_ID (out_feature_unit_desc->bUnitID) +#define USB_IN_FU_ID (in_feature_unit_desc->bUnitID) #define CONTROL_ABSENT 0 #define CONTROL_RDONLY 1 @@ -34,6 +40,8 @@ #define CLK_FREQ_CTRL 0 #define CLK_VLD_CTRL 2 +#define FU_MUTE_CTRL 0 +#define FU_VOL_CTRL 2 #define COPY_CTRL 0 #define CONN_CTRL 2 @@ -44,12 +52,26 @@ #define EPIN_EN(_opts) ((_opts)->p_chmask != 0) #define EPOUT_EN(_opts) ((_opts)->c_chmask != 0) +#define FUIN_EN(_opts) (EPIN_EN(_opts) \ + && ((_opts)->p_mute_present \ + || (_opts)->p_volume_present)) +#define FUOUT_EN(_opts) (EPOUT_EN(_opts) \ + && ((_opts)->c_mute_present \ + || (_opts)->c_volume_present)) #define EPOUT_FBACK_IN_EN(_opts) ((_opts)->c_sync == USB_ENDPOINT_SYNC_ASYNC) struct f_uac2 { struct g_audio g_audio; u8 ac_intf, as_in_intf, as_out_intf; u8 ac_alt, as_in_alt, as_out_alt; /* needed for get_alt() */ + + struct usb_ctrlrequest setup_cr; /* will be used in data stage */ + + /* Interrupt IN endpoint of AC interface */ + struct usb_ep *int_ep; + atomic_t int_count; + /* transient state, only valid during handling of a single control request */ + int clock_id; }; static inline struct f_uac2 *func_to_uac2(struct usb_function *f) @@ -63,6 +85,8 @@ struct f_uac2_opts *g_audio_to_uac2_opts(struct g_audio *agdev) return container_of(agdev->func.fi, struct f_uac2_opts, func_inst); } +static int afunc_notify(struct g_audio *agdev, int unit_id, int cs); + /* --------- USB Function Interface ------------- */ enum { @@ -74,24 +98,25 @@ enum { STR_IO_IT, STR_USB_OT, STR_IO_OT, + STR_FU_IN, + STR_FU_OUT, STR_AS_OUT_ALT0, STR_AS_OUT_ALT1, STR_AS_IN_ALT0, STR_AS_IN_ALT1, }; -static char clksrc_in[8]; -static char clksrc_out[8]; - static struct usb_string strings_fn[] = { - [STR_ASSOC].s = "Source/Sink", + /* [STR_ASSOC].s = DYNAMIC, */ [STR_IF_CTRL].s = "Topology Control", - [STR_CLKSRC_IN].s = clksrc_in, - [STR_CLKSRC_OUT].s = clksrc_out, + [STR_CLKSRC_IN].s = "Input Clock", + [STR_CLKSRC_OUT].s = "Output Clock", [STR_USB_IT].s = "USBH Out", [STR_IO_IT].s = "USBD Out", [STR_USB_OT].s = "USBH In", [STR_IO_OT].s = "USBD In", + [STR_FU_IN].s = "Capture Volume", + [STR_FU_OUT].s = "Playback Volume", [STR_AS_OUT_ALT0].s = "Playback Inactive", [STR_AS_OUT_ALT1].s = "Playback Active", [STR_AS_IN_ALT0].s = "Capture Inactive", @@ -126,7 +151,7 @@ static struct usb_interface_descriptor std_ac_if_desc = { .bDescriptorType = USB_DT_INTERFACE, .bAlternateSetting = 0, - .bNumEndpoints = 0, + /* .bNumEndpoints = DYNAMIC */ .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, .bInterfaceProtocol = UAC_VERSION_2, @@ -140,7 +165,7 @@ static struct uac_clock_source_descriptor in_clk_src_desc = { .bDescriptorSubtype = UAC2_CLOCK_SOURCE, /* .bClockID = DYNAMIC */ .bmAttributes = UAC_CLOCK_SOURCE_TYPE_INT_FIXED, - .bmControls = (CONTROL_RDONLY << CLK_FREQ_CTRL), + .bmControls = (CONTROL_RDWR << CLK_FREQ_CTRL), .bAssocTerminal = 0, }; @@ -152,7 +177,7 @@ static struct uac_clock_source_descriptor out_clk_src_desc = { .bDescriptorSubtype = UAC2_CLOCK_SOURCE, /* .bClockID = DYNAMIC */ .bmAttributes = UAC_CLOCK_SOURCE_TYPE_INT_FIXED, - .bmControls = (CONTROL_RDONLY << CLK_FREQ_CTRL), + .bmControls = (CONTROL_RDWR << CLK_FREQ_CTRL), .bAssocTerminal = 0, }; @@ -212,6 +237,9 @@ static struct uac2_output_terminal_descriptor io_out_ot_desc = { .bmControls = cpu_to_le16(CONTROL_RDWR << COPY_CTRL), }; +static struct uac2_feature_unit_descriptor *in_feature_unit_desc; +static struct uac2_feature_unit_descriptor *out_feature_unit_desc; + static struct uac2_ac_header_descriptor ac_hdr_desc = { .bLength = sizeof ac_hdr_desc, .bDescriptorType = USB_DT_CS_INTERFACE, @@ -223,6 +251,36 @@ static struct uac2_ac_header_descriptor ac_hdr_desc = { .bmControls = 0, }; +/* AC IN Interrupt Endpoint */ +static struct usb_endpoint_descriptor fs_ep_int_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = cpu_to_le16(6), + .bInterval = 1, +}; + +static struct usb_endpoint_descriptor hs_ep_int_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = cpu_to_le16(6), + .bInterval = 4, +}; + +static struct usb_endpoint_descriptor ss_ep_int_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = cpu_to_le16(6), + .bInterval = 4, +}; + /* Audio Streaming OUT Interface - Alt0 */ static struct usb_interface_descriptor std_as_out_if0_desc = { .bLength = sizeof std_as_out_if0_desc, @@ -460,10 +518,14 @@ static struct usb_descriptor_header *fs_audio_desc[] = { (struct usb_descriptor_header *)&in_clk_src_desc, (struct usb_descriptor_header *)&out_clk_src_desc, (struct usb_descriptor_header *)&usb_out_it_desc, + (struct usb_descriptor_header *)&out_feature_unit_desc, (struct usb_descriptor_header *)&io_in_it_desc, (struct usb_descriptor_header *)&usb_in_ot_desc, + (struct usb_descriptor_header *)&in_feature_unit_desc, (struct usb_descriptor_header *)&io_out_ot_desc, + (struct usb_descriptor_header *)&fs_ep_int_desc, + (struct usb_descriptor_header *)&std_as_out_if0_desc, (struct usb_descriptor_header *)&std_as_out_if1_desc, @@ -491,10 +553,14 @@ static struct usb_descriptor_header *hs_audio_desc[] = { (struct usb_descriptor_header *)&in_clk_src_desc, (struct usb_descriptor_header *)&out_clk_src_desc, (struct usb_descriptor_header *)&usb_out_it_desc, + (struct usb_descriptor_header *)&out_feature_unit_desc, (struct usb_descriptor_header *)&io_in_it_desc, (struct usb_descriptor_header *)&usb_in_ot_desc, + (struct usb_descriptor_header *)&in_feature_unit_desc, (struct usb_descriptor_header *)&io_out_ot_desc, + (struct usb_descriptor_header *)&hs_ep_int_desc, + (struct usb_descriptor_header *)&std_as_out_if0_desc, (struct usb_descriptor_header *)&std_as_out_if1_desc, @@ -522,10 +588,14 @@ static struct usb_descriptor_header *ss_audio_desc[] = { (struct usb_descriptor_header *)&in_clk_src_desc, (struct usb_descriptor_header *)&out_clk_src_desc, (struct usb_descriptor_header *)&usb_out_it_desc, + (struct usb_descriptor_header *)&out_feature_unit_desc, (struct usb_descriptor_header *)&io_in_it_desc, (struct usb_descriptor_header *)&usb_in_ot_desc, + (struct usb_descriptor_header *)&in_feature_unit_desc, (struct usb_descriptor_header *)&io_out_ot_desc, + (struct usb_descriptor_header *)&ss_ep_int_desc, + (struct usb_descriptor_header *)&std_as_out_if0_desc, (struct usb_descriptor_header *)&std_as_out_if1_desc, @@ -548,17 +618,52 @@ static struct usb_descriptor_header *ss_audio_desc[] = { NULL, }; +struct cntrl_cur_lay2 { + __le16 wCUR; +}; + +struct cntrl_range_lay2 { + __le16 wNumSubRanges; + __le16 wMIN; + __le16 wMAX; + __le16 wRES; +} __packed; + struct cntrl_cur_lay3 { __le32 dCUR; }; -struct cntrl_range_lay3 { - __le16 wNumSubRanges; +struct cntrl_subrange_lay3 { __le32 dMIN; __le32 dMAX; __le32 dRES; } __packed; +#define ranges_lay3_size(c) (sizeof(c.wNumSubRanges) \ + + le16_to_cpu(c.wNumSubRanges) \ + * sizeof(struct cntrl_subrange_lay3)) + +#define DECLARE_UAC2_CNTRL_RANGES_LAY3(k, n) \ + struct cntrl_ranges_lay3_##k { \ + __le16 wNumSubRanges; \ + struct cntrl_subrange_lay3 r[n]; \ +} __packed + +DECLARE_UAC2_CNTRL_RANGES_LAY3(srates, UAC_MAX_RATES); + +static int get_max_srate(const int *srates) +{ + int i, max_srate = 0; + + for (i = 0; i < UAC_MAX_RATES; i++) { + if (srates[i] == 0) + break; + if (srates[i] > max_srate) + max_srate = srates[i]; + } + return max_srate; +} + static int set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, struct usb_endpoint_descriptor *ep_desc, enum usb_device_speed speed, bool is_playback) @@ -585,16 +690,17 @@ static int set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, if (is_playback) { chmask = uac2_opts->p_chmask; - srate = uac2_opts->p_srate; + srate = get_max_srate(uac2_opts->p_srates); ssize = uac2_opts->p_ssize; } else { chmask = uac2_opts->c_chmask; - srate = uac2_opts->c_srate; + srate = get_max_srate(uac2_opts->c_srates); ssize = uac2_opts->c_ssize; } - if (!is_playback && (uac2_opts->c_sync == USB_ENDPOINT_SYNC_ASYNC)) { - // Win10 requires max packet size + 1 frame + if (is_playback || (uac2_opts->c_sync == USB_ENDPOINT_SYNC_ASYNC)) { + // playback is always async, capture only when configured + // Win10 requires max packet size + 1 frame srate = srate * (1000 + uac2_opts->fb_max) / 1000; // updated srate is always bigger, therefore DIV_ROUND_UP always yields +1 max_size_bw = num_channels(chmask) * ssize * @@ -610,6 +716,26 @@ static int set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, return 0; } +static struct uac2_feature_unit_descriptor *build_fu_desc(int chmask) +{ + struct uac2_feature_unit_descriptor *fu_desc; + int channels = num_channels(chmask); + int fu_desc_size = UAC2_DT_FEATURE_UNIT_SIZE(channels); + + fu_desc = kzalloc(fu_desc_size, GFP_KERNEL); + if (!fu_desc) + return NULL; + + fu_desc->bLength = fu_desc_size; + fu_desc->bDescriptorType = USB_DT_CS_INTERFACE; + + fu_desc->bDescriptorSubtype = UAC_FEATURE_UNIT; + + /* bUnitID, bSourceID and bmaControls will be defined later */ + + return fu_desc; +} + /* Use macro to overcome line length limitation */ #define USBDHDR(p) (struct usb_descriptor_header *)(p) @@ -623,6 +749,7 @@ static void setup_headers(struct f_uac2_opts *opts, struct usb_endpoint_descriptor *epout_desc; struct usb_endpoint_descriptor *epin_desc; struct usb_endpoint_descriptor *epin_fback_desc; + struct usb_endpoint_descriptor *ep_int_desc; int i; switch (speed) { @@ -630,11 +757,13 @@ static void setup_headers(struct f_uac2_opts *opts, epout_desc = &fs_epout_desc; epin_desc = &fs_epin_desc; epin_fback_desc = &fs_epin_fback_desc; + ep_int_desc = &fs_ep_int_desc; break; case USB_SPEED_HIGH: epout_desc = &hs_epout_desc; epin_desc = &hs_epin_desc; epin_fback_desc = &hs_epin_fback_desc; + ep_int_desc = &hs_ep_int_desc; break; default: epout_desc = &ss_epout_desc; @@ -643,6 +772,7 @@ static void setup_headers(struct f_uac2_opts *opts, epin_desc_comp = &ss_epin_desc_comp; epin_fback_desc = &ss_epin_fback_desc; epin_fback_desc_comp = &ss_epin_fback_desc_comp; + ep_int_desc = &ss_ep_int_desc; } i = 0; @@ -654,13 +784,27 @@ static void setup_headers(struct f_uac2_opts *opts, if (EPOUT_EN(opts)) { headers[i++] = USBDHDR(&out_clk_src_desc); headers[i++] = USBDHDR(&usb_out_it_desc); - } + + if (FUOUT_EN(opts)) + headers[i++] = USBDHDR(out_feature_unit_desc); + } + if (EPIN_EN(opts)) { headers[i++] = USBDHDR(&io_in_it_desc); + + if (FUIN_EN(opts)) + headers[i++] = USBDHDR(in_feature_unit_desc); + headers[i++] = USBDHDR(&usb_in_ot_desc); } - if (EPOUT_EN(opts)) { + + if (EPOUT_EN(opts)) headers[i++] = USBDHDR(&io_out_ot_desc); + + if (FUOUT_EN(opts) || FUIN_EN(opts)) + headers[i++] = USBDHDR(ep_int_desc); + + if (EPOUT_EN(opts)) { headers[i++] = USBDHDR(&std_as_out_if0_desc); headers[i++] = USBDHDR(&std_as_out_if1_desc); headers[i++] = USBDHDR(&as_out_hdr_desc); @@ -677,6 +821,7 @@ static void setup_headers(struct f_uac2_opts *opts, headers[i++] = USBDHDR(epin_fback_desc_comp); } } + if (EPIN_EN(opts)) { headers[i++] = USBDHDR(&std_as_in_if0_desc); headers[i++] = USBDHDR(&std_as_in_if1_desc); @@ -704,17 +849,35 @@ static void setup_descriptor(struct f_uac2_opts *opts) io_out_ot_desc.bTerminalID = i++; if (EPIN_EN(opts)) usb_in_ot_desc.bTerminalID = i++; + if (FUOUT_EN(opts)) + out_feature_unit_desc->bUnitID = i++; + if (FUIN_EN(opts)) + in_feature_unit_desc->bUnitID = i++; if (EPOUT_EN(opts)) out_clk_src_desc.bClockID = i++; if (EPIN_EN(opts)) in_clk_src_desc.bClockID = i++; usb_out_it_desc.bCSourceID = out_clk_src_desc.bClockID; - usb_in_ot_desc.bSourceID = io_in_it_desc.bTerminalID; + + if (FUIN_EN(opts)) { + usb_in_ot_desc.bSourceID = in_feature_unit_desc->bUnitID; + in_feature_unit_desc->bSourceID = io_in_it_desc.bTerminalID; + } else { + usb_in_ot_desc.bSourceID = io_in_it_desc.bTerminalID; + } + usb_in_ot_desc.bCSourceID = in_clk_src_desc.bClockID; io_in_it_desc.bCSourceID = in_clk_src_desc.bClockID; io_out_ot_desc.bCSourceID = out_clk_src_desc.bClockID; - io_out_ot_desc.bSourceID = usb_out_it_desc.bTerminalID; + + if (FUOUT_EN(opts)) { + io_out_ot_desc.bSourceID = out_feature_unit_desc->bUnitID; + out_feature_unit_desc->bSourceID = usb_out_it_desc.bTerminalID; + } else { + io_out_ot_desc.bSourceID = usb_out_it_desc.bTerminalID; + } + as_out_hdr_desc.bTerminalLink = usb_out_it_desc.bTerminalID; as_in_hdr_desc.bTerminalLink = usb_in_ot_desc.bTerminalID; @@ -726,6 +889,10 @@ static void setup_descriptor(struct f_uac2_opts *opts) len += sizeof(in_clk_src_desc); len += sizeof(usb_in_ot_desc); + + if (FUIN_EN(opts)) + len += in_feature_unit_desc->bLength; + len += sizeof(io_in_it_desc); ac_hdr_desc.wTotalLength = cpu_to_le16(len); iad_desc.bInterfaceCount++; @@ -735,6 +902,10 @@ static void setup_descriptor(struct f_uac2_opts *opts) len += sizeof(out_clk_src_desc); len += sizeof(usb_out_it_desc); + + if (FUOUT_EN(opts)) + len += out_feature_unit_desc->bLength; + len += sizeof(io_out_ot_desc); ac_hdr_desc.wTotalLength = cpu_to_le16(len); iad_desc.bInterfaceCount++; @@ -764,14 +935,36 @@ static int afunc_validate_opts(struct g_audio *agdev, struct device *dev) } else if ((opts->c_ssize < 1) || (opts->c_ssize > 4)) { dev_err(dev, "Error: incorrect capture sample size\n"); return -EINVAL; - } else if (!opts->p_srate) { + } else if (!opts->p_srates[0]) { dev_err(dev, "Error: incorrect playback sampling rate\n"); return -EINVAL; - } else if (!opts->c_srate) { + } else if (!opts->c_srates[0]) { dev_err(dev, "Error: incorrect capture sampling rate\n"); return -EINVAL; } + if (opts->p_volume_max <= opts->p_volume_min) { + dev_err(dev, "Error: incorrect playback volume max/min\n"); + return -EINVAL; + } else if (opts->c_volume_max <= opts->c_volume_min) { + dev_err(dev, "Error: incorrect capture volume max/min\n"); + return -EINVAL; + } else if (opts->p_volume_res <= 0) { + dev_err(dev, "Error: negative/zero playback volume resolution\n"); + return -EINVAL; + } else if (opts->c_volume_res <= 0) { + dev_err(dev, "Error: negative/zero capture volume resolution\n"); + return -EINVAL; + } + + if ((opts->p_volume_max - opts->p_volume_min) % opts->p_volume_res) { + dev_err(dev, "Error: incorrect playback volume resolution\n"); + return -EINVAL; + } else if ((opts->c_volume_max - opts->c_volume_min) % opts->c_volume_res) { + dev_err(dev, "Error: incorrect capture volume resolution\n"); + return -EINVAL; + } + return 0; } @@ -791,9 +984,25 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) if (ret) return ret; + strings_fn[STR_ASSOC].s = uac2_opts->function_name; + us = usb_gstrings_attach(cdev, fn_strings, ARRAY_SIZE(strings_fn)); if (IS_ERR(us)) return PTR_ERR(us); + + if (FUOUT_EN(uac2_opts)) { + out_feature_unit_desc = build_fu_desc(uac2_opts->c_chmask); + if (!out_feature_unit_desc) + return -ENOMEM; + } + if (FUIN_EN(uac2_opts)) { + in_feature_unit_desc = build_fu_desc(uac2_opts->p_chmask); + if (!in_feature_unit_desc) { + ret = -ENOMEM; + goto err_free_fu; + } + } + iad_desc.iFunction = us[STR_ASSOC].id; std_ac_if_desc.iInterface = us[STR_IF_CTRL].id; in_clk_src_desc.iClockSource = us[STR_CLKSRC_IN].id; @@ -807,6 +1016,21 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) std_as_in_if0_desc.iInterface = us[STR_AS_IN_ALT0].id; std_as_in_if1_desc.iInterface = us[STR_AS_IN_ALT1].id; + if (FUOUT_EN(uac2_opts)) { + u8 *i_feature = (u8 *)out_feature_unit_desc; + + i_feature = (u8 *)out_feature_unit_desc + + out_feature_unit_desc->bLength - 1; + *i_feature = us[STR_FU_OUT].id; + } + if (FUIN_EN(uac2_opts)) { + u8 *i_feature = (u8 *)in_feature_unit_desc; + + i_feature = (u8 *)in_feature_unit_desc + + in_feature_unit_desc->bLength - 1; + *i_feature = us[STR_FU_IN].id; + } + /* Initialize the configurable parameters */ usb_out_it_desc.bNrChannels = num_channels(uac2_opts->c_chmask); @@ -821,14 +1045,31 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) as_out_fmt1_desc.bBitResolution = uac2_opts->c_ssize * 8; as_in_fmt1_desc.bSubslotSize = uac2_opts->p_ssize; as_in_fmt1_desc.bBitResolution = uac2_opts->p_ssize * 8; + if (FUOUT_EN(uac2_opts)) { + __le32 *bma = (__le32 *)&out_feature_unit_desc->bmaControls[0]; + u32 control = 0; - snprintf(clksrc_in, sizeof(clksrc_in), "%uHz", uac2_opts->p_srate); - snprintf(clksrc_out, sizeof(clksrc_out), "%uHz", uac2_opts->c_srate); + if (uac2_opts->c_mute_present) + control |= CONTROL_RDWR << FU_MUTE_CTRL; + if (uac2_opts->c_volume_present) + control |= CONTROL_RDWR << FU_VOL_CTRL; + *bma = cpu_to_le32(control); + } + if (FUIN_EN(uac2_opts)) { + __le32 *bma = (__le32 *)&in_feature_unit_desc->bmaControls[0]; + u32 control = 0; + + if (uac2_opts->p_mute_present) + control |= CONTROL_RDWR << FU_MUTE_CTRL; + if (uac2_opts->p_volume_present) + control |= CONTROL_RDWR << FU_VOL_CTRL; + *bma = cpu_to_le32(control); + } ret = usb_interface_id(cfg, fn); if (ret < 0) { dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); - return ret; + goto err_free_fu; } iad_desc.bFirstInterface = ret; @@ -840,7 +1081,7 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) ret = usb_interface_id(cfg, fn); if (ret < 0) { dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); - return ret; + goto err_free_fu; } std_as_out_if0_desc.bInterfaceNumber = ret; std_as_out_if1_desc.bInterfaceNumber = ret; @@ -869,7 +1110,7 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) ret = usb_interface_id(cfg, fn); if (ret < 0) { dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); - return ret; + goto err_free_fu; } std_as_in_if0_desc.bInterfaceNumber = ret; std_as_in_if1_desc.bInterfaceNumber = ret; @@ -877,6 +1118,17 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) uac2->as_in_alt = 0; } + if (FUOUT_EN(uac2_opts) || FUIN_EN(uac2_opts)) { + uac2->int_ep = usb_ep_autoconfig(gadget, &fs_ep_int_desc); + if (!uac2->int_ep) { + dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); + ret = -ENODEV; + goto err_free_fu; + } + + std_ac_if_desc.bNumEndpoints = 1; + } + /* Calculate wMaxPacketSize according to audio bandwidth */ ret = set_ep_max_packet_size(uac2_opts, &fs_epin_desc, USB_SPEED_FULL, true); @@ -924,7 +1176,8 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) agdev->out_ep = usb_ep_autoconfig(gadget, &fs_epout_desc); if (!agdev->out_ep) { dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); - return -ENODEV; + ret = -ENODEV; + goto err_free_fu; } if (EPOUT_FBACK_IN_EN(uac2_opts)) { agdev->in_ep_fback = usb_ep_autoconfig(gadget, @@ -932,7 +1185,8 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) if (!agdev->in_ep_fback) { dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); - return -ENODEV; + ret = -ENODEV; + goto err_free_fu; } } } @@ -941,7 +1195,8 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) agdev->in_ep = usb_ep_autoconfig(gadget, &fs_epin_desc); if (!agdev->in_ep) { dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); - return -ENODEV; + ret = -ENODEV; + goto err_free_fu; } } @@ -960,38 +1215,139 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) ss_epin_desc_comp.wBytesPerInterval = ss_epin_desc.wMaxPacketSize; ss_epout_desc_comp.wBytesPerInterval = ss_epout_desc.wMaxPacketSize; + // HS and SS endpoint addresses are copied from autoconfigured FS descriptors + hs_ep_int_desc.bEndpointAddress = fs_ep_int_desc.bEndpointAddress; hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress; hs_epin_fback_desc.bEndpointAddress = fs_epin_fback_desc.bEndpointAddress; hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress; ss_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress; ss_epin_fback_desc.bEndpointAddress = fs_epin_fback_desc.bEndpointAddress; ss_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress; + ss_ep_int_desc.bEndpointAddress = fs_ep_int_desc.bEndpointAddress; setup_descriptor(uac2_opts); ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, ss_audio_desc, ss_audio_desc); if (ret) - return ret; + goto err_free_fu; agdev->gadget = gadget; agdev->params.p_chmask = uac2_opts->p_chmask; - agdev->params.p_srate = uac2_opts->p_srate; + memcpy(agdev->params.p_srates, uac2_opts->p_srates, + sizeof(agdev->params.p_srates)); agdev->params.p_ssize = uac2_opts->p_ssize; + if (FUIN_EN(uac2_opts)) { + agdev->params.p_fu.id = USB_IN_FU_ID; + agdev->params.p_fu.mute_present = uac2_opts->p_mute_present; + agdev->params.p_fu.volume_present = uac2_opts->p_volume_present; + agdev->params.p_fu.volume_min = uac2_opts->p_volume_min; + agdev->params.p_fu.volume_max = uac2_opts->p_volume_max; + agdev->params.p_fu.volume_res = uac2_opts->p_volume_res; + } agdev->params.c_chmask = uac2_opts->c_chmask; - agdev->params.c_srate = uac2_opts->c_srate; + memcpy(agdev->params.c_srates, uac2_opts->c_srates, + sizeof(agdev->params.c_srates)); agdev->params.c_ssize = uac2_opts->c_ssize; + if (FUOUT_EN(uac2_opts)) { + agdev->params.c_fu.id = USB_OUT_FU_ID; + agdev->params.c_fu.mute_present = uac2_opts->c_mute_present; + agdev->params.c_fu.volume_present = uac2_opts->c_volume_present; + agdev->params.c_fu.volume_min = uac2_opts->c_volume_min; + agdev->params.c_fu.volume_max = uac2_opts->c_volume_max; + agdev->params.c_fu.volume_res = uac2_opts->c_volume_res; + } agdev->params.req_number = uac2_opts->req_number; agdev->params.fb_max = uac2_opts->fb_max; + + if (FUOUT_EN(uac2_opts) || FUIN_EN(uac2_opts)) + agdev->notify = afunc_notify; + ret = g_audio_setup(agdev, "UAC2 PCM", "UAC2_Gadget"); if (ret) goto err_free_descs; + return 0; err_free_descs: usb_free_all_descriptors(fn); agdev->gadget = NULL; +err_free_fu: + kfree(out_feature_unit_desc); + out_feature_unit_desc = NULL; + kfree(in_feature_unit_desc); + in_feature_unit_desc = NULL; + return ret; +} + +static void +afunc_notify_complete(struct usb_ep *_ep, struct usb_request *req) +{ + struct g_audio *agdev = req->context; + struct f_uac2 *uac2 = func_to_uac2(&agdev->func); + + atomic_dec(&uac2->int_count); + kfree(req->buf); + usb_ep_free_request(_ep, req); +} + +static int +afunc_notify(struct g_audio *agdev, int unit_id, int cs) +{ + struct f_uac2 *uac2 = func_to_uac2(&agdev->func); + struct usb_request *req; + struct uac2_interrupt_data_msg *msg; + u16 w_index, w_value; + int ret; + + if (!uac2->int_ep->enabled) + return 0; + + if (atomic_inc_return(&uac2->int_count) > UAC2_DEF_INT_REQ_NUM) { + atomic_dec(&uac2->int_count); + return 0; + } + + req = usb_ep_alloc_request(uac2->int_ep, GFP_ATOMIC); + if (req == NULL) { + ret = -ENOMEM; + goto err_dec_int_count; + } + + msg = kzalloc(sizeof(*msg), GFP_ATOMIC); + if (msg == NULL) { + ret = -ENOMEM; + goto err_free_request; + } + + w_index = unit_id << 8 | uac2->ac_intf; + w_value = cs << 8; + + msg->bInfo = 0; /* Non-vendor, interface interrupt */ + msg->bAttribute = UAC2_CS_CUR; + msg->wIndex = cpu_to_le16(w_index); + msg->wValue = cpu_to_le16(w_value); + + req->length = sizeof(*msg); + req->buf = msg; + req->context = agdev; + req->complete = afunc_notify_complete; + + ret = usb_ep_queue(uac2->int_ep, req, GFP_ATOMIC); + + if (ret) + goto err_free_msg; + + return 0; + +err_free_msg: + kfree(msg); +err_free_request: + usb_ep_free_request(uac2->int_ep, req); +err_dec_int_count: + atomic_dec(&uac2->int_count); + return ret; } @@ -1000,6 +1356,7 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt) { struct usb_composite_dev *cdev = fn->config->cdev; struct f_uac2 *uac2 = func_to_uac2(fn); + struct g_audio *agdev = func_to_g_audio(fn); struct usb_gadget *gadget = cdev->gadget; struct device *dev = &gadget->dev; int ret = 0; @@ -1016,6 +1373,14 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt) dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); return -EINVAL; } + + /* restart interrupt endpoint */ + if (uac2->int_ep) { + usb_ep_disable(uac2->int_ep); + config_ep_by_speed(gadget, &agdev->func, uac2->int_ep); + usb_ep_enable(uac2->int_ep); + } + return 0; } @@ -1070,6 +1435,16 @@ afunc_disable(struct usb_function *fn) uac2->as_out_alt = 0; u_audio_stop_capture(&uac2->g_audio); u_audio_stop_playback(&uac2->g_audio); + if (uac2->int_ep) + usb_ep_disable(uac2->int_ep); +} + +static void +afunc_suspend(struct usb_function *fn) +{ + struct f_uac2 *uac2 = func_to_uac2(fn); + + u_audio_suspend(&uac2->g_audio); } static int @@ -1077,37 +1452,73 @@ in_rq_cur(struct usb_function *fn, const struct usb_ctrlrequest *cr) { struct usb_request *req = fn->config->cdev->req; struct g_audio *agdev = func_to_g_audio(fn); - struct f_uac2_opts *opts; + struct f_uac2_opts *opts = g_audio_to_uac2_opts(agdev); u16 w_length = le16_to_cpu(cr->wLength); u16 w_index = le16_to_cpu(cr->wIndex); u16 w_value = le16_to_cpu(cr->wValue); u8 entity_id = (w_index >> 8) & 0xff; u8 control_selector = w_value >> 8; int value = -EOPNOTSUPP; - int p_srate, c_srate; + u32 p_srate, c_srate; - opts = g_audio_to_uac2_opts(agdev); - p_srate = opts->p_srate; - c_srate = opts->c_srate; + u_audio_get_playback_srate(agdev, &p_srate); + u_audio_get_capture_srate(agdev, &c_srate); - if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) { - struct cntrl_cur_lay3 c; - memset(&c, 0, sizeof(struct cntrl_cur_lay3)); + if ((entity_id == USB_IN_CLK_ID) || (entity_id == USB_OUT_CLK_ID)) { + if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) { + struct cntrl_cur_lay3 c; - if (entity_id == USB_IN_CLK_ID) - c.dCUR = cpu_to_le32(p_srate); - else if (entity_id == USB_OUT_CLK_ID) - c.dCUR = cpu_to_le32(c_srate); + memset(&c, 0, sizeof(struct cntrl_cur_lay3)); - value = min_t(unsigned, w_length, sizeof c); - memcpy(req->buf, &c, value); - } else if (control_selector == UAC2_CS_CONTROL_CLOCK_VALID) { - *(u8 *)req->buf = 1; - value = min_t(unsigned, w_length, 1); + if (entity_id == USB_IN_CLK_ID) + c.dCUR = cpu_to_le32(p_srate); + else if (entity_id == USB_OUT_CLK_ID) + c.dCUR = cpu_to_le32(c_srate); + + value = min_t(unsigned int, w_length, sizeof(c)); + memcpy(req->buf, &c, value); + } else if (control_selector == UAC2_CS_CONTROL_CLOCK_VALID) { + *(u8 *)req->buf = 1; + value = min_t(unsigned int, w_length, 1); + } else { + dev_err(&agdev->gadget->dev, + "%s:%d control_selector=%d TODO!\n", + __func__, __LINE__, control_selector); + } + } else if ((FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) || + (FUOUT_EN(opts) && (entity_id == USB_OUT_FU_ID))) { + unsigned int is_playback = 0; + + if (FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) + is_playback = 1; + + if (control_selector == UAC_FU_MUTE) { + unsigned int mute; + + u_audio_get_mute(agdev, is_playback, &mute); + + *(u8 *)req->buf = mute; + value = min_t(unsigned int, w_length, 1); + } else if (control_selector == UAC_FU_VOLUME) { + struct cntrl_cur_lay2 c; + s16 volume; + + memset(&c, 0, sizeof(struct cntrl_cur_lay2)); + + u_audio_get_volume(agdev, is_playback, &volume); + c.wCUR = cpu_to_le16(volume); + + value = min_t(unsigned int, w_length, sizeof(c)); + memcpy(req->buf, &c, value); + } else { + dev_err(&agdev->gadget->dev, + "%s:%d control_selector=%d TODO!\n", + __func__, __LINE__, control_selector); + } } else { dev_err(&agdev->gadget->dev, - "%s:%d control_selector=%d TODO!\n", - __func__, __LINE__, control_selector); + "%s:%d entity_id=%d control_selector=%d TODO!\n", + __func__, __LINE__, entity_id, control_selector); } return value; @@ -1118,38 +1529,88 @@ in_rq_range(struct usb_function *fn, const struct usb_ctrlrequest *cr) { struct usb_request *req = fn->config->cdev->req; struct g_audio *agdev = func_to_g_audio(fn); - struct f_uac2_opts *opts; + struct f_uac2_opts *opts = g_audio_to_uac2_opts(agdev); u16 w_length = le16_to_cpu(cr->wLength); u16 w_index = le16_to_cpu(cr->wIndex); u16 w_value = le16_to_cpu(cr->wValue); u8 entity_id = (w_index >> 8) & 0xff; u8 control_selector = w_value >> 8; - struct cntrl_range_lay3 r; int value = -EOPNOTSUPP; - int p_srate, c_srate; - opts = g_audio_to_uac2_opts(agdev); - p_srate = opts->p_srate; - c_srate = opts->c_srate; + if ((entity_id == USB_IN_CLK_ID) || (entity_id == USB_OUT_CLK_ID)) { + if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) { + struct cntrl_ranges_lay3_srates rs; + int i; + int wNumSubRanges = 0; + int srate; + int *srates; - if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) { - if (entity_id == USB_IN_CLK_ID) - r.dMIN = cpu_to_le32(p_srate); - else if (entity_id == USB_OUT_CLK_ID) - r.dMIN = cpu_to_le32(c_srate); - else - return -EOPNOTSUPP; + if (entity_id == USB_IN_CLK_ID) + srates = opts->p_srates; + else if (entity_id == USB_OUT_CLK_ID) + srates = opts->c_srates; + else + return -EOPNOTSUPP; + for (i = 0; i < UAC_MAX_RATES; i++) { + srate = srates[i]; + if (srate == 0) + break; - r.dMAX = r.dMIN; - r.dRES = 0; - r.wNumSubRanges = cpu_to_le16(1); + rs.r[wNumSubRanges].dMIN = cpu_to_le32(srate); + rs.r[wNumSubRanges].dMAX = cpu_to_le32(srate); + rs.r[wNumSubRanges].dRES = 0; + wNumSubRanges++; + dev_dbg(&agdev->gadget->dev, + "%s(): clk %d: rate ID %d: %d\n", + __func__, entity_id, wNumSubRanges, srate); + } + rs.wNumSubRanges = cpu_to_le16(wNumSubRanges); + value = min_t(unsigned int, w_length, ranges_lay3_size(rs)); + dev_dbg(&agdev->gadget->dev, "%s(): sending %d rates, size %d\n", + __func__, rs.wNumSubRanges, value); + memcpy(req->buf, &rs, value); + } else { + dev_err(&agdev->gadget->dev, + "%s:%d control_selector=%d TODO!\n", + __func__, __LINE__, control_selector); + } + } else if ((FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) || + (FUOUT_EN(opts) && (entity_id == USB_OUT_FU_ID))) { + unsigned int is_playback = 0; - value = min_t(unsigned, w_length, sizeof r); - memcpy(req->buf, &r, value); + if (FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) + is_playback = 1; + + if (control_selector == UAC_FU_VOLUME) { + struct cntrl_range_lay2 r; + s16 max_db, min_db, res_db; + + if (is_playback) { + max_db = opts->p_volume_max; + min_db = opts->p_volume_min; + res_db = opts->p_volume_res; + } else { + max_db = opts->c_volume_max; + min_db = opts->c_volume_min; + res_db = opts->c_volume_res; + } + + r.wMAX = cpu_to_le16(max_db); + r.wMIN = cpu_to_le16(min_db); + r.wRES = cpu_to_le16(res_db); + r.wNumSubRanges = cpu_to_le16(1); + + value = min_t(unsigned int, w_length, sizeof(r)); + memcpy(req->buf, &r, value); + } else { + dev_err(&agdev->gadget->dev, + "%s:%d control_selector=%d TODO!\n", + __func__, __LINE__, control_selector); + } } else { dev_err(&agdev->gadget->dev, - "%s:%d control_selector=%d TODO!\n", - __func__, __LINE__, control_selector); + "%s:%d entity_id=%d control_selector=%d TODO!\n", + __func__, __LINE__, entity_id, control_selector); } return value; @@ -1166,16 +1627,109 @@ ac_rq_in(struct usb_function *fn, const struct usb_ctrlrequest *cr) return -EOPNOTSUPP; } +static void uac2_cs_control_sam_freq(struct usb_ep *ep, struct usb_request *req) +{ + struct usb_function *fn = ep->driver_data; + struct g_audio *agdev = func_to_g_audio(fn); + struct f_uac2 *uac2 = func_to_uac2(fn); + u32 val; + + if (req->actual != 4) + return; + + val = le32_to_cpu(*((__le32 *)req->buf)); + dev_dbg(&agdev->gadget->dev, "%s val: %d.\n", __func__, val); + if (uac2->clock_id == USB_IN_CLK_ID) { + u_audio_set_playback_srate(agdev, val); + } else if (uac2->clock_id == USB_OUT_CLK_ID) { + u_audio_set_capture_srate(agdev, val); + } +} + +static void +out_rq_cur_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct g_audio *agdev = req->context; + struct usb_composite_dev *cdev = agdev->func.config->cdev; + struct f_uac2_opts *opts = g_audio_to_uac2_opts(agdev); + struct f_uac2 *uac2 = func_to_uac2(&agdev->func); + struct usb_ctrlrequest *cr = &uac2->setup_cr; + u16 w_index = le16_to_cpu(cr->wIndex); + u16 w_value = le16_to_cpu(cr->wValue); + u8 entity_id = (w_index >> 8) & 0xff; + u8 control_selector = w_value >> 8; + + if (req->status != 0) { + dev_dbg(&cdev->gadget->dev, "completion err %d\n", req->status); + return; + } + + if ((FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) || + (FUOUT_EN(opts) && (entity_id == USB_OUT_FU_ID))) { + unsigned int is_playback = 0; + + if (FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) + is_playback = 1; + + if (control_selector == UAC_FU_MUTE) { + u8 mute = *(u8 *)req->buf; + + u_audio_set_mute(agdev, is_playback, mute); + + return; + } else if (control_selector == UAC_FU_VOLUME) { + struct cntrl_cur_lay2 *c = req->buf; + s16 volume; + + volume = le16_to_cpu(c->wCUR); + u_audio_set_volume(agdev, is_playback, volume); + + return; + } else { + dev_err(&agdev->gadget->dev, + "%s:%d control_selector=%d TODO!\n", + __func__, __LINE__, control_selector); + usb_ep_set_halt(ep); + } + } +} + static int out_rq_cur(struct usb_function *fn, const struct usb_ctrlrequest *cr) { + struct usb_composite_dev *cdev = fn->config->cdev; + struct usb_request *req = fn->config->cdev->req; + struct g_audio *agdev = func_to_g_audio(fn); + struct f_uac2_opts *opts = g_audio_to_uac2_opts(agdev); + struct f_uac2 *uac2 = func_to_uac2(fn); u16 w_length = le16_to_cpu(cr->wLength); + u16 w_index = le16_to_cpu(cr->wIndex); u16 w_value = le16_to_cpu(cr->wValue); + u8 entity_id = (w_index >> 8) & 0xff; u8 control_selector = w_value >> 8; + u8 clock_id = w_index >> 8; + + if ((entity_id == USB_IN_CLK_ID) || (entity_id == USB_OUT_CLK_ID)) { + if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) { + dev_dbg(&agdev->gadget->dev, + "control_selector UAC2_CS_CONTROL_SAM_FREQ, clock: %d\n", clock_id); + cdev->gadget->ep0->driver_data = fn; + uac2->clock_id = clock_id; + req->complete = uac2_cs_control_sam_freq; + return w_length; + } + } else if ((FUIN_EN(opts) && (entity_id == USB_IN_FU_ID)) || + (FUOUT_EN(opts) && (entity_id == USB_OUT_FU_ID))) { + memcpy(&uac2->setup_cr, cr, sizeof(*cr)); + req->context = agdev; + req->complete = out_rq_cur_complete; - if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) return w_length; - + } else { + dev_err(&agdev->gadget->dev, + "%s:%d entity_id=%d control_selector=%d TODO!\n", + __func__, __LINE__, entity_id, control_selector); + } return -EOPNOTSUPP; } @@ -1251,7 +1805,15 @@ static struct configfs_item_operations f_uac2_item_ops = { .release = f_uac2_attr_release, }; -#define UAC2_ATTRIBUTE(name) \ +#define uac2_kstrtou32 kstrtou32 +#define uac2_kstrtos16 kstrtos16 +#define uac2_kstrtobool(s, base, res) kstrtobool((s), (res)) + +static const char *u32_fmt = "%u\n"; +static const char *s16_fmt = "%hd\n"; +static const char *bool_fmt = "%u\n"; + +#define UAC2_ATTRIBUTE(type, name) \ static ssize_t f_uac2_opts_##name##_show(struct config_item *item, \ char *page) \ { \ @@ -1259,7 +1821,7 @@ static ssize_t f_uac2_opts_##name##_show(struct config_item *item, \ int result; \ \ mutex_lock(&opts->lock); \ - result = sprintf(page, "%u\n", opts->name); \ + result = sprintf(page, type##_fmt, opts->name); \ mutex_unlock(&opts->lock); \ \ return result; \ @@ -1270,7 +1832,7 @@ static ssize_t f_uac2_opts_##name##_store(struct config_item *item, \ { \ struct f_uac2_opts *opts = to_f_uac2_opts(item); \ int ret; \ - u32 num; \ + type num; \ \ mutex_lock(&opts->lock); \ if (opts->refcnt) { \ @@ -1278,7 +1840,7 @@ static ssize_t f_uac2_opts_##name##_store(struct config_item *item, \ goto end; \ } \ \ - ret = kstrtou32(page, 0, &num); \ + ret = uac2_kstrto##type(page, 0, &num); \ if (ret) \ goto end; \ \ @@ -1348,15 +1910,123 @@ end: \ \ CONFIGFS_ATTR(f_uac2_opts_, name) -UAC2_ATTRIBUTE(p_chmask); -UAC2_ATTRIBUTE(p_srate); -UAC2_ATTRIBUTE(p_ssize); -UAC2_ATTRIBUTE(c_chmask); -UAC2_ATTRIBUTE(c_srate); +#define UAC2_RATE_ATTRIBUTE(name) \ +static ssize_t f_uac2_opts_##name##_show(struct config_item *item, \ + char *page) \ +{ \ + struct f_uac2_opts *opts = to_f_uac2_opts(item); \ + int result = 0; \ + int i; \ + \ + mutex_lock(&opts->lock); \ + page[0] = '\0'; \ + for (i = 0; i < UAC_MAX_RATES; i++) { \ + if (opts->name##s[i] == 0) \ + break; \ + result += sprintf(page + strlen(page), "%u,", \ + opts->name##s[i]); \ + } \ + if (strlen(page) > 0) \ + page[strlen(page) - 1] = '\n'; \ + mutex_unlock(&opts->lock); \ + \ + return result; \ +} \ + \ +static ssize_t f_uac2_opts_##name##_store(struct config_item *item, \ + const char *page, size_t len) \ +{ \ + struct f_uac2_opts *opts = to_f_uac2_opts(item); \ + char *split_page = NULL; \ + int ret = -EINVAL; \ + char *token; \ + u32 num; \ + int i; \ + \ + mutex_lock(&opts->lock); \ + if (opts->refcnt) { \ + ret = -EBUSY; \ + goto end; \ + } \ + \ + i = 0; \ + memset(opts->name##s, 0x00, sizeof(opts->name##s)); \ + split_page = kstrdup(page, GFP_KERNEL); \ + while ((token = strsep(&split_page, ",")) != NULL) { \ + ret = kstrtou32(token, 0, &num); \ + if (ret) \ + goto end; \ + \ + opts->name##s[i++] = num; \ + ret = len; \ + }; \ + \ +end: \ + kfree(split_page); \ + mutex_unlock(&opts->lock); \ + return ret; \ +} \ + \ +CONFIGFS_ATTR(f_uac2_opts_, name) + +#define UAC2_ATTRIBUTE_STRING(name) \ +static ssize_t f_uac2_opts_##name##_show(struct config_item *item, \ + char *page) \ +{ \ + struct f_uac2_opts *opts = to_f_uac2_opts(item); \ + int result; \ + \ + mutex_lock(&opts->lock); \ + result = snprintf(page, sizeof(opts->name), "%s", opts->name); \ + mutex_unlock(&opts->lock); \ + \ + return result; \ +} \ + \ +static ssize_t f_uac2_opts_##name##_store(struct config_item *item, \ + const char *page, size_t len) \ +{ \ + struct f_uac2_opts *opts = to_f_uac2_opts(item); \ + int ret = 0; \ + \ + mutex_lock(&opts->lock); \ + if (opts->refcnt) { \ + ret = -EBUSY; \ + goto end; \ + } \ + \ + ret = snprintf(opts->name, min(sizeof(opts->name), len), \ + "%s", page); \ + \ +end: \ + mutex_unlock(&opts->lock); \ + return ret; \ +} \ + \ +CONFIGFS_ATTR(f_uac2_opts_, name) + +UAC2_ATTRIBUTE(u32, p_chmask); +UAC2_RATE_ATTRIBUTE(p_srate); +UAC2_ATTRIBUTE(u32, p_ssize); +UAC2_ATTRIBUTE(u32, c_chmask); +UAC2_RATE_ATTRIBUTE(c_srate); UAC2_ATTRIBUTE_SYNC(c_sync); -UAC2_ATTRIBUTE(c_ssize); -UAC2_ATTRIBUTE(req_number); -UAC2_ATTRIBUTE(fb_max); +UAC2_ATTRIBUTE(u32, c_ssize); +UAC2_ATTRIBUTE(u32, req_number); + +UAC2_ATTRIBUTE(bool, p_mute_present); +UAC2_ATTRIBUTE(bool, p_volume_present); +UAC2_ATTRIBUTE(s16, p_volume_min); +UAC2_ATTRIBUTE(s16, p_volume_max); +UAC2_ATTRIBUTE(s16, p_volume_res); + +UAC2_ATTRIBUTE(bool, c_mute_present); +UAC2_ATTRIBUTE(bool, c_volume_present); +UAC2_ATTRIBUTE(s16, c_volume_min); +UAC2_ATTRIBUTE(s16, c_volume_max); +UAC2_ATTRIBUTE(s16, c_volume_res); +UAC2_ATTRIBUTE(u32, fb_max); +UAC2_ATTRIBUTE_STRING(function_name); static struct configfs_attribute *f_uac2_attrs[] = { &f_uac2_opts_attr_p_chmask, @@ -1368,6 +2038,21 @@ static struct configfs_attribute *f_uac2_attrs[] = { &f_uac2_opts_attr_c_sync, &f_uac2_opts_attr_req_number, &f_uac2_opts_attr_fb_max, + + &f_uac2_opts_attr_p_mute_present, + &f_uac2_opts_attr_p_volume_present, + &f_uac2_opts_attr_p_volume_min, + &f_uac2_opts_attr_p_volume_max, + &f_uac2_opts_attr_p_volume_res, + + &f_uac2_opts_attr_c_mute_present, + &f_uac2_opts_attr_c_volume_present, + &f_uac2_opts_attr_c_volume_min, + &f_uac2_opts_attr_c_volume_max, + &f_uac2_opts_attr_c_volume_res, + + &f_uac2_opts_attr_function_name, + NULL, }; @@ -1400,14 +2085,30 @@ static struct usb_function_instance *afunc_alloc_inst(void) &f_uac2_func_type); opts->p_chmask = UAC2_DEF_PCHMASK; - opts->p_srate = UAC2_DEF_PSRATE; + opts->p_srates[0] = UAC2_DEF_PSRATE; opts->p_ssize = UAC2_DEF_PSSIZE; opts->c_chmask = UAC2_DEF_CCHMASK; - opts->c_srate = UAC2_DEF_CSRATE; + opts->c_srates[0] = UAC2_DEF_CSRATE; opts->c_ssize = UAC2_DEF_CSSIZE; opts->c_sync = UAC2_DEF_CSYNC; + + opts->p_mute_present = UAC2_DEF_MUTE_PRESENT; + opts->p_volume_present = UAC2_DEF_VOLUME_PRESENT; + opts->p_volume_min = UAC2_DEF_MIN_DB; + opts->p_volume_max = UAC2_DEF_MAX_DB; + opts->p_volume_res = UAC2_DEF_RES_DB; + + opts->c_mute_present = UAC2_DEF_MUTE_PRESENT; + opts->c_volume_present = UAC2_DEF_VOLUME_PRESENT; + opts->c_volume_min = UAC2_DEF_MIN_DB; + opts->c_volume_max = UAC2_DEF_MAX_DB; + opts->c_volume_res = UAC2_DEF_RES_DB; + opts->req_number = UAC2_DEF_REQ_NUM; - opts->fb_max = UAC2_DEF_FB_MAX; + opts->fb_max = FBACK_FAST_MAX; + + snprintf(opts->function_name, sizeof(opts->function_name), "Source/Sink"); + return &opts->func_inst; } @@ -1432,6 +2133,11 @@ static void afunc_unbind(struct usb_configuration *c, struct usb_function *f) usb_free_all_descriptors(f); agdev->gadget = NULL; + + kfree(out_feature_unit_desc); + out_feature_unit_desc = NULL; + kfree(in_feature_unit_desc); + in_feature_unit_desc = NULL; } static struct usb_function *afunc_alloc(struct usb_function_instance *fi) @@ -1454,6 +2160,7 @@ static struct usb_function *afunc_alloc(struct usb_function_instance *fi) uac2->g_audio.func.set_alt = afunc_set_alt; uac2->g_audio.func.get_alt = afunc_get_alt; uac2->g_audio.func.disable = afunc_disable; + uac2->g_audio.func.suspend = afunc_suspend; uac2->g_audio.func.setup = afunc_setup; uac2->g_audio.func.free_func = afunc_free; @@ -1464,3 +2171,4 @@ DECLARE_USB_FUNCTION_INIT(uac2, afunc_alloc_inst, afunc_alloc); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Yadwinder Singh"); MODULE_AUTHOR("Jaswinder Singh"); +MODULE_AUTHOR("Ruslan Bilovol"); diff --git a/drivers/usb/gadget/function/u_audio.c b/drivers/usb/gadget/function/u_audio.c index e35a66aec941..b29cae056f7f 100644 --- a/drivers/usb/gadget/function/u_audio.c +++ b/drivers/usb/gadget/function/u_audio.c @@ -12,11 +12,14 @@ * Jaswinder Singh (jaswinder.singh@linaro.org) */ +#include #include #include #include #include #include +#include +#include #include "u_audio.h" @@ -24,6 +27,14 @@ #define PRD_SIZE_MAX PAGE_SIZE #define MIN_PERIODS 4 +enum { + UAC_FBACK_CTRL, + UAC_P_PITCH_CTRL, + UAC_MUTE_CTRL, + UAC_VOLUME_CTRL, + UAC_RATE_CTRL, +}; + /* Runtime data params for one stream */ struct uac_rtd_params { struct snd_uac_chip *uac; /* parent chip */ @@ -43,6 +54,21 @@ struct uac_rtd_params { struct usb_request *req_fback; /* Feedback endpoint request */ bool fb_ep_enabled; /* if the ep is enabled */ + + /* Volume/Mute controls and their state */ + int fu_id; /* Feature Unit ID */ + struct snd_kcontrol *snd_kctl_volume; + struct snd_kcontrol *snd_kctl_mute; + s16 volume_min, volume_max, volume_res; + s16 volume; + int mute; + + struct snd_kcontrol *snd_kctl_rate; /* read-only current rate */ + int srate; /* selected samplerate */ + int active; /* playback/capture running */ + + spinlock_t lock; /* lock for control transfers */ + }; struct snd_uac_chip { @@ -54,13 +80,9 @@ struct snd_uac_chip { struct snd_card *card; struct snd_pcm *pcm; - /* timekeeping for the playback endpoint */ - unsigned int p_interval; - unsigned int p_residue; - /* pre-calculated values for playback iso completion */ - unsigned int p_pktsize; - unsigned int p_pktsize_residue; + unsigned long long p_residue_mil; + unsigned int p_interval; unsigned int p_framesize; }; @@ -133,6 +155,9 @@ static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req) struct snd_pcm_runtime *runtime; struct uac_rtd_params *prm = req->context; struct snd_uac_chip *uac = prm->uac; + unsigned int frames, p_pktsize; + unsigned long long pitched_rate_mil, p_pktsize_residue_mil, + residue_frames_mil, div_result; /* i/f shutting down */ if (!prm->ep_enabled) { @@ -172,19 +197,44 @@ static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req) * If there is a residue from this division, add it to the * residue accumulator. */ - req->length = uac->p_pktsize; - uac->p_residue += uac->p_pktsize_residue; + unsigned long long p_interval_mil = uac->p_interval * 1000000ULL; + + pitched_rate_mil = (unsigned long long) prm->srate * prm->pitch; + div_result = pitched_rate_mil; + do_div(div_result, uac->p_interval); + do_div(div_result, 1000000); + frames = (unsigned int) div_result; + + pr_debug("p_srate %d, pitch %d, interval_mil %llu, frames %d\n", + prm->srate, prm->pitch, p_interval_mil, frames); + + p_pktsize = min_t(unsigned int, + uac->p_framesize * frames, + ep->maxpacket); + + if (p_pktsize < ep->maxpacket) { + residue_frames_mil = pitched_rate_mil - frames * p_interval_mil; + p_pktsize_residue_mil = uac->p_framesize * residue_frames_mil; + } else + p_pktsize_residue_mil = 0; + + req->length = p_pktsize; + uac->p_residue_mil += p_pktsize_residue_mil; /* - * Whenever there are more bytes in the accumulator than we + * Whenever there are more bytes in the accumulator p_residue_mil than we * need to add one more sample frame, increase this packet's * size and decrease the accumulator. */ - if (uac->p_residue / uac->p_interval >= uac->p_framesize) { + div_result = uac->p_residue_mil; + do_div(div_result, uac->p_interval); + do_div(div_result, 1000000); + if ((unsigned int) div_result >= uac->p_framesize) { req->length += uac->p_framesize; - uac->p_residue -= uac->p_framesize * - uac->p_interval; + uac->p_residue_mil -= uac->p_framesize * p_interval_mil; + pr_debug("increased req length to %d\n", req->length); } + pr_debug("remains uac->p_residue_mil %llu\n", uac->p_residue_mil); req->actual = req->length; } @@ -233,7 +283,6 @@ static void u_audio_iso_fback_complete(struct usb_ep *ep, struct uac_rtd_params *prm = req->context; struct snd_uac_chip *uac = prm->uac; struct g_audio *audio_dev = uac->audio_dev; - struct uac_params *params = &audio_dev->params; int status = req->status; /* i/f shutting down */ @@ -255,7 +304,7 @@ static void u_audio_iso_fback_complete(struct usb_ep *ep, __func__, status, req->actual, req->length); u_audio_set_fback_frequency(audio_dev->gadget->speed, audio_dev->out_ep, - params->c_srate, prm->pitch, + prm->srate, prm->pitch, req->buf); if (usb_ep_queue(ep, req, GFP_ATOMIC)) @@ -339,36 +388,33 @@ static int uac_pcm_open(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct g_audio *audio_dev; struct uac_params *params; + struct uac_rtd_params *prm; int p_ssize, c_ssize; - int p_srate, c_srate; int p_chmask, c_chmask; audio_dev = uac->audio_dev; params = &audio_dev->params; p_ssize = params->p_ssize; c_ssize = params->c_ssize; - p_srate = params->p_srate; - c_srate = params->c_srate; p_chmask = params->p_chmask; c_chmask = params->c_chmask; - uac->p_residue = 0; + uac->p_residue_mil = 0; runtime->hw = uac_pcm_hardware; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - runtime->hw.rate_min = p_srate; runtime->hw.formats = uac_ssize_to_fmt(p_ssize); runtime->hw.channels_min = num_channels(p_chmask); - runtime->hw.period_bytes_min = 2 * uac->p_prm.max_psize - / runtime->hw.periods_min; + prm = &uac->p_prm; } else { - runtime->hw.rate_min = c_srate; runtime->hw.formats = uac_ssize_to_fmt(c_ssize); runtime->hw.channels_min = num_channels(c_chmask); - runtime->hw.period_bytes_min = 2 * uac->c_prm.max_psize - / runtime->hw.periods_min; + prm = &uac->c_prm; } + runtime->hw.period_bytes_min = 2 * prm->max_psize + / runtime->hw.periods_min; + runtime->hw.rate_min = prm->srate; runtime->hw.rate_max = runtime->hw.rate_min; runtime->hw.channels_max = runtime->hw.channels_min; @@ -445,6 +491,99 @@ static inline void free_ep_fback(struct uac_rtd_params *prm, struct usb_ep *ep) dev_err(uac->card->dev, "%s:%d Error!\n", __func__, __LINE__); } +static void set_active(struct uac_rtd_params *prm, bool active) +{ + // notifying through the Rate ctrl + struct snd_kcontrol *kctl = prm->snd_kctl_rate; + unsigned long flags; + + spin_lock_irqsave(&prm->lock, flags); + if (prm->active != active) { + prm->active = active; + snd_ctl_notify(prm->uac->card, SNDRV_CTL_EVENT_MASK_VALUE, + &kctl->id); + } + spin_unlock_irqrestore(&prm->lock, flags); +} + +int u_audio_set_capture_srate(struct g_audio *audio_dev, int srate) +{ + struct uac_params *params = &audio_dev->params; + struct snd_uac_chip *uac = audio_dev->uac; + struct uac_rtd_params *prm; + int i; + unsigned long flags; + + dev_dbg(&audio_dev->gadget->dev, "%s: srate %d\n", __func__, srate); + prm = &uac->c_prm; + for (i = 0; i < UAC_MAX_RATES; i++) { + if (params->c_srates[i] == srate) { + spin_lock_irqsave(&prm->lock, flags); + prm->srate = srate; + spin_unlock_irqrestore(&prm->lock, flags); + return 0; + } + if (params->c_srates[i] == 0) + break; + } + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(u_audio_set_capture_srate); + +int u_audio_get_capture_srate(struct g_audio *audio_dev, u32 *val) +{ + struct snd_uac_chip *uac = audio_dev->uac; + struct uac_rtd_params *prm; + unsigned long flags; + + prm = &uac->c_prm; + spin_lock_irqsave(&prm->lock, flags); + *val = prm->srate; + spin_unlock_irqrestore(&prm->lock, flags); + return 0; +} +EXPORT_SYMBOL_GPL(u_audio_get_capture_srate); + +int u_audio_set_playback_srate(struct g_audio *audio_dev, int srate) +{ + struct uac_params *params = &audio_dev->params; + struct snd_uac_chip *uac = audio_dev->uac; + struct uac_rtd_params *prm; + int i; + unsigned long flags; + + dev_dbg(&audio_dev->gadget->dev, "%s: srate %d\n", __func__, srate); + prm = &uac->p_prm; + for (i = 0; i < UAC_MAX_RATES; i++) { + if (params->p_srates[i] == srate) { + spin_lock_irqsave(&prm->lock, flags); + prm->srate = srate; + spin_unlock_irqrestore(&prm->lock, flags); + return 0; + } + if (params->p_srates[i] == 0) + break; + } + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(u_audio_set_playback_srate); + +int u_audio_get_playback_srate(struct g_audio *audio_dev, u32 *val) +{ + struct snd_uac_chip *uac = audio_dev->uac; + struct uac_rtd_params *prm; + unsigned long flags; + + prm = &uac->p_prm; + spin_lock_irqsave(&prm->lock, flags); + *val = prm->srate; + spin_unlock_irqrestore(&prm->lock, flags); + return 0; +} +EXPORT_SYMBOL_GPL(u_audio_get_playback_srate); + int u_audio_start_capture(struct g_audio *audio_dev) { struct snd_uac_chip *uac = audio_dev->uac; @@ -456,8 +595,9 @@ int u_audio_start_capture(struct g_audio *audio_dev) struct uac_params *params = &audio_dev->params; int req_len, i; - ep = audio_dev->out_ep; prm = &uac->c_prm; + dev_dbg(dev, "start capture with rate %d\n", prm->srate); + ep = audio_dev->out_ep; config_ep_by_speed(gadget, &audio_dev->func, ep); req_len = ep->maxpacket; @@ -483,6 +623,8 @@ int u_audio_start_capture(struct g_audio *audio_dev) dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); } + set_active(&uac->c_prm, true); + ep_fback = audio_dev->in_ep_fback; if (!ep_fback) return 0; @@ -514,7 +656,7 @@ int u_audio_start_capture(struct g_audio *audio_dev) */ prm->pitch = 1000000; u_audio_set_fback_frequency(audio_dev->gadget->speed, ep, - params->c_srate, prm->pitch, + prm->srate, prm->pitch, req_fback->buf); if (usb_ep_queue(ep_fback, req_fback, GFP_ATOMIC)) @@ -528,6 +670,7 @@ void u_audio_stop_capture(struct g_audio *audio_dev) { struct snd_uac_chip *uac = audio_dev->uac; + set_active(&uac->c_prm, false); if (audio_dev->in_ep_fback) free_ep_fback(&uac->c_prm, audio_dev->in_ep_fback); free_ep(&uac->c_prm, audio_dev->out_ep); @@ -546,12 +689,18 @@ int u_audio_start_playback(struct g_audio *audio_dev) unsigned int factor; const struct usb_endpoint_descriptor *ep_desc; int req_len, i; + unsigned int p_pktsize; - ep = audio_dev->in_ep; prm = &uac->p_prm; + dev_dbg(dev, "start playback with rate %d\n", prm->srate); + ep = audio_dev->in_ep; config_ep_by_speed(gadget, &audio_dev->func, ep); ep_desc = ep->desc; + /* + * Always start with original frequency + */ + prm->pitch = 1000000; /* pre-calculate the playback endpoint's interval */ if (gadget->speed == USB_SPEED_FULL) @@ -563,19 +712,13 @@ int u_audio_start_playback(struct g_audio *audio_dev) uac->p_framesize = params->p_ssize * num_channels(params->p_chmask); uac->p_interval = factor / (1 << (ep_desc->bInterval - 1)); - uac->p_pktsize = min_t(unsigned int, + p_pktsize = min_t(unsigned int, uac->p_framesize * - (params->p_srate / uac->p_interval), + (prm->srate / uac->p_interval), ep->maxpacket); - if (uac->p_pktsize < ep->maxpacket) - uac->p_pktsize_residue = uac->p_framesize * - (params->p_srate % uac->p_interval); - else - uac->p_pktsize_residue = 0; - - req_len = uac->p_pktsize; - uac->p_residue = 0; + req_len = p_pktsize; + uac->p_residue_mil = 0; prm->ep_enabled = true; usb_ep_enable(ep); @@ -599,6 +742,8 @@ int u_audio_start_playback(struct g_audio *audio_dev) dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); } + set_active(&uac->p_prm, true); + return 0; } EXPORT_SYMBOL_GPL(u_audio_start_playback); @@ -607,10 +752,117 @@ void u_audio_stop_playback(struct g_audio *audio_dev) { struct snd_uac_chip *uac = audio_dev->uac; + set_active(&uac->p_prm, false); free_ep(&uac->p_prm, audio_dev->in_ep); } EXPORT_SYMBOL_GPL(u_audio_stop_playback); +void u_audio_suspend(struct g_audio *audio_dev) +{ + struct snd_uac_chip *uac = audio_dev->uac; + + set_active(&uac->p_prm, false); + set_active(&uac->c_prm, false); +} +EXPORT_SYMBOL_GPL(u_audio_suspend); + +int u_audio_get_volume(struct g_audio *audio_dev, int playback, s16 *val) +{ + struct snd_uac_chip *uac = audio_dev->uac; + struct uac_rtd_params *prm; + unsigned long flags; + + if (playback) + prm = &uac->p_prm; + else + prm = &uac->c_prm; + + spin_lock_irqsave(&prm->lock, flags); + *val = prm->volume; + spin_unlock_irqrestore(&prm->lock, flags); + + return 0; +} +EXPORT_SYMBOL_GPL(u_audio_get_volume); + +int u_audio_set_volume(struct g_audio *audio_dev, int playback, s16 val) +{ + struct snd_uac_chip *uac = audio_dev->uac; + struct uac_rtd_params *prm; + unsigned long flags; + int change = 0; + + if (playback) + prm = &uac->p_prm; + else + prm = &uac->c_prm; + + spin_lock_irqsave(&prm->lock, flags); + val = clamp(val, prm->volume_min, prm->volume_max); + if (prm->volume != val) { + prm->volume = val; + change = 1; + } + spin_unlock_irqrestore(&prm->lock, flags); + + if (change) + snd_ctl_notify(uac->card, SNDRV_CTL_EVENT_MASK_VALUE, + &prm->snd_kctl_volume->id); + + return 0; +} +EXPORT_SYMBOL_GPL(u_audio_set_volume); + +int u_audio_get_mute(struct g_audio *audio_dev, int playback, int *val) +{ + struct snd_uac_chip *uac = audio_dev->uac; + struct uac_rtd_params *prm; + unsigned long flags; + + if (playback) + prm = &uac->p_prm; + else + prm = &uac->c_prm; + + spin_lock_irqsave(&prm->lock, flags); + *val = prm->mute; + spin_unlock_irqrestore(&prm->lock, flags); + + return 0; +} +EXPORT_SYMBOL_GPL(u_audio_get_mute); + +int u_audio_set_mute(struct g_audio *audio_dev, int playback, int val) +{ + struct snd_uac_chip *uac = audio_dev->uac; + struct uac_rtd_params *prm; + unsigned long flags; + int change = 0; + int mute; + + if (playback) + prm = &uac->p_prm; + else + prm = &uac->c_prm; + + mute = val ? 1 : 0; + + spin_lock_irqsave(&prm->lock, flags); + if (prm->mute != mute) { + prm->mute = mute; + change = 1; + } + spin_unlock_irqrestore(&prm->lock, flags); + + if (change) + snd_ctl_notify(uac->card, SNDRV_CTL_EVENT_MASK_VALUE, + &prm->snd_kctl_mute->id); + + return 0; +} +EXPORT_SYMBOL_GPL(u_audio_set_mute); + + static int u_audio_pitch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -670,14 +922,234 @@ static int u_audio_pitch_put(struct snd_kcontrol *kcontrol, return change; } -static const struct snd_kcontrol_new u_audio_controls[] = { +static int u_audio_mute_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) { - .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = "Capture Pitch 1000000", - .info = u_audio_pitch_info, - .get = u_audio_pitch_get, - .put = u_audio_pitch_put, -}, + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + uinfo->value.integer.step = 1; + + return 0; +} + +static int u_audio_mute_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol); + unsigned long flags; + + spin_lock_irqsave(&prm->lock, flags); + ucontrol->value.integer.value[0] = !prm->mute; + spin_unlock_irqrestore(&prm->lock, flags); + + return 0; +} + +static int u_audio_mute_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol); + struct snd_uac_chip *uac = prm->uac; + struct g_audio *audio_dev = uac->audio_dev; + unsigned int val; + unsigned long flags; + int change = 0; + + val = !ucontrol->value.integer.value[0]; + + spin_lock_irqsave(&prm->lock, flags); + if (val != prm->mute) { + prm->mute = val; + change = 1; + } + spin_unlock_irqrestore(&prm->lock, flags); + + if (change && audio_dev->notify) + audio_dev->notify(audio_dev, prm->fu_id, UAC_FU_MUTE); + + return change; +} + +/* + * TLV callback for mixer volume controls + */ +static int u_audio_volume_tlv(struct snd_kcontrol *kcontrol, int op_flag, + unsigned int size, unsigned int __user *_tlv) +{ + struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol); + DECLARE_TLV_DB_MINMAX(scale, 0, 0); + + if (size < sizeof(scale)) + return -ENOMEM; + + /* UAC volume resolution is 1/256 dB, TLV is 1/100 dB */ + scale[2] = (prm->volume_min * 100) / 256; + scale[3] = (prm->volume_max * 100) / 256; + if (copy_to_user(_tlv, scale, sizeof(scale))) + return -EFAULT; + + return 0; +} + +static int u_audio_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol); + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = + (prm->volume_max - prm->volume_min + prm->volume_res - 1) + / prm->volume_res; + uinfo->value.integer.step = 1; + + return 0; +} + +static int u_audio_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol); + unsigned long flags; + + spin_lock_irqsave(&prm->lock, flags); + ucontrol->value.integer.value[0] = + (prm->volume - prm->volume_min) / prm->volume_res; + spin_unlock_irqrestore(&prm->lock, flags); + + return 0; +} + +static int u_audio_volume_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol); + struct snd_uac_chip *uac = prm->uac; + struct g_audio *audio_dev = uac->audio_dev; + unsigned int val; + s16 volume; + unsigned long flags; + int change = 0; + + val = ucontrol->value.integer.value[0]; + + spin_lock_irqsave(&prm->lock, flags); + volume = (val * prm->volume_res) + prm->volume_min; + volume = clamp(volume, prm->volume_min, prm->volume_max); + if (volume != prm->volume) { + prm->volume = volume; + change = 1; + } + spin_unlock_irqrestore(&prm->lock, flags); + + if (change && audio_dev->notify) + audio_dev->notify(audio_dev, prm->fu_id, UAC_FU_VOLUME); + + return change; +} + +static int get_max_srate(const int *srates) +{ + int i, max_srate = 0; + + for (i = 0; i < UAC_MAX_RATES; i++) { + if (srates[i] == 0) + break; + if (srates[i] > max_srate) + max_srate = srates[i]; + } + return max_srate; +} + +static int get_min_srate(const int *srates) +{ + int i, min_srate = INT_MAX; + + for (i = 0; i < UAC_MAX_RATES; i++) { + if (srates[i] == 0) + break; + if (srates[i] < min_srate) + min_srate = srates[i]; + } + return min_srate; +} + +static int u_audio_rate_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + const int *srates; + struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol); + struct snd_uac_chip *uac = prm->uac; + struct g_audio *audio_dev = uac->audio_dev; + struct uac_params *params = &audio_dev->params; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + + if (prm == &uac->c_prm) + srates = params->c_srates; + else + srates = params->p_srates; + uinfo->value.integer.min = get_min_srate(srates); + uinfo->value.integer.max = get_max_srate(srates); + return 0; +} + +static int u_audio_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol); + unsigned long flags; + + spin_lock_irqsave(&prm->lock, flags); + if (prm->active) + ucontrol->value.integer.value[0] = prm->srate; + else + /* not active: reporting zero rate */ + ucontrol->value.integer.value[0] = 0; + spin_unlock_irqrestore(&prm->lock, flags); + return 0; +} + +static struct snd_kcontrol_new u_audio_controls[] = { + [UAC_FBACK_CTRL] { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "Capture Pitch 1000000", + .info = u_audio_pitch_info, + .get = u_audio_pitch_get, + .put = u_audio_pitch_put, + }, + [UAC_P_PITCH_CTRL] { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "Playback Pitch 1000000", + .info = u_audio_pitch_info, + .get = u_audio_pitch_get, + .put = u_audio_pitch_put, + }, + [UAC_MUTE_CTRL] { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", /* will be filled later */ + .info = u_audio_mute_info, + .get = u_audio_mute_get, + .put = u_audio_mute_put, + }, + [UAC_VOLUME_CTRL] { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "", /* will be filled later */ + .info = u_audio_volume_info, + .get = u_audio_volume_get, + .put = u_audio_volume_put, + }, + [UAC_RATE_CTRL] { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "", /* will be filled later */ + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = u_audio_rate_info, + .get = u_audio_rate_get, + }, }; int g_audio_setup(struct g_audio *g_audio, const char *pcm_name, @@ -689,7 +1161,7 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name, struct snd_kcontrol *kctl; struct uac_params *params; int p_chmask, c_chmask; - int err; + int i, err; if (!g_audio) return -EINVAL; @@ -707,8 +1179,10 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name, if (c_chmask) { struct uac_rtd_params *prm = &uac->c_prm; - uac->c_prm.uac = uac; + spin_lock_init(&prm->lock); + uac->c_prm.uac = uac; prm->max_psize = g_audio->out_ep_maxpsize; + prm->srate = params->c_srates[0]; prm->reqs = kcalloc(params->req_number, sizeof(struct usb_request *), @@ -730,8 +1204,10 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name, if (p_chmask) { struct uac_rtd_params *prm = &uac->p_prm; + spin_lock_init(&prm->lock); uac->p_prm.uac = uac; prm->max_psize = g_audio->in_ep_maxpsize; + prm->srate = params->p_srates[0]; prm->reqs = kcalloc(params->req_number, sizeof(struct usb_request *), @@ -774,10 +1250,18 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name, snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &uac_pcm_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &uac_pcm_ops); - if (c_chmask && g_audio->in_ep_fback) { + /* + * Create mixer and controls + * Create only if it's required on USB side + */ + if ((c_chmask && g_audio->in_ep_fback) + || (p_chmask && params->p_fu.id) + || (c_chmask && params->c_fu.id)) strscpy(card->mixername, card_name, sizeof(card->driver)); - kctl = snd_ctl_new1(&u_audio_controls[0], &uac->c_prm); + if (c_chmask && g_audio->in_ep_fback) { + kctl = snd_ctl_new1(&u_audio_controls[UAC_FBACK_CTRL], + &uac->c_prm); if (!kctl) { err = -ENOMEM; goto snd_fail; @@ -791,6 +1275,117 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name, goto snd_fail; } + if (p_chmask) { + kctl = snd_ctl_new1(&u_audio_controls[UAC_P_PITCH_CTRL], + &uac->p_prm); + if (!kctl) { + err = -ENOMEM; + goto snd_fail; + } + + kctl->id.device = pcm->device; + kctl->id.subdevice = 0; + + err = snd_ctl_add(card, kctl); + if (err < 0) + goto snd_fail; + } + + for (i = 0; i <= SNDRV_PCM_STREAM_LAST; i++) { + struct uac_rtd_params *prm; + struct uac_fu_params *fu; + char ctrl_name[24]; + char *direction; + + if (!pcm->streams[i].substream_count) + continue; + + if (i == SNDRV_PCM_STREAM_PLAYBACK) { + prm = &uac->p_prm; + fu = ¶ms->p_fu; + direction = "Playback"; + } else { + prm = &uac->c_prm; + fu = ¶ms->c_fu; + direction = "Capture"; + } + + prm->fu_id = fu->id; + + if (fu->mute_present) { + snprintf(ctrl_name, sizeof(ctrl_name), + "PCM %s Switch", direction); + + u_audio_controls[UAC_MUTE_CTRL].name = ctrl_name; + + kctl = snd_ctl_new1(&u_audio_controls[UAC_MUTE_CTRL], + prm); + if (!kctl) { + err = -ENOMEM; + goto snd_fail; + } + + kctl->id.device = pcm->device; + kctl->id.subdevice = 0; + + err = snd_ctl_add(card, kctl); + if (err < 0) + goto snd_fail; + prm->snd_kctl_mute = kctl; + prm->mute = 0; + } + + if (fu->volume_present) { + snprintf(ctrl_name, sizeof(ctrl_name), + "PCM %s Volume", direction); + + u_audio_controls[UAC_VOLUME_CTRL].name = ctrl_name; + + kctl = snd_ctl_new1(&u_audio_controls[UAC_VOLUME_CTRL], + prm); + if (!kctl) { + err = -ENOMEM; + goto snd_fail; + } + + kctl->id.device = pcm->device; + kctl->id.subdevice = 0; + + + kctl->tlv.c = u_audio_volume_tlv; + kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ | + SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; + + err = snd_ctl_add(card, kctl); + if (err < 0) + goto snd_fail; + prm->snd_kctl_volume = kctl; + prm->volume = fu->volume_max; + prm->volume_max = fu->volume_max; + prm->volume_min = fu->volume_min; + prm->volume_res = fu->volume_res; + } + + /* Add rate control */ + snprintf(ctrl_name, sizeof(ctrl_name), + "%s Rate", direction); + u_audio_controls[UAC_RATE_CTRL].name = ctrl_name; + + kctl = snd_ctl_new1(&u_audio_controls[UAC_RATE_CTRL], prm); + if (!kctl) { + err = -ENOMEM; + goto snd_fail; + } + + kctl->id.device = pcm->device; + kctl->id.subdevice = 0; + + err = snd_ctl_add(card, kctl); + if (err < 0) + goto snd_fail; + prm->snd_kctl_rate = kctl; + } + strscpy(card->driver, card_name, sizeof(card->driver)); strscpy(card->shortname, card_name, sizeof(card->shortname)); sprintf(card->longname, "%s %i", card_name, card->dev->id); diff --git a/drivers/usb/gadget/function/u_audio.h b/drivers/usb/gadget/function/u_audio.h index a218cdf771fe..9512b8fccfaa 100644 --- a/drivers/usb/gadget/function/u_audio.h +++ b/drivers/usb/gadget/function/u_audio.h @@ -10,25 +10,48 @@ #define __U_AUDIO_H #include +#include "uac_common.h" /* * Same maximum frequency deviation on the slower side as in * sound/usb/endpoint.c. Value is expressed in per-mil deviation. - * The maximum deviation on the faster side will be provided as - * parameter, as it impacts the endpoint required bandwidth. */ #define FBACK_SLOW_MAX 250 +/* + * Maximum frequency deviation on the faster side, default value for UAC1/2. + * Value is expressed in per-mil deviation. + * UAC2 provides the value as a parameter as it impacts the endpoint required + * bandwidth. + */ +#define FBACK_FAST_MAX 5 + +/* Feature Unit parameters */ +struct uac_fu_params { + int id; /* Feature Unit ID */ + + bool mute_present; /* mute control enable */ + + bool volume_present; /* volume control enable */ + s16 volume_min; /* min volume in 1/256 dB */ + s16 volume_max; /* max volume in 1/256 dB */ + s16 volume_res; /* volume resolution in 1/256 dB */ +}; + struct uac_params { /* playback */ int p_chmask; /* channel mask */ - int p_srate; /* rate in Hz */ + int p_srates[UAC_MAX_RATES]; /* available rates in Hz (0 terminated list) */ int p_ssize; /* sample size */ + struct uac_fu_params p_fu; /* Feature Unit parameters */ /* capture */ int c_chmask; /* channel mask */ - int c_srate; /* rate in Hz */ + int c_srates[UAC_MAX_RATES]; /* available rates in Hz (0 terminated list) */ int c_ssize; /* sample size */ + struct uac_fu_params c_fu; /* Feature Unit parameters */ + + /* rates are dynamic, in uac_rtd_params */ int req_number; /* number of preallocated requests */ int fb_max; /* upper frequency drift feedback limit per-mil */ @@ -49,6 +72,9 @@ struct g_audio { /* Max packet size for all out_ep possible speeds */ unsigned int out_ep_maxpsize; + /* Notify UAC driver about control change */ + int (*notify)(struct g_audio *g_audio, int unit_id, int cs); + /* The ALSA Sound Card it represents on the USB-Client side */ struct snd_uac_chip *uac; @@ -94,4 +120,16 @@ void u_audio_stop_capture(struct g_audio *g_audio); int u_audio_start_playback(struct g_audio *g_audio); void u_audio_stop_playback(struct g_audio *g_audio); +int u_audio_get_capture_srate(struct g_audio *audio_dev, u32 *val); +int u_audio_set_capture_srate(struct g_audio *audio_dev, int srate); +int u_audio_get_playback_srate(struct g_audio *audio_dev, u32 *val); +int u_audio_set_playback_srate(struct g_audio *audio_dev, int srate); + +int u_audio_get_volume(struct g_audio *g_audio, int playback, s16 *val); +int u_audio_set_volume(struct g_audio *g_audio, int playback, s16 val); +int u_audio_get_mute(struct g_audio *g_audio, int playback, int *val); +int u_audio_set_mute(struct g_audio *g_audio, int playback, int val); + +void u_audio_suspend(struct g_audio *g_audio); + #endif /* __U_AUDIO_H */ diff --git a/drivers/usb/gadget/function/u_uac1.h b/drivers/usb/gadget/function/u_uac1.h index 39c0e29e1b46..f7a616760e31 100644 --- a/drivers/usb/gadget/function/u_uac1.h +++ b/drivers/usb/gadget/function/u_uac1.h @@ -9,6 +9,7 @@ #define __U_UAC1_H #include +#include "uac_common.h" #define UAC1_OUT_EP_MAX_PACKET_SIZE 200 #define UAC1_DEF_CCHMASK 0x3 @@ -18,19 +19,41 @@ #define UAC1_DEF_PSRATE 48000 #define UAC1_DEF_PSSIZE 2 #define UAC1_DEF_REQ_NUM 2 +#define UAC1_DEF_INT_REQ_NUM 10 + +#define UAC1_DEF_MUTE_PRESENT 1 +#define UAC1_DEF_VOLUME_PRESENT 1 +#define UAC1_DEF_MIN_DB (-100*256) /* -100 dB */ +#define UAC1_DEF_MAX_DB 0 /* 0 dB */ +#define UAC1_DEF_RES_DB (1*256) /* 1 dB */ struct f_uac1_opts { struct usb_function_instance func_inst; int c_chmask; - int c_srate; + int c_srates[UAC_MAX_RATES]; int c_ssize; int p_chmask; - int p_srate; + int p_srates[UAC_MAX_RATES]; int p_ssize; + + bool p_mute_present; + bool p_volume_present; + s16 p_volume_min; + s16 p_volume_max; + s16 p_volume_res; + + bool c_mute_present; + bool c_volume_present; + s16 c_volume_min; + s16 c_volume_max; + s16 c_volume_res; + int req_number; unsigned bound:1; + char function_name[32]; + struct mutex lock; int refcnt; }; diff --git a/drivers/usb/gadget/function/u_uac2.h b/drivers/usb/gadget/function/u_uac2.h index 179d3ef6a195..ed96c7c853e4 100644 --- a/drivers/usb/gadget/function/u_uac2.h +++ b/drivers/usb/gadget/function/u_uac2.h @@ -14,6 +14,7 @@ #define U_UAC2_H #include +#include "uac_common.h" #define UAC2_DEF_PCHMASK 0x3 #define UAC2_DEF_PSRATE 48000 @@ -22,21 +23,43 @@ #define UAC2_DEF_CSRATE 64000 #define UAC2_DEF_CSSIZE 2 #define UAC2_DEF_CSYNC USB_ENDPOINT_SYNC_ASYNC + +#define UAC2_DEF_MUTE_PRESENT 1 +#define UAC2_DEF_VOLUME_PRESENT 1 +#define UAC2_DEF_MIN_DB (-100*256) /* -100 dB */ +#define UAC2_DEF_MAX_DB 0 /* 0 dB */ +#define UAC2_DEF_RES_DB (1*256) /* 1 dB */ + #define UAC2_DEF_REQ_NUM 2 -#define UAC2_DEF_FB_MAX 5 +#define UAC2_DEF_INT_REQ_NUM 10 struct f_uac2_opts { struct usb_function_instance func_inst; int p_chmask; - int p_srate; + int p_srates[UAC_MAX_RATES]; int p_ssize; int c_chmask; - int c_srate; + int c_srates[UAC_MAX_RATES]; int c_ssize; int c_sync; + + bool p_mute_present; + bool p_volume_present; + s16 p_volume_min; + s16 p_volume_max; + s16 p_volume_res; + + bool c_mute_present; + bool c_volume_present; + s16 c_volume_min; + s16 c_volume_max; + s16 c_volume_res; + int req_number; int fb_max; - bool bound; + bool bound; + + char function_name[32]; struct mutex lock; int refcnt; diff --git a/drivers/usb/gadget/function/uac_common.h b/drivers/usb/gadget/function/uac_common.h new file mode 100644 index 000000000000..3ecf89d6e814 --- /dev/null +++ b/drivers/usb/gadget/function/uac_common.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + */ + +#ifndef UAC_COMMON_H +#define UAC_COMMON_H + +#define UAC_MAX_RATES 10 /* maximum number of rates configurable by f_uac1/2 */ +#endif diff --git a/drivers/usb/gadget/legacy/audio.c b/drivers/usb/gadget/legacy/audio.c index a748ed0842e8..c89c777a1aa3 100644 --- a/drivers/usb/gadget/legacy/audio.c +++ b/drivers/usb/gadget/legacy/audio.c @@ -22,32 +22,34 @@ USB_GADGET_COMPOSITE_OPTIONS(); /* Playback(USB-IN) Default Stereo - Fl/Fr */ static int p_chmask = UAC2_DEF_PCHMASK; -module_param(p_chmask, uint, S_IRUGO); +module_param(p_chmask, uint, 0444); MODULE_PARM_DESC(p_chmask, "Playback Channel Mask"); /* Playback Default 48 KHz */ -static int p_srate = UAC2_DEF_PSRATE; -module_param(p_srate, uint, S_IRUGO); -MODULE_PARM_DESC(p_srate, "Playback Sampling Rate"); +static int p_srates[UAC_MAX_RATES] = {UAC2_DEF_PSRATE}; +static int p_srates_cnt = 1; +module_param_array_named(p_srate, p_srates, uint, &p_srates_cnt, 0444); +MODULE_PARM_DESC(p_srate, "Playback Sampling Rates (array)"); /* Playback Default 16bits/sample */ static int p_ssize = UAC2_DEF_PSSIZE; -module_param(p_ssize, uint, S_IRUGO); +module_param(p_ssize, uint, 0444); MODULE_PARM_DESC(p_ssize, "Playback Sample Size(bytes)"); /* Capture(USB-OUT) Default Stereo - Fl/Fr */ static int c_chmask = UAC2_DEF_CCHMASK; -module_param(c_chmask, uint, S_IRUGO); +module_param(c_chmask, uint, 0444); MODULE_PARM_DESC(c_chmask, "Capture Channel Mask"); /* Capture Default 64 KHz */ -static int c_srate = UAC2_DEF_CSRATE; -module_param(c_srate, uint, S_IRUGO); -MODULE_PARM_DESC(c_srate, "Capture Sampling Rate"); +static int c_srates[UAC_MAX_RATES] = {UAC2_DEF_CSRATE}; +static int c_srates_cnt = 1; +module_param_array_named(c_srate, c_srates, uint, &c_srates_cnt, 0444); +MODULE_PARM_DESC(c_srate, "Capture Sampling Rates (array)"); /* Capture Default 16bits/sample */ static int c_ssize = UAC2_DEF_CSSIZE; -module_param(c_ssize, uint, S_IRUGO); +module_param(c_ssize, uint, 0444); MODULE_PARM_DESC(c_ssize, "Capture Sample Size(bytes)"); #else #ifndef CONFIG_GADGET_UAC1_LEGACY @@ -55,58 +57,60 @@ MODULE_PARM_DESC(c_ssize, "Capture Sample Size(bytes)"); /* Playback(USB-IN) Default Stereo - Fl/Fr */ static int p_chmask = UAC1_DEF_PCHMASK; -module_param(p_chmask, uint, S_IRUGO); +module_param(p_chmask, uint, 0444); MODULE_PARM_DESC(p_chmask, "Playback Channel Mask"); /* Playback Default 48 KHz */ -static int p_srate = UAC1_DEF_PSRATE; -module_param(p_srate, uint, S_IRUGO); -MODULE_PARM_DESC(p_srate, "Playback Sampling Rate"); +static int p_srates[UAC_MAX_RATES] = {UAC1_DEF_PSRATE}; +static int p_srates_cnt = 1; +module_param_array_named(p_srate, p_srates, uint, &p_srates_cnt, 0444); +MODULE_PARM_DESC(p_srate, "Playback Sampling Rates (array)"); /* Playback Default 16bits/sample */ static int p_ssize = UAC1_DEF_PSSIZE; -module_param(p_ssize, uint, S_IRUGO); +module_param(p_ssize, uint, 0444); MODULE_PARM_DESC(p_ssize, "Playback Sample Size(bytes)"); /* Capture(USB-OUT) Default Stereo - Fl/Fr */ static int c_chmask = UAC1_DEF_CCHMASK; -module_param(c_chmask, uint, S_IRUGO); +module_param(c_chmask, uint, 0444); MODULE_PARM_DESC(c_chmask, "Capture Channel Mask"); /* Capture Default 48 KHz */ -static int c_srate = UAC1_DEF_CSRATE; -module_param(c_srate, uint, S_IRUGO); -MODULE_PARM_DESC(c_srate, "Capture Sampling Rate"); +static int c_srates[UAC_MAX_RATES] = {UAC1_DEF_CSRATE}; +static int c_srates_cnt = 1; +module_param_array_named(c_srate, c_srates, uint, &c_srates_cnt, 0444); +MODULE_PARM_DESC(c_srate, "Capture Sampling Rates (array)"); /* Capture Default 16bits/sample */ static int c_ssize = UAC1_DEF_CSSIZE; -module_param(c_ssize, uint, S_IRUGO); +module_param(c_ssize, uint, 0444); MODULE_PARM_DESC(c_ssize, "Capture Sample Size(bytes)"); #else /* CONFIG_GADGET_UAC1_LEGACY */ #include "u_uac1_legacy.h" static char *fn_play = FILE_PCM_PLAYBACK; -module_param(fn_play, charp, S_IRUGO); +module_param(fn_play, charp, 0444); MODULE_PARM_DESC(fn_play, "Playback PCM device file name"); static char *fn_cap = FILE_PCM_CAPTURE; -module_param(fn_cap, charp, S_IRUGO); +module_param(fn_cap, charp, 0444); MODULE_PARM_DESC(fn_cap, "Capture PCM device file name"); static char *fn_cntl = FILE_CONTROL; -module_param(fn_cntl, charp, S_IRUGO); +module_param(fn_cntl, charp, 0444); MODULE_PARM_DESC(fn_cntl, "Control device file name"); static int req_buf_size = UAC1_OUT_EP_MAX_PACKET_SIZE; -module_param(req_buf_size, int, S_IRUGO); +module_param(req_buf_size, int, 0444); MODULE_PARM_DESC(req_buf_size, "ISO OUT endpoint request buffer size"); static int req_count = UAC1_REQ_COUNT; -module_param(req_count, int, S_IRUGO); +module_param(req_count, int, 0444); MODULE_PARM_DESC(req_count, "ISO OUT endpoint request count"); static int audio_buf_size = UAC1_AUDIO_BUF_SIZE; -module_param(audio_buf_size, int, S_IRUGO); +module_param(audio_buf_size, int, 0444); MODULE_PARM_DESC(audio_buf_size, "Audio buffer size"); #endif /* CONFIG_GADGET_UAC1_LEGACY */ #endif @@ -237,9 +241,11 @@ static int audio_bind(struct usb_composite_dev *cdev) { #ifndef CONFIG_GADGET_UAC1 struct f_uac2_opts *uac2_opts; + int i; #else #ifndef CONFIG_GADGET_UAC1_LEGACY struct f_uac1_opts *uac1_opts; + int i; #else struct f_uac1_legacy_opts *uac1_opts; #endif @@ -263,20 +269,32 @@ static int audio_bind(struct usb_composite_dev *cdev) #ifndef CONFIG_GADGET_UAC1 uac2_opts = container_of(fi_uac2, struct f_uac2_opts, func_inst); uac2_opts->p_chmask = p_chmask; - uac2_opts->p_srate = p_srate; + + for (i = 0; i < p_srates_cnt; ++i) + uac2_opts->p_srates[i] = p_srates[i]; + uac2_opts->p_ssize = p_ssize; uac2_opts->c_chmask = c_chmask; - uac2_opts->c_srate = c_srate; + + for (i = 0; i < c_srates_cnt; ++i) + uac2_opts->c_srates[i] = c_srates[i]; + uac2_opts->c_ssize = c_ssize; uac2_opts->req_number = UAC2_DEF_REQ_NUM; #else #ifndef CONFIG_GADGET_UAC1_LEGACY uac1_opts = container_of(fi_uac1, struct f_uac1_opts, func_inst); uac1_opts->p_chmask = p_chmask; - uac1_opts->p_srate = p_srate; + + for (i = 0; i < p_srates_cnt; ++i) + uac1_opts->p_srates[i] = p_srates[i]; + uac1_opts->p_ssize = p_ssize; uac1_opts->c_chmask = c_chmask; - uac1_opts->c_srate = c_srate; + + for (i = 0; i < c_srates_cnt; ++i) + uac1_opts->c_srates[i] = c_srates[i]; + uac1_opts->c_ssize = c_ssize; uac1_opts->req_number = UAC1_DEF_REQ_NUM; #else /* CONFIG_GADGET_UAC1_LEGACY */ diff --git a/fs/exfat/balloc.c b/fs/exfat/balloc.c index 51b16f03fc3c..da2c94c652b0 100644 --- a/fs/exfat/balloc.c +++ b/fs/exfat/balloc.c @@ -160,7 +160,7 @@ int exfat_set_bitmap(struct inode *inode, unsigned int clu, bool sync) return 0; } -void exfat_clear_bitmap(struct inode *inode, unsigned int clu) +void exfat_clear_bitmap(struct inode *inode, unsigned int clu, bool sync) { int i, b; unsigned int ent_idx; @@ -176,7 +176,7 @@ void exfat_clear_bitmap(struct inode *inode, unsigned int clu) b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx); clear_bit_le(b, sbi->vol_amap[i]->b_data); - exfat_update_bh(sbi->vol_amap[i], IS_DIRSYNC(inode)); + exfat_update_bh(sbi->vol_amap[i], sync); if (opts->discard) { int ret_discard; diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h index 52f3b6457e14..2aa02a7c643a 100644 --- a/fs/exfat/exfat_fs.h +++ b/fs/exfat/exfat_fs.h @@ -416,7 +416,7 @@ int exfat_count_num_clusters(struct super_block *sb, int exfat_load_bitmap(struct super_block *sb); void exfat_free_bitmap(struct exfat_sb_info *sbi); int exfat_set_bitmap(struct inode *inode, unsigned int clu, bool sync); -void exfat_clear_bitmap(struct inode *inode, unsigned int clu); +void exfat_clear_bitmap(struct inode *inode, unsigned int clu, bool sync); unsigned int exfat_find_free_bitmap(struct super_block *sb, unsigned int clu); int exfat_count_used_clusters(struct super_block *sb, unsigned int *ret_count); diff --git a/fs/exfat/fatent.c b/fs/exfat/fatent.c index 084ae062f5b2..78aa02e2d2c1 100644 --- a/fs/exfat/fatent.c +++ b/fs/exfat/fatent.c @@ -149,6 +149,7 @@ int exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain) unsigned int clu; struct super_block *sb = inode->i_sb; struct exfat_sb_info *sbi = EXFAT_SB(sb); + int cur_cmap_i, next_cmap_i; /* invalid cluster number */ if (p_chain->dir == EXFAT_FREE_CLUSTER || @@ -168,21 +169,53 @@ int exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain) clu = p_chain->dir; - if (p_chain->flags == ALLOC_NO_FAT_CHAIN) { - do { - exfat_clear_bitmap(inode, clu); - clu++; + cur_cmap_i = next_cmap_i = + BITMAP_OFFSET_SECTOR_INDEX(sb, CLUSTER_TO_BITMAP_ENT(clu)); + if (p_chain->flags == ALLOC_NO_FAT_CHAIN) { + unsigned int last_cluster = p_chain->dir + p_chain->size - 1; + + do { + bool sync = false; + + if (clu < last_cluster) + next_cmap_i = + BITMAP_OFFSET_SECTOR_INDEX(sb, CLUSTER_TO_BITMAP_ENT(clu+1)); + + /* flush bitmap only if index would be changed or for last cluster */ + if (clu == last_cluster || cur_cmap_i != next_cmap_i) { + sync = true; + cur_cmap_i = next_cmap_i; + } + + exfat_clear_bitmap(inode, clu, (sync && IS_DIRSYNC(inode))); + clu++; num_clusters++; } while (num_clusters < p_chain->size); } else { do { - exfat_clear_bitmap(inode, clu); + bool sync = false; + unsigned int n_clu = clu; + int err = exfat_get_next_cluster(sb, &n_clu); - if (exfat_get_next_cluster(sb, &clu)) - goto dec_used_clus; + if (err || n_clu == EXFAT_EOF_CLUSTER) + sync = true; + else + next_cmap_i = + BITMAP_OFFSET_SECTOR_INDEX(sb, CLUSTER_TO_BITMAP_ENT(n_clu)); + + if (cur_cmap_i != next_cmap_i) { + sync = true; + cur_cmap_i = next_cmap_i; + } + + exfat_clear_bitmap(inode, clu, (sync && IS_DIRSYNC(inode))); + clu = n_clu; num_clusters++; + + if (err) + goto dec_used_clus; } while (clu != EXFAT_EOF_CLUSTER); } diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index a612d641d21b..76b46cfac240 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -4217,8 +4217,9 @@ static inline void f2fs_invalidate_compress_pages(struct f2fs_sb_info *sbi, #define inc_compr_inode_stat(inode) do { } while (0) #endif -static inline void set_compress_context(struct inode *inode) +static inline int set_compress_context(struct inode *inode) { +#ifdef CONFIG_F2FS_FS_COMPRESSION struct f2fs_sb_info *sbi = F2FS_I_SB(inode); F2FS_I(inode)->i_compress_algorithm = @@ -4240,6 +4241,10 @@ static inline void set_compress_context(struct inode *inode) stat_inc_compr_inode(inode); inc_compr_inode_stat(inode); f2fs_mark_inode_dirty_sync(inode, true); + return 0; +#else + return -EOPNOTSUPP; +#endif } static inline bool f2fs_disable_compressed_file(struct inode *inode) diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index c4fe1295340c..b14843c686a6 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -1855,8 +1855,8 @@ static int f2fs_setflags_common(struct inode *inode, u32 iflags, u32 mask) return -EINVAL; if (S_ISREG(inode->i_mode) && inode->i_size) return -EINVAL; - - set_compress_context(inode); + if (set_compress_context(inode)) + return -EOPNOTSUPP; } } if ((iflags ^ masked_flags) & F2FS_NOCOMP_FL) { diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h index 8c193033604f..3ee42f15483b 100644 --- a/include/linux/cgroup-defs.h +++ b/include/linux/cgroup-defs.h @@ -282,6 +282,13 @@ struct css_set { struct rcu_head rcu_head; }; +struct ext_css_set { + struct css_set cset; + + struct list_head mg_src_preload_node; + struct list_head mg_dst_preload_node; +}; + struct cgroup_base_stat { struct task_cputime cputime; }; diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 67b2190b1dae..771fc8ecba49 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -72,7 +72,8 @@ struct css_task_iter { }; extern struct cgroup_root cgrp_dfl_root; -extern struct css_set init_css_set; +extern struct ext_css_set init_ext_css_set; +#define init_css_set init_ext_css_set.cset #define SUBSYS(_x) extern struct cgroup_subsys _x ## _cgrp_subsys; #include diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index 6ea0873708b1..2e9c8a504fab 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -345,6 +345,9 @@ struct mem_cgroup { extern struct mem_cgroup *root_mem_cgroup; +struct lruvec *page_to_lruvec(struct page *page, pg_data_t *pgdat); +void do_traversal_all_lruvec(void); + static __always_inline bool memcg_stat_item_in_bytes(int idx) { if (idx == MEMCG_PERCPU_B) @@ -969,6 +972,15 @@ void split_page_memcg(struct page *head, unsigned int nr); struct mem_cgroup; +static inline struct lruvec *page_to_lruvec(struct page *page, pg_data_t *pgdat) +{ + return NULL; +} + +static inline void do_traversal_all_lruvec(void) +{ +} + static inline bool mem_cgroup_is_root(struct mem_cgroup *memcg) { return true; diff --git a/include/linux/mm.h b/include/linux/mm.h index 70fee0e3a5fa..1a64ab7ba67a 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -3363,7 +3363,6 @@ unsigned long wp_shared_mapping_range(struct address_space *mapping, extern int sysctl_nr_trim_pages; extern bool pte_map_lock_addr(struct vm_fault *vmf, unsigned long addr); extern int reclaim_shmem_address_space(struct address_space *mapping); -extern int reclaim_pages_from_list(struct list_head *page_list); /** * seal_check_future_write - Check for F_SEAL_FUTURE_WRITE flag and handle it diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h index 8fc71e9d7bb0..835e4f83e7a4 100644 --- a/include/linux/mm_inline.h +++ b/include/linux/mm_inline.h @@ -4,6 +4,10 @@ #include #include +#ifndef __GENKSYMS__ +#define PROTECT_TRACE_INCLUDE_PATH +#include +#endif /** * page_is_file_lru - should the page be on a file LRU or anon LRU? @@ -48,6 +52,7 @@ static __always_inline void update_lru_size(struct lruvec *lruvec, static __always_inline void add_page_to_lru_list(struct page *page, struct lruvec *lruvec, enum lru_list lru) { + trace_android_vh_add_page_to_lrulist(page, false, lru); update_lru_size(lruvec, lru, page_zonenum(page), thp_nr_pages(page)); list_add(&page->lru, &lruvec->lists[lru]); } @@ -55,6 +60,7 @@ static __always_inline void add_page_to_lru_list(struct page *page, static __always_inline void add_page_to_lru_list_tail(struct page *page, struct lruvec *lruvec, enum lru_list lru) { + trace_android_vh_add_page_to_lrulist(page, false, lru); update_lru_size(lruvec, lru, page_zonenum(page), thp_nr_pages(page)); list_add_tail(&page->lru, &lruvec->lists[lru]); } @@ -62,6 +68,7 @@ static __always_inline void add_page_to_lru_list_tail(struct page *page, static __always_inline void del_page_from_lru_list(struct page *page, struct lruvec *lruvec, enum lru_list lru) { + trace_android_vh_del_page_from_lrulist(page, false, lru); list_del(&page->lru); update_lru_size(lruvec, lru, page_zonenum(page), -thp_nr_pages(page)); } diff --git a/include/linux/rmap.h b/include/linux/rmap.h index 7482da1ea67b..7dee138fbf0f 100644 --- a/include/linux/rmap.h +++ b/include/linux/rmap.h @@ -11,6 +11,10 @@ #include #include #include +#ifndef __GENKSYMS__ +#define PROTECT_TRACE_INCLUDE_PATH +#include +#endif /* * The anon_vma heads a list of private "related" vmas, to scan if @@ -194,7 +198,12 @@ void hugepage_add_new_anon_rmap(struct page *, struct vm_area_struct *, static inline void page_dup_rmap(struct page *page, bool compound) { - atomic_inc(compound ? compound_mapcount_ptr(page) : &page->_mapcount); + bool success = false; + + if (!compound) + trace_android_vh_update_page_mapcount(page, true, compound, NULL, &success); + if (!success) + atomic_inc(compound ? compound_mapcount_ptr(page) : &page->_mapcount); } /* diff --git a/include/linux/sched/sysctl.h b/include/linux/sched/sysctl.h index 3c31ba88aca5..581ee79550de 100644 --- a/include/linux/sched/sysctl.h +++ b/include/linux/sched/sysctl.h @@ -92,6 +92,13 @@ int sysctl_numa_balancing(struct ctl_table *table, int write, void *buffer, int sysctl_schedstats(struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos); +#ifdef CONFIG_SMP +extern unsigned int sysctl_sched_pelt_multiplier; + +int sched_pelt_multiplier(struct ctl_table *table, int write, void *buffer, + size_t *lenp, loff_t *ppos); +#endif + #if defined(CONFIG_ENERGY_MODEL) && defined(CONFIG_CPU_FREQ_GOV_SCHEDUTIL) extern unsigned int sysctl_sched_energy_aware; int sched_energy_aware_handler(struct ctl_table *table, int write, diff --git a/include/linux/usb/audio-v2.h b/include/linux/usb/audio-v2.h index ead8c9a47c6a..8fc2abd7aecb 100644 --- a/include/linux/usb/audio-v2.h +++ b/include/linux/usb/audio-v2.h @@ -156,6 +156,20 @@ struct uac2_feature_unit_descriptor { __u8 bmaControls[]; /* variable length */ } __attribute__((packed)); +#define UAC2_DT_FEATURE_UNIT_SIZE(ch) (6 + ((ch) + 1) * 4) + +/* As above, but more useful for defining your own descriptors: */ +#define DECLARE_UAC2_FEATURE_UNIT_DESCRIPTOR(ch) \ +struct uac2_feature_unit_descriptor_##ch { \ + __u8 bLength; \ + __u8 bDescriptorType; \ + __u8 bDescriptorSubtype; \ + __u8 bUnitID; \ + __u8 bSourceID; \ + __le32 bmaControls[ch + 1]; \ + __u8 iFeature; \ +} __packed + /* 4.7.2.10 Effect Unit Descriptor */ struct uac2_effect_unit_descriptor { diff --git a/include/sound/hdmi-codec.h b/include/sound/hdmi-codec.h index b55970859a13..4fc733c8c570 100644 --- a/include/sound/hdmi-codec.h +++ b/include/sound/hdmi-codec.h @@ -34,6 +34,11 @@ struct hdmi_codec_daifmt { unsigned int frame_clk_inv:1; unsigned int bit_clk_master:1; unsigned int frame_clk_master:1; + /* bit_fmt could be standard PCM format or + * IEC958 encoded format. ALSA IEC958 plugin will pass + * IEC958_SUBFRAME format to the underneath driver. + */ + snd_pcm_format_t bit_fmt; }; /* @@ -60,12 +65,22 @@ struct hdmi_codec_ops { /* * Configures HDMI-encoder for audio stream. - * Mandatory + * Having either prepare or hw_params is mandatory. */ int (*hw_params)(struct device *dev, void *data, struct hdmi_codec_daifmt *fmt, struct hdmi_codec_params *hparms); + /* + * Configures HDMI-encoder for audio stream. Can be called + * multiple times for each setup. + * + * Having either prepare or hw_params is mandatory. + */ + int (*prepare)(struct device *dev, void *data, + struct hdmi_codec_daifmt *fmt, + struct hdmi_codec_params *hparms); + /* * Shuts down the audio stream. * Mandatory diff --git a/include/sound/pcm_iec958.h b/include/sound/pcm_iec958.h index 0939aa45e2fe..64e84441cde1 100644 --- a/include/sound/pcm_iec958.h +++ b/include/sound/pcm_iec958.h @@ -4,6 +4,14 @@ #include +int snd_pcm_create_iec958_consumer_default(u8 *cs, size_t len); + +int snd_pcm_fill_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs, + size_t len); + +int snd_pcm_fill_iec958_consumer_hw_params(struct snd_pcm_hw_params *params, + u8 *cs, size_t len); + int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs, size_t len); diff --git a/include/trace/hooks/binder.h b/include/trace/hooks/binder.h index 2b9e7e09a13d..5147261de15c 100644 --- a/include/trace/hooks/binder.h +++ b/include/trace/hooks/binder.h @@ -11,19 +11,23 @@ * Following tracepoints are not exported in tracefs and provide a * mechanism for vendor modules to hook and extend functionality */ -#ifdef __GENKSYMS__ +#if defined(__GENKSYMS__) || !IS_ENABLED(CONFIG_ANDROID_BINDER_IPC) struct binder_alloc; struct binder_proc; struct binder_thread; struct binder_transaction; -struct task_struct; -struct seq_file; struct binder_transaction_data; #else /* struct binder_alloc */ #include <../drivers/android/binder_alloc.h> /* struct binder_proc, struct binder_thread, struct binder_transaction */ #include <../drivers/android/binder_internal.h> +#endif + +#ifdef __GENKSYMS__ +struct task_struct; +struct seq_file; +#else /* struct task_struct */ #include /* struct seq_file */ @@ -31,6 +35,7 @@ struct binder_transaction_data; /* struct binder_transaction_data */ #include #endif /* __GENKSYMS__ */ + DECLARE_HOOK(android_vh_binder_transaction_init, TP_PROTO(struct binder_transaction *t), TP_ARGS(t)); diff --git a/include/trace/hooks/block.h b/include/trace/hooks/block.h index 964fff355602..a5a7ac70a2ee 100644 --- a/include/trace/hooks/block.h +++ b/include/trace/hooks/block.h @@ -10,7 +10,7 @@ #include #include -#ifdef __GENKSYMS__ +#if defined(__GENKSYMS__) || !defined(CONFIG_BLOCK) struct blk_mq_tags; struct blk_mq_alloc_data; struct blk_mq_tag_set; diff --git a/include/trace/hooks/cgroup.h b/include/trace/hooks/cgroup.h index 68818ad29600..dfe79e5a3646 100644 --- a/include/trace/hooks/cgroup.h +++ b/include/trace/hooks/cgroup.h @@ -9,12 +9,16 @@ #include struct cgroup_taskset; -#ifdef __GENKSYMS__ +#if defined(__GENKSYMS__) || !IS_ENABLED(CONFIG_CGROUPS) struct cgroup_subsys; -struct task_struct; #else /* struct cgroup_subsys */ #include +#endif + +#ifdef __GENKSYMS__ +struct task_struct; +#else /* struct task_struct */ #include #endif /* __GENKSYMS__ */ diff --git a/include/trace/hooks/logbuf.h b/include/trace/hooks/logbuf.h index 6aeb10a4661b..3794192554cb 100644 --- a/include/trace/hooks/logbuf.h +++ b/include/trace/hooks/logbuf.h @@ -10,7 +10,7 @@ #include #include -#ifdef __GENKSYMS__ +#if defined(__GENKSYMS__) || !IS_ENABLED(CONFIG_PRINTK) struct printk_record; struct printk_ringbuffer; #else diff --git a/include/trace/hooks/mm.h b/include/trace/hooks/mm.h index 91d9172c6b4a..8b0225ce7ced 100644 --- a/include/trace/hooks/mm.h +++ b/include/trace/hooks/mm.h @@ -1,4 +1,13 @@ /* SPDX-License-Identifier: GPL-2.0 */ +#ifdef PROTECT_TRACE_INCLUDE_PATH +#undef PROTECT_TRACE_INCLUDE_PATH + +#include +#include +#include + +#else /* PROTECT_TRACE_INCLUDE_PATH */ + #undef TRACE_SYSTEM #define TRACE_SYSTEM mm @@ -13,6 +22,7 @@ #include #include #include +#include #ifdef __GENKSYMS__ struct slabinfo; @@ -87,6 +97,12 @@ DECLARE_HOOK(android_vh_include_reserved_zone, DECLARE_HOOK(android_vh_show_mem, TP_PROTO(unsigned int filter, nodemask_t *nodemask), TP_ARGS(filter, nodemask)); +DECLARE_HOOK(android_vh_alloc_pages_slowpath_begin, + TP_PROTO(gfp_t gfp_mask, unsigned int order, unsigned long *pdata), + TP_ARGS(gfp_mask, order, pdata)); +DECLARE_HOOK(android_vh_alloc_pages_slowpath_end, + TP_PROTO(gfp_t gfp_mask, unsigned int order, unsigned long data), + TP_ARGS(gfp_mask, order, data)); struct dirty_throttle_control; DECLARE_HOOK(android_vh_mm_dirty_limits, TP_PROTO(struct dirty_throttle_control *const gdtc, bool strictlimit, @@ -133,11 +149,37 @@ DECLARE_HOOK(android_vh_mmap_region, DECLARE_HOOK(android_vh_try_to_unmap_one, TP_PROTO(struct vm_area_struct *vma, struct page *page, unsigned long addr, bool ret), TP_ARGS(vma, page, addr, ret)); +DECLARE_HOOK(android_vh_do_page_trylock, + TP_PROTO(struct page *page, struct rw_semaphore *sem, + bool *got_lock, bool *success), + TP_ARGS(page, sem, got_lock, success)); DECLARE_HOOK(android_vh_drain_all_pages_bypass, TP_PROTO(gfp_t gfp_mask, unsigned int order, unsigned long alloc_flags, int migratetype, unsigned long did_some_progress, bool *bypass), TP_ARGS(gfp_mask, order, alloc_flags, migratetype, did_some_progress, bypass)); +DECLARE_HOOK(android_vh_update_page_mapcount, + TP_PROTO(struct page *page, bool inc_size, bool compound, + bool *first_mapping, bool *success), + TP_ARGS(page, inc_size, compound, first_mapping, success)); +DECLARE_HOOK(android_vh_add_page_to_lrulist, + TP_PROTO(struct page *page, bool compound, enum lru_list lru), + TP_ARGS(page, compound, lru)); +DECLARE_HOOK(android_vh_del_page_from_lrulist, + TP_PROTO(struct page *page, bool compound, enum lru_list lru), + TP_ARGS(page, compound, lru)); +DECLARE_HOOK(android_vh_show_mapcount_pages, + TP_PROTO(void *unused), + TP_ARGS(unused)); +DECLARE_HOOK(android_vh_do_traversal_lruvec, + TP_PROTO(struct lruvec *lruvec), + TP_ARGS(lruvec)); +DECLARE_HOOK(android_vh_page_should_be_protected, + TP_PROTO(struct page *page, bool *should_protect), + TP_ARGS(page, should_protect)); +DECLARE_HOOK(android_vh_mark_page_accessed, + TP_PROTO(struct page *page), + TP_ARGS(page)); DECLARE_HOOK(android_vh_cma_drain_all_pages_bypass, TP_PROTO(unsigned int migratetype, bool *bypass), TP_ARGS(migratetype, bypass)); @@ -215,9 +257,17 @@ DECLARE_HOOK(android_vh_alloc_si, DECLARE_HOOK(android_vh_free_pages, TP_PROTO(struct page *page, unsigned int order), TP_ARGS(page, order)); +DECLARE_HOOK(android_vh_set_shmem_page_flag, + TP_PROTO(struct page *page), + TP_ARGS(page)); +DECLARE_HOOK(android_vh_remove_vmalloc_stack, + TP_PROTO(struct vm_struct *vm), + TP_ARGS(vm)); /* macro versions of hooks are no longer required */ #endif /* _TRACE_HOOK_MM_H */ /* This part must be outside protection */ #include + +#endif /* PROTECT_TRACE_INCLUDE_PATH */ diff --git a/include/trace/hooks/mmc_core.h b/include/trace/hooks/mmc_core.h index b4b93b2f4c9e..eb012e9c8147 100644 --- a/include/trace/hooks/mmc_core.h +++ b/include/trace/hooks/mmc_core.h @@ -10,13 +10,17 @@ #include #include -#ifdef __GENKSYMS__ +#if defined(__GENKSYMS__) || !IS_ENABLED(CONFIG_MMC_SDHCI) struct sdhci_host; -struct mmc_card; -struct mmc_host; #else /* struct sdhci_host */ #include <../drivers/mmc/host/sdhci.h> +#endif + +#ifdef __GENKSYMS__ +struct mmc_card; +struct mmc_host; +#else /* struct mmc_card */ #include /* struct mmc_host */ diff --git a/include/trace/hooks/psi.h b/include/trace/hooks/psi.h index 3842118af3c3..3200b639ad3f 100644 --- a/include/trace/hooks/psi.h +++ b/include/trace/hooks/psi.h @@ -12,7 +12,7 @@ #if defined(CONFIG_TRACEPOINTS) && defined(CONFIG_ANDROID_VENDOR_HOOKS) -#ifdef __GENKSYMS__ +#if defined(__GENKSYMS__) || !defined(CONFIG_PSI) struct psi_group; struct psi_trigger; #else diff --git a/include/trace/hooks/restore_incpath.h b/include/trace/hooks/restore_incpath.h new file mode 100644 index 000000000000..3a97e4572007 --- /dev/null +++ b/include/trace/hooks/restore_incpath.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Include this file from a header declaring vendor hooks to preserve and later + * restore TRACE_INCLUDE_PATH value. Typical usage: + * + * #ifdef PROTECT_TRACE_INCLUDE_PATH + * #undef PROTECT_TRACE_INCLUDE_PATH + * + * #include + * #include + * #include + * + * #else + * + * + * + * #endif + * + * The header that includes vendor hooks header file should define + * PROTECT_TRACE_INCLUDE_PATH before including the vendor hook file like this: + * + * #define PROTECT_TRACE_INCLUDE_PATH + * #include + */ +#ifdef STORED_TRACE_INCLUDE_PATH +# undef TRACE_INCLUDE_PATH +# define TRACE_INCLUDE_PATH STORED_TRACE_INCLUDE_PATH +# undef STORED_TRACE_INCLUDE_PATH +#else +# undef TRACE_INCLUDE_PATH +#endif + diff --git a/include/trace/hooks/save_incpath.h b/include/trace/hooks/save_incpath.h new file mode 100644 index 000000000000..3b4621a47275 --- /dev/null +++ b/include/trace/hooks/save_incpath.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Include this file from a header declaring vendor hooks to preserve and later + * restore TRACE_INCLUDE_PATH value. Typical usage: + * + * #ifdef PROTECT_TRACE_INCLUDE_PATH + * #undef PROTECT_TRACE_INCLUDE_PATH + * + * #include + * #include + * #include + * + * #else + * + * + * + * #endif + * + * The header that includes vendor hooks header file should define + * PROTECT_TRACE_INCLUDE_PATH before including the vendor hook file like this: + * + * #define PROTECT_TRACE_INCLUDE_PATH + * #include + */ +#ifdef TRACE_INCLUDE_PATH +#define STORED_TRACE_INCLUDE_PATH TRACE_INCLUDE_PATH +#undef TRACE_INCLUDE_PATH +#endif + diff --git a/include/trace/hooks/sched.h b/include/trace/hooks/sched.h index 9f16fffd89e4..d0fc31e2c966 100644 --- a/include/trace/hooks/sched.h +++ b/include/trace/hooks/sched.h @@ -391,6 +391,17 @@ DECLARE_HOOK(android_vh_setscheduler_uclamp, TP_PROTO(struct task_struct *tsk, int clamp_id, unsigned int value), TP_ARGS(tsk, clamp_id, value)); +DECLARE_HOOK(android_vh_pidfd_open, + TP_PROTO(struct pid *p), + TP_ARGS(p)); + +DECLARE_HOOK(android_vh_mmput, + TP_PROTO(void *unused), + TP_ARGS(unused)); + +DECLARE_HOOK(android_vh_sched_pelt_multiplier, + TP_PROTO(unsigned int old, unsigned int cur, int *ret), + TP_ARGS(old, cur, ret)); /* macro versions of hooks are no longer required */ #endif /* _TRACE_HOOK_SCHED_H */ diff --git a/include/trace/hooks/typec.h b/include/trace/hooks/typec.h index db06fb8c30e9..825cb37bc8b2 100644 --- a/include/trace/hooks/typec.h +++ b/include/trace/hooks/typec.h @@ -6,12 +6,13 @@ #define _TRACE_HOOK_TYPEC_H #include #include +#include #include /* * Following tracepoints are not exported in tracefs and provide a * mechanism for vendor modules to hook and extend functionality */ -#ifdef __GENKSYMS__ +#if defined(__GENKSYMS__) || !IS_ENABLED(CONFIG_TYPEC_TCPCI) struct tcpci_data; #else /* struct tcpci_data */ diff --git a/include/trace/hooks/ufshcd.h b/include/trace/hooks/ufshcd.h index 8483dc966c6c..906e02740f3f 100644 --- a/include/trace/hooks/ufshcd.h +++ b/include/trace/hooks/ufshcd.h @@ -10,7 +10,7 @@ * Following tracepoints are not exported in tracefs and provide a * mechanism for vendor modules to hook and extend functionality */ -#ifdef __GENKSYMS__ +#if defined(__GENKSYMS__) || !IS_ENABLED(CONFIG_SCSI_UFSHCD) struct ufs_hba; struct ufshcd_lrb; struct uic_command; diff --git a/include/trace/hooks/vmscan.h b/include/trace/hooks/vmscan.h index 4f1d6ab9f498..a175232c89f6 100644 --- a/include/trace/hooks/vmscan.h +++ b/include/trace/hooks/vmscan.h @@ -28,6 +28,18 @@ DECLARE_RESTRICTED_HOOK(android_rvh_set_balance_anon_file_reclaim, DECLARE_HOOK(android_vh_page_referenced_check_bypass, TP_PROTO(struct page *page, unsigned long nr_to_scan, int lru, bool *bypass), TP_ARGS(page, nr_to_scan, lru, bypass)); +DECLARE_HOOK(android_vh_page_trylock_get_result, + TP_PROTO(struct page *page, bool *trylock_fail), + TP_ARGS(page, trylock_fail)); +DECLARE_HOOK(android_vh_handle_failed_page_trylock, + TP_PROTO(struct list_head *page_list), + TP_ARGS(page_list)); +DECLARE_HOOK(android_vh_page_trylock_set, + TP_PROTO(struct page *page), + TP_ARGS(page)); +DECLARE_HOOK(android_vh_page_trylock_clear, + TP_PROTO(struct page *page), + TP_ARGS(page)); DECLARE_HOOK(android_vh_shrink_node_memcgs, TP_PROTO(struct mem_cgroup *memcg, bool *skip), TP_ARGS(memcg, skip)); diff --git a/include/uapi/linux/android/binder.h b/include/uapi/linux/android/binder.h index 2d3f015e2ae3..7badb670f24f 100644 --- a/include/uapi/linux/android/binder.h +++ b/include/uapi/linux/android/binder.h @@ -319,6 +319,7 @@ enum transaction_flags { TF_STATUS_CODE = 0x08, /* contents are a 32-bit status code */ TF_ACCEPT_FDS = 0x10, /* allow replies with file descriptors */ TF_CLEAR_BUF = 0x20, /* clear buffer on txn complete */ + TF_UPDATE_TXN = 0x40, /* update the outdated pending async txn */ }; struct binder_transaction_data { diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index 2b39f8ce5ac4..d50776066fa5 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -746,25 +746,28 @@ EXPORT_SYMBOL_GPL(of_css); * reference-counted, to improve performance when child cgroups * haven't been created. */ -struct css_set init_css_set = { - .refcount = REFCOUNT_INIT(1), - .dom_cset = &init_css_set, - .tasks = LIST_HEAD_INIT(init_css_set.tasks), - .mg_tasks = LIST_HEAD_INIT(init_css_set.mg_tasks), - .dying_tasks = LIST_HEAD_INIT(init_css_set.dying_tasks), - .task_iters = LIST_HEAD_INIT(init_css_set.task_iters), - .threaded_csets = LIST_HEAD_INIT(init_css_set.threaded_csets), - .cgrp_links = LIST_HEAD_INIT(init_css_set.cgrp_links), - .mg_preload_node = LIST_HEAD_INIT(init_css_set.mg_preload_node), - .mg_node = LIST_HEAD_INIT(init_css_set.mg_node), - - /* - * The following field is re-initialized when this cset gets linked - * in cgroup_init(). However, let's initialize the field - * statically too so that the default cgroup can be accessed safely - * early during boot. - */ - .dfl_cgrp = &cgrp_dfl_root.cgrp, +struct ext_css_set init_ext_css_set = { + .cset = { + .refcount = REFCOUNT_INIT(1), + .dom_cset = &init_css_set, + .tasks = LIST_HEAD_INIT(init_css_set.tasks), + .mg_tasks = LIST_HEAD_INIT(init_css_set.mg_tasks), + .dying_tasks = LIST_HEAD_INIT(init_css_set.dying_tasks), + .task_iters = LIST_HEAD_INIT(init_css_set.task_iters), + .threaded_csets = LIST_HEAD_INIT(init_css_set.threaded_csets), + .cgrp_links = LIST_HEAD_INIT(init_css_set.cgrp_links), + .mg_preload_node = LIST_HEAD_INIT(init_css_set.mg_preload_node), + .mg_node = LIST_HEAD_INIT(init_css_set.mg_node), + /* + * The following field is re-initialized when this cset gets linked + * in cgroup_init(). However, let's initialize the field + * statically too so that the default cgroup can be accessed safely + * early during boot. + */ + .dfl_cgrp = &cgrp_dfl_root.cgrp, + }, + .mg_src_preload_node = LIST_HEAD_INIT(init_ext_css_set.mg_src_preload_node), + .mg_dst_preload_node = LIST_HEAD_INIT(init_ext_css_set.mg_dst_preload_node), }; static int css_set_count = 1; /* 1 for init_css_set */ @@ -1191,6 +1194,7 @@ static struct css_set *find_css_set(struct css_set *old_cset, struct cgroup *cgrp) { struct cgroup_subsys_state *template[CGROUP_SUBSYS_COUNT] = { }; + struct ext_css_set *ext_cset; struct css_set *cset; struct list_head tmp_links; struct cgrp_cset_link *link; @@ -1211,9 +1215,10 @@ static struct css_set *find_css_set(struct css_set *old_cset, if (cset) return cset; - cset = kzalloc(sizeof(*cset), GFP_KERNEL); - if (!cset) + ext_cset = kzalloc(sizeof(*ext_cset), GFP_KERNEL); + if (!ext_cset) return NULL; + cset = &ext_cset->cset; /* Allocate all the cgrp_cset_link objects that we'll need */ if (allocate_cgrp_cset_links(cgroup_root_count, &tmp_links) < 0) { @@ -1231,6 +1236,8 @@ static struct css_set *find_css_set(struct css_set *old_cset, INIT_HLIST_NODE(&cset->hlist); INIT_LIST_HEAD(&cset->cgrp_links); INIT_LIST_HEAD(&cset->mg_preload_node); + INIT_LIST_HEAD(&ext_cset->mg_src_preload_node); + INIT_LIST_HEAD(&ext_cset->mg_dst_preload_node); INIT_LIST_HEAD(&cset->mg_node); /* Copy the set of subsystem state objects generated in @@ -2578,22 +2585,28 @@ int cgroup_migrate_vet_dst(struct cgroup *dst_cgrp) */ void cgroup_migrate_finish(struct cgroup_mgctx *mgctx) { - LIST_HEAD(preloaded); - struct css_set *cset, *tmp_cset; + struct ext_css_set *cset, *tmp_cset; lockdep_assert_held(&cgroup_mutex); spin_lock_irq(&css_set_lock); - list_splice_tail_init(&mgctx->preloaded_src_csets, &preloaded); - list_splice_tail_init(&mgctx->preloaded_dst_csets, &preloaded); + list_for_each_entry_safe(cset, tmp_cset, &mgctx->preloaded_src_csets, + mg_src_preload_node) { + cset->cset.mg_src_cgrp = NULL; + cset->cset.mg_dst_cgrp = NULL; + cset->cset.mg_dst_cset = NULL; + list_del_init(&cset->mg_src_preload_node); + put_css_set_locked(&cset->cset); + } - list_for_each_entry_safe(cset, tmp_cset, &preloaded, mg_preload_node) { - cset->mg_src_cgrp = NULL; - cset->mg_dst_cgrp = NULL; - cset->mg_dst_cset = NULL; - list_del_init(&cset->mg_preload_node); - put_css_set_locked(cset); + list_for_each_entry_safe(cset, tmp_cset, &mgctx->preloaded_dst_csets, + mg_dst_preload_node) { + cset->cset.mg_src_cgrp = NULL; + cset->cset.mg_dst_cgrp = NULL; + cset->cset.mg_dst_cset = NULL; + list_del_init(&cset->mg_dst_preload_node); + put_css_set_locked(&cset->cset); } spin_unlock_irq(&css_set_lock); @@ -2620,6 +2633,7 @@ void cgroup_migrate_add_src(struct css_set *src_cset, struct cgroup_mgctx *mgctx) { struct cgroup *src_cgrp; + struct ext_css_set *ext_src_cset; lockdep_assert_held(&cgroup_mutex); lockdep_assert_held(&css_set_lock); @@ -2633,8 +2647,9 @@ void cgroup_migrate_add_src(struct css_set *src_cset, return; src_cgrp = cset_cgroup_from_root(src_cset, dst_cgrp->root); + ext_src_cset = container_of(src_cset, struct ext_css_set, cset); - if (!list_empty(&src_cset->mg_preload_node)) + if (!list_empty(&ext_src_cset->mg_src_preload_node)) return; WARN_ON(src_cset->mg_src_cgrp); @@ -2645,7 +2660,7 @@ void cgroup_migrate_add_src(struct css_set *src_cset, src_cset->mg_src_cgrp = src_cgrp; src_cset->mg_dst_cgrp = dst_cgrp; get_css_set(src_cset); - list_add_tail(&src_cset->mg_preload_node, &mgctx->preloaded_src_csets); + list_add_tail(&ext_src_cset->mg_src_preload_node, &mgctx->preloaded_src_csets); } /** @@ -2664,20 +2679,23 @@ void cgroup_migrate_add_src(struct css_set *src_cset, */ int cgroup_migrate_prepare_dst(struct cgroup_mgctx *mgctx) { - struct css_set *src_cset, *tmp_cset; + struct ext_css_set *ext_src_set, *tmp_cset; lockdep_assert_held(&cgroup_mutex); /* look up the dst cset for each src cset and link it to src */ - list_for_each_entry_safe(src_cset, tmp_cset, &mgctx->preloaded_src_csets, - mg_preload_node) { + list_for_each_entry_safe(ext_src_set, tmp_cset, &mgctx->preloaded_src_csets, + mg_src_preload_node) { + struct css_set *src_cset = &ext_src_set->cset; struct css_set *dst_cset; + struct ext_css_set *ext_dst_cset; struct cgroup_subsys *ss; int ssid; dst_cset = find_css_set(src_cset, src_cset->mg_dst_cgrp); if (!dst_cset) return -ENOMEM; + ext_dst_cset = container_of(dst_cset, struct ext_css_set, cset); WARN_ON_ONCE(src_cset->mg_dst_cset || dst_cset->mg_dst_cset); @@ -2689,7 +2707,7 @@ int cgroup_migrate_prepare_dst(struct cgroup_mgctx *mgctx) if (src_cset == dst_cset) { src_cset->mg_src_cgrp = NULL; src_cset->mg_dst_cgrp = NULL; - list_del_init(&src_cset->mg_preload_node); + list_del_init(&ext_src_set->mg_src_preload_node); put_css_set(src_cset); put_css_set(dst_cset); continue; @@ -2697,8 +2715,8 @@ int cgroup_migrate_prepare_dst(struct cgroup_mgctx *mgctx) src_cset->mg_dst_cset = dst_cset; - if (list_empty(&dst_cset->mg_preload_node)) - list_add_tail(&dst_cset->mg_preload_node, + if (list_empty(&ext_dst_cset->mg_dst_preload_node)) + list_add_tail(&ext_dst_cset->mg_dst_preload_node, &mgctx->preloaded_dst_csets); else put_css_set(dst_cset); @@ -2926,7 +2944,7 @@ static int cgroup_update_dfl_csses(struct cgroup *cgrp) DEFINE_CGROUP_MGCTX(mgctx); struct cgroup_subsys_state *d_css; struct cgroup *dsct; - struct css_set *src_cset; + struct ext_css_set *ext_src_set; int ret; lockdep_assert_held(&cgroup_mutex); @@ -2949,11 +2967,12 @@ static int cgroup_update_dfl_csses(struct cgroup *cgrp) goto out_finish; spin_lock_irq(&css_set_lock); - list_for_each_entry(src_cset, &mgctx.preloaded_src_csets, mg_preload_node) { + list_for_each_entry(ext_src_set, &mgctx.preloaded_src_csets, + mg_src_preload_node) { struct task_struct *task, *ntask; /* all tasks in src_csets need to be migrated */ - list_for_each_entry_safe(task, ntask, &src_cset->tasks, cg_list) + list_for_each_entry_safe(task, ntask, &ext_src_set->cset.tasks, cg_list) cgroup_migrate_add_task(task, &mgctx); } spin_unlock_irq(&css_set_lock); diff --git a/kernel/fork.c b/kernel/fork.c index 3b281326c0e1..58409b7178c2 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1150,8 +1150,10 @@ void mmput(struct mm_struct *mm) { might_sleep(); - if (atomic_dec_and_test(&mm->mm_users)) + if (atomic_dec_and_test(&mm->mm_users)) { + trace_android_vh_mmput(NULL); __mmput(mm); + } } EXPORT_SYMBOL_GPL(mmput); diff --git a/kernel/pid.c b/kernel/pid.c index 48babb1dd3e1..468d04810b40 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -45,6 +45,9 @@ #include #include +#undef CREATE_TRACE_POINTS +#include + struct pid init_struct_pid = { .count = REFCOUNT_INIT(1), .tasks = { @@ -602,6 +605,7 @@ SYSCALL_DEFINE2(pidfd_open, pid_t, pid, unsigned int, flags) else fd = -EINVAL; + trace_android_vh_pidfd_open(p); put_pid(p); return fd; } diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 708151220ea3..bae53499a9d7 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -4788,7 +4788,7 @@ static int tg_unthrottle_up(struct task_group *tg, void *data) cfs_rq->throttle_count--; if (!cfs_rq->throttle_count) { - cfs_rq->throttled_clock_pelt_time += rq_clock_pelt(rq) - + cfs_rq->throttled_clock_pelt_time += rq_clock_task_mult(rq) - cfs_rq->throttled_clock_pelt; /* Add cfs_rq with already running entity in the list */ @@ -4806,7 +4806,7 @@ static int tg_throttle_down(struct task_group *tg, void *data) /* group is entering throttled state, stop time */ if (!cfs_rq->throttle_count) { - cfs_rq->throttled_clock_pelt = rq_clock_pelt(rq); + cfs_rq->throttled_clock_pelt = rq_clock_task_mult(rq); list_del_leaf_cfs_rq(cfs_rq); } cfs_rq->throttle_count++; @@ -5224,7 +5224,7 @@ static void sync_throttle(struct task_group *tg, int cpu) pcfs_rq = tg->parent->cfs_rq[cpu]; cfs_rq->throttle_count = pcfs_rq->throttle_count; - cfs_rq->throttled_clock_pelt = rq_clock_pelt(cpu_rq(cpu)); + cfs_rq->throttled_clock_pelt = rq_clock_task_mult(cpu_rq(cpu)); } /* conditionally throttle active cfs_rq's from put_prev_entity() */ diff --git a/kernel/sched/pelt.c b/kernel/sched/pelt.c index bbb0de2219f9..15a237ab2d0c 100644 --- a/kernel/sched/pelt.c +++ b/kernel/sched/pelt.c @@ -531,3 +531,50 @@ int update_irq_load_avg(struct rq *rq, u64 running) return ret; } #endif + +#include +DEFINE_PER_CPU(u64, clock_task_mult); + +unsigned int sysctl_sched_pelt_multiplier = 1; +__read_mostly unsigned int sched_pelt_lshift; + +int sched_pelt_multiplier(struct ctl_table *table, int write, void *buffer, + size_t *lenp, loff_t *ppos) +{ + static DEFINE_MUTEX(mutex); + unsigned int old; + int ret; + + mutex_lock(&mutex); + + old = sysctl_sched_pelt_multiplier; + ret = proc_dointvec(table, write, buffer, lenp, ppos); + if (ret) + goto undo; + if (!write) + goto done; + + trace_android_vh_sched_pelt_multiplier(old, sysctl_sched_pelt_multiplier, &ret); + if (ret) + goto undo; + + switch (sysctl_sched_pelt_multiplier) { + case 1: + fallthrough; + case 2: + fallthrough; + case 4: + WRITE_ONCE(sched_pelt_lshift, + sysctl_sched_pelt_multiplier >> 1); + goto done; + default: + ret = -EINVAL; + } + +undo: + sysctl_sched_pelt_multiplier = old; +done: + mutex_unlock(&mutex); + + return ret; +} diff --git a/kernel/sched/pelt.h b/kernel/sched/pelt.h index 89150ced09cf..0245e3e21f93 100644 --- a/kernel/sched/pelt.h +++ b/kernel/sched/pelt.h @@ -61,6 +61,8 @@ static inline void cfs_se_util_change(struct sched_avg *avg) WRITE_ONCE(avg->util_est.enqueued, enqueued); } +extern unsigned int sched_pelt_lshift; + /* * The clock_pelt scales the time to reflect the effective amount of * computation done during the running delta time but then sync back to @@ -75,9 +77,13 @@ static inline void cfs_se_util_change(struct sched_avg *avg) */ static inline void update_rq_clock_pelt(struct rq *rq, s64 delta) { + delta <<= READ_ONCE(sched_pelt_lshift); + + per_cpu(clock_task_mult, rq->cpu) += delta; + if (unlikely(is_idle_task(rq->curr))) { /* The rq is idle, we can sync to clock_task */ - rq->clock_pelt = rq_clock_task(rq); + rq->clock_pelt = rq_clock_task_mult(rq); return; } @@ -129,7 +135,8 @@ static inline void update_idle_rq_clock_pelt(struct rq *rq) * rq's clock_task. */ if (util_sum >= divider) - rq->lost_idle_time += rq_clock_task(rq) - rq->clock_pelt; + rq->lost_idle_time += rq_clock_task_mult(rq) - + rq->clock_pelt; } static inline u64 rq_clock_pelt(struct rq *rq) diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 98793aef4c97..938e0091fc93 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1193,6 +1193,16 @@ static inline u64 rq_clock_task(struct rq *rq) return rq->clock_task; } +DECLARE_PER_CPU(u64, clock_task_mult); + +static inline u64 rq_clock_task_mult(struct rq *rq) +{ + lockdep_assert_held(&rq->lock); + assert_clock_updated(rq); + + return per_cpu(clock_task_mult, cpu_of(rq)); +} + /** * By default the decay is the default pelt decay period. * The decay shift can change the decay period in diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 93bac9849cdb..759215b95545 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1832,6 +1832,15 @@ static struct ctl_table kern_table[] = { .mode = 0644, .proc_handler = sched_rr_handler, }, +#ifdef CONFIG_SMP + { + .procname = "sched_pelt_multiplier", + .data = &sysctl_sched_pelt_multiplier, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = sched_pelt_multiplier, + }, +#endif #ifdef CONFIG_UCLAMP_TASK { .procname = "sched_util_clamp_min", diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 1eea5787fd63..c24716571a93 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -33,7 +33,7 @@ #include #include #include - +#include #include #include #include "internal.h" @@ -2033,6 +2033,7 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd, bool young, write, soft_dirty, pmd_migration = false, uffd_wp = false; unsigned long addr; int i; + bool success = false; VM_BUG_ON(haddr & ~HPAGE_PMD_MASK); VM_BUG_ON_VMA(vma->vm_start > haddr, vma); @@ -2164,8 +2165,12 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd, pte = pte_offset_map(&_pmd, addr); BUG_ON(!pte_none(*pte)); set_pte_at(mm, addr, pte, entry); - if (!pmd_migration) - atomic_inc(&page[i]._mapcount); + if (!pmd_migration) { + trace_android_vh_update_page_mapcount(&page[i], true, + false, NULL, &success); + if (!success) + atomic_inc(&page[i]._mapcount); + } pte_unmap(pte); } @@ -2176,8 +2181,12 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd, */ if (compound_mapcount(page) > 1 && !TestSetPageDoubleMap(page)) { - for (i = 0; i < HPAGE_PMD_NR; i++) - atomic_inc(&page[i]._mapcount); + for (i = 0; i < HPAGE_PMD_NR; i++) { + trace_android_vh_update_page_mapcount(&page[i], true, + false, NULL, &success); + if (!success) + atomic_inc(&page[i]._mapcount); + } } lock_page_memcg(page); @@ -2186,8 +2195,12 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd, __dec_lruvec_page_state(page, NR_ANON_THPS); if (TestClearPageDoubleMap(page)) { /* No need in mapcount reference anymore */ - for (i = 0; i < HPAGE_PMD_NR; i++) - atomic_dec(&page[i]._mapcount); + for (i = 0; i < HPAGE_PMD_NR; i++) { + trace_android_vh_update_page_mapcount(&page[i], + false, false, NULL, &success); + if (!success) + atomic_dec(&page[i]._mapcount); + } } } unlock_page_memcg(page); diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 008e72c2b980..f585eef0f4fe 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -1372,6 +1372,38 @@ out: return lruvec; } +struct lruvec *page_to_lruvec(struct page *page, pg_data_t *pgdat) +{ + struct lruvec *lruvec; + + lruvec = mem_cgroup_page_lruvec(page, pgdat); + + return lruvec; +} +EXPORT_SYMBOL_GPL(page_to_lruvec); + +void do_traversal_all_lruvec(void) +{ + pg_data_t *pgdat; + + for_each_online_pgdat(pgdat) { + struct mem_cgroup *memcg = NULL; + + spin_lock_irq(&pgdat->lru_lock); + memcg = mem_cgroup_iter(NULL, NULL, NULL); + do { + struct lruvec *lruvec = mem_cgroup_lruvec(memcg, pgdat); + + trace_android_vh_do_traversal_lruvec(lruvec); + + memcg = mem_cgroup_iter(NULL, memcg, NULL); + } while (memcg); + + spin_unlock_irq(&pgdat->lru_lock); + } +} +EXPORT_SYMBOL_GPL(do_traversal_all_lruvec); + /** * mem_cgroup_update_lru_size - account for adding or removing an lru page * @lruvec: mem_cgroup per zone lru vector diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 7330061a0501..da1acff64e87 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -4794,7 +4794,9 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order, int no_progress_loops; unsigned int cpuset_mems_cookie; int reserve_flags; + unsigned long vh_record; + trace_android_vh_alloc_pages_slowpath_begin(gfp_mask, order, &vh_record); /* * We also sanity check to catch abuse of atomic reserves being used by * callers that are not in atomic context. @@ -5036,6 +5038,7 @@ fail: warn_alloc(gfp_mask, ac->nodemask, "page allocation failure: order:%u", order); got_pg: + trace_android_vh_alloc_pages_slowpath_end(gfp_mask, order, vh_record); return page; } @@ -5647,6 +5650,7 @@ void show_free_areas(unsigned int filter, nodemask_t *nodemask) free_pcp, global_zone_page_state(NR_FREE_CMA_PAGES)); + trace_android_vh_show_mapcount_pages(NULL); for_each_online_pgdat(pgdat) { if (show_mem_node_skip(filter, pgdat->node_id, nodemask)) continue; diff --git a/mm/rmap.c b/mm/rmap.c index e526fbc7826e..2e62c1aa5139 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -525,6 +525,7 @@ struct anon_vma *page_lock_anon_vma_read(struct page *page) struct anon_vma *anon_vma = NULL; struct anon_vma *root_anon_vma; unsigned long anon_mapping; + bool success = false; rcu_read_lock(); anon_mapping = (unsigned long)READ_ONCE(page->mapping); @@ -547,7 +548,11 @@ struct anon_vma *page_lock_anon_vma_read(struct page *page) } goto out; } - + trace_android_vh_do_page_trylock(page, NULL, NULL, &success); + if (success) { + anon_vma = NULL; + goto out; + } /* trylock failed, we got to sleep */ if (!atomic_inc_not_zero(&anon_vma->refcount)) { anon_vma = NULL; @@ -1113,6 +1118,7 @@ void do_page_add_anon_rmap(struct page *page, { bool compound = flags & RMAP_COMPOUND; bool first; + bool success = false; if (unlikely(PageKsm(page))) lock_page_memcg(page); @@ -1126,7 +1132,10 @@ void do_page_add_anon_rmap(struct page *page, mapcount = compound_mapcount_ptr(page); first = atomic_inc_and_test(mapcount); } else { - first = atomic_inc_and_test(&page->_mapcount); + trace_android_vh_update_page_mapcount(page, true, compound, + &first, &success); + if (!success) + first = atomic_inc_and_test(&page->_mapcount); } if (first) { @@ -1200,13 +1209,22 @@ void __page_add_new_anon_rmap(struct page *page, void page_add_file_rmap(struct page *page, bool compound) { int i, nr = 1; + bool first_mapping; + bool success = false; VM_BUG_ON_PAGE(compound && !PageTransHuge(page), page); lock_page_memcg(page); if (compound && PageTransHuge(page)) { for (i = 0, nr = 0; i < thp_nr_pages(page); i++) { - if (atomic_inc_and_test(&page[i]._mapcount)) - nr++; + trace_android_vh_update_page_mapcount(&page[i], true, + compound, &first_mapping, &success); + if ((success)) { + if (first_mapping) + nr++; + } else { + if (atomic_inc_and_test(&page[i]._mapcount)) + nr++; + } } if (!atomic_inc_and_test(compound_mapcount_ptr(page))) goto out; @@ -1222,8 +1240,15 @@ void page_add_file_rmap(struct page *page, bool compound) if (PageMlocked(page)) clear_page_mlock(compound_head(page)); } - if (!atomic_inc_and_test(&page->_mapcount)) - goto out; + trace_android_vh_update_page_mapcount(page, true, + compound, &first_mapping, &success); + if (success) { + if (!first_mapping) + goto out; + } else { + if (!atomic_inc_and_test(&page->_mapcount)) + goto out; + } } __mod_lruvec_page_state(page, NR_FILE_MAPPED, nr); out: @@ -1233,6 +1258,8 @@ out: static void page_remove_file_rmap(struct page *page, bool compound) { int i, nr = 1; + bool first_mapping; + bool success = false; VM_BUG_ON_PAGE(compound && !PageHead(page), page); @@ -1246,8 +1273,15 @@ static void page_remove_file_rmap(struct page *page, bool compound) /* page still mapped by someone else? */ if (compound && PageTransHuge(page)) { for (i = 0, nr = 0; i < thp_nr_pages(page); i++) { - if (atomic_add_negative(-1, &page[i]._mapcount)) - nr++; + trace_android_vh_update_page_mapcount(&page[i], false, + compound, &first_mapping, &success); + if (success) { + if (first_mapping) + nr++; + } else { + if (atomic_add_negative(-1, &page[i]._mapcount)) + nr++; + } } if (!atomic_add_negative(-1, compound_mapcount_ptr(page))) return; @@ -1256,8 +1290,15 @@ static void page_remove_file_rmap(struct page *page, bool compound) else __dec_node_page_state(page, NR_FILE_PMDMAPPED); } else { - if (!atomic_add_negative(-1, &page->_mapcount)) - return; + trace_android_vh_update_page_mapcount(page, false, + compound, &first_mapping, &success); + if (success) { + if (!first_mapping) + return; + } else { + if (!atomic_add_negative(-1, &page->_mapcount)) + return; + } } /* @@ -1274,6 +1315,8 @@ static void page_remove_file_rmap(struct page *page, bool compound) static void page_remove_anon_compound_rmap(struct page *page) { int i, nr; + bool first_mapping; + bool success = false; if (!atomic_add_negative(-1, compound_mapcount_ptr(page))) return; @@ -1293,8 +1336,15 @@ static void page_remove_anon_compound_rmap(struct page *page) * them are still mapped. */ for (i = 0, nr = 0; i < thp_nr_pages(page); i++) { - if (atomic_add_negative(-1, &page[i]._mapcount)) - nr++; + trace_android_vh_update_page_mapcount(&page[i], false, + false, &first_mapping, &success); + if (success) { + if (first_mapping) + nr++; + } else { + if (atomic_add_negative(-1, &page[i]._mapcount)) + nr++; + } } /* @@ -1324,6 +1374,8 @@ static void page_remove_anon_compound_rmap(struct page *page) */ void page_remove_rmap(struct page *page, bool compound) { + bool first_mapping; + bool success = false; lock_page_memcg(page); if (!PageAnon(page)) { @@ -1336,10 +1388,16 @@ void page_remove_rmap(struct page *page, bool compound) goto out; } - /* page still mapped by someone else? */ - if (!atomic_add_negative(-1, &page->_mapcount)) - goto out; - + trace_android_vh_update_page_mapcount(page, false, + compound, &first_mapping, &success); + if (success) { + if (!first_mapping) + goto out; + } else { + /* page still mapped by someone else? */ + if (!atomic_add_negative(-1, &page->_mapcount)) + goto out; + } /* * We use the irq-unsafe __{inc|mod}_zone_page_stat because * these counters are not modified in interrupt context, and @@ -1928,6 +1986,7 @@ static void rmap_walk_file(struct page *page, struct rmap_walk_control *rwc, struct address_space *mapping = page_mapping(page); pgoff_t pgoff_start, pgoff_end; struct vm_area_struct *vma; + bool got_lock = false, success = false; /* * The page lock not only makes sure that page->mapping cannot @@ -1942,8 +2001,16 @@ static void rmap_walk_file(struct page *page, struct rmap_walk_control *rwc, pgoff_start = page_to_pgoff(page); pgoff_end = pgoff_start + thp_nr_pages(page) - 1; - if (!locked) - i_mmap_lock_read(mapping); + if (!locked) { + trace_android_vh_do_page_trylock(page, + &mapping->i_mmap_rwsem, &got_lock, &success); + if (success) { + if (!got_lock) + return; + } else { + i_mmap_lock_read(mapping); + } + } vma_interval_tree_foreach(vma, &mapping->i_mmap, pgoff_start, pgoff_end) { unsigned long address = vma_address(page, vma); diff --git a/mm/shmem.c b/mm/shmem.c index 8fb9d2ddec70..768c91896036 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -46,6 +46,7 @@ #undef CREATE_TRACE_POINTS #include +#include static struct vfsmount *shm_mnt; @@ -1430,6 +1431,7 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc) SetPageUptodate(page); } + trace_android_vh_set_shmem_page_flag(page); swap = get_swap_page(page); if (!swap.val) goto redirty; @@ -4311,7 +4313,6 @@ int reclaim_shmem_address_space(struct address_space *mapping) pgoff_t start = 0; struct page *page; LIST_HEAD(page_list); - int reclaimed; XA_STATE(xas, &mapping->i_pages, start); if (!shmem_mapping(mapping)) @@ -4329,8 +4330,6 @@ int reclaim_shmem_address_space(struct address_space *mapping) continue; list_add(&page->lru, &page_list); - inc_node_page_state(page, NR_ISOLATED_ANON + - page_is_file_lru(page)); if (need_resched()) { xas_pause(&xas); @@ -4338,9 +4337,8 @@ int reclaim_shmem_address_space(struct address_space *mapping) } } rcu_read_unlock(); - reclaimed = reclaim_pages_from_list(&page_list); - return reclaimed; + return reclaim_pages(&page_list); #else return 0; #endif diff --git a/mm/swap.c b/mm/swap.c index abf445bd7721..16b2bc48211e 100644 --- a/mm/swap.c +++ b/mm/swap.c @@ -437,6 +437,7 @@ void mark_page_accessed(struct page *page) { page = compound_head(page); + trace_android_vh_mark_page_accessed(page); if (!PageReferenced(page)) { SetPageReferenced(page); } else if (PageUnevictable(page)) { diff --git a/mm/vmalloc.c b/mm/vmalloc.c index d5615977e7f3..817a472ee30f 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -2170,6 +2170,7 @@ struct vm_struct *remove_vm_area(const void *addr) if (va && va->vm) { struct vm_struct *vm = va->vm; + trace_android_vh_remove_vmalloc_stack(vm); va->vm = NULL; spin_unlock(&vmap_area_lock); diff --git a/mm/vmscan.c b/mm/vmscan.c index 24b0c38c2c5c..0f82957c4de7 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -1020,11 +1020,20 @@ static enum page_references page_check_references(struct page *page, { int referenced_ptes, referenced_page; unsigned long vm_flags; + bool should_protect = false; + bool trylock_fail = false; + trace_android_vh_page_should_be_protected(page, &should_protect); + if (unlikely(should_protect)) + return PAGEREF_ACTIVATE; + + trace_android_vh_page_trylock_set(page); referenced_ptes = page_referenced(page, 1, sc->target_mem_cgroup, &vm_flags); referenced_page = TestClearPageReferenced(page); - + trace_android_vh_page_trylock_get_result(page, &trylock_fail); + if (trylock_fail) + return PAGEREF_KEEP; /* * Mlock lost the isolation race with us. Let try_to_unmap() * move the page to the unevictable list. @@ -1336,6 +1345,7 @@ static unsigned int shrink_page_list(struct list_head *page_list, if (unlikely(PageTransHuge(page))) flags |= TTU_SPLIT_HUGE_PMD; + trace_android_vh_page_trylock_set(page); if (!try_to_unmap(page, flags)) { stat->nr_unmap_fail += nr_pages; if (!was_swapbacked && PageSwapBacked(page)) @@ -1446,6 +1456,7 @@ static unsigned int shrink_page_list(struct list_head *page_list, * increment nr_reclaimed here (and * leave it off the LRU). */ + trace_android_vh_page_trylock_clear(page); nr_reclaimed++; continue; } @@ -1481,8 +1492,10 @@ free_it: */ if (unlikely(PageTransHuge(page))) destroy_compound_page(page); - else + else { + trace_android_vh_page_trylock_clear(page); list_add(&page->lru, &free_pages); + } continue; activate_locked_split: @@ -1564,36 +1577,6 @@ unsigned int reclaim_clean_pages_from_list(struct zone *zone, return nr_reclaimed; } -int reclaim_pages_from_list(struct list_head *page_list) -{ - struct scan_control sc = { - .gfp_mask = GFP_KERNEL, - .priority = DEF_PRIORITY, - .may_writepage = 1, - .may_unmap = 1, - .may_swap = 1, - }; - unsigned long nr_reclaimed; - struct reclaim_stat dummy_stat; - struct page *page; - - list_for_each_entry(page, page_list, lru) - ClearPageActive(page); - - nr_reclaimed = shrink_page_list(page_list, NULL, &sc, - &dummy_stat, false); - while (!list_empty(page_list)) { - - page = lru_to_page(page_list); - list_del(&page->lru); - dec_node_page_state(page, NR_ISOLATED_ANON + - page_is_file_lru(page)); - putback_lru_page(page); - } - - return nr_reclaimed; -} - /* * Attempt to remove the specified page from its LRU. Only take this page * if it is of the appropriate PageActive status. Pages which are being @@ -1757,6 +1740,7 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan, case 0: nr_taken += nr_pages; nr_zone_taken[page_zonenum(page)] += nr_pages; + trace_android_vh_del_page_from_lrulist(page, false, lru); list_move(&page->lru, dst); break; @@ -1931,6 +1915,7 @@ static unsigned noinline_for_stack move_pages_to_lru(struct lruvec *lruvec, nr_pages = thp_nr_pages(page); update_lru_size(lruvec, lru, page_zonenum(page), nr_pages); list_move(&page->lru, &lruvec->lists[lru]); + trace_android_vh_add_page_to_lrulist(page, false, lru); if (put_page_testzero(page)) { __ClearPageLRU(page); @@ -2022,6 +2007,7 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec, return 0; nr_reclaimed = shrink_page_list(&page_list, pgdat, sc, &stat, false); + trace_android_vh_handle_failed_page_trylock(&page_list); spin_lock_irq(&pgdat->lru_lock); @@ -2034,7 +2020,6 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec, __count_vm_events(item, nr_reclaimed); __count_memcg_events(lruvec_memcg(lruvec), item, nr_reclaimed); __count_vm_events(PGSTEAL_ANON + file, nr_reclaimed); - spin_unlock_irq(&pgdat->lru_lock); mem_cgroup_uncharge_list(&page_list); @@ -2085,6 +2070,7 @@ static void shrink_active_list(unsigned long nr_to_scan, int file = is_file_lru(lru); struct pglist_data *pgdat = lruvec_pgdat(lruvec); bool bypass = false; + bool should_protect = false; lru_add_drain(); @@ -2119,10 +2105,17 @@ static void shrink_active_list(unsigned long nr_to_scan, } } + trace_android_vh_page_should_be_protected(page, &should_protect); + if (unlikely(should_protect)) { + nr_rotated += thp_nr_pages(page); + list_add(&page->lru, &l_active); + continue; + } + trace_android_vh_page_referenced_check_bypass(page, nr_to_scan, lru, &bypass); if (bypass) goto skip_page_referenced; - + trace_android_vh_page_trylock_set(page); if (page_referenced(page, 0, sc->target_mem_cgroup, &vm_flags)) { /* @@ -2135,11 +2128,13 @@ static void shrink_active_list(unsigned long nr_to_scan, * so we ignore them here. */ if ((vm_flags & VM_EXEC) && page_is_file_lru(page)) { + trace_android_vh_page_trylock_clear(page); nr_rotated += thp_nr_pages(page); list_add(&page->lru, &l_active); continue; } } + trace_android_vh_page_trylock_clear(page); skip_page_referenced: ClearPageActive(page); /* we are de-activating */ SetPageWorkingset(page); @@ -2221,6 +2216,7 @@ unsigned long reclaim_pages(struct list_head *page_list) return nr_reclaimed; } +EXPORT_SYMBOL_GPL(reclaim_pages); static unsigned long shrink_list(enum lru_list lru, unsigned long nr_to_scan, struct lruvec *lruvec, struct scan_control *sc) diff --git a/sound/core/pcm_iec958.c b/sound/core/pcm_iec958.c index f9a211cc1f2c..7a1b816f67cc 100644 --- a/sound/core/pcm_iec958.c +++ b/sound/core/pcm_iec958.c @@ -9,41 +9,85 @@ #include #include -static int create_iec958_consumer(uint rate, uint sample_width, - u8 *cs, size_t len) +/** + * snd_pcm_create_iec958_consumer_default - create default consumer format IEC958 channel status + * @cs: channel status buffer, at least four bytes + * @len: length of channel status buffer + * + * Create the consumer format channel status data in @cs of maximum size + * @len. When relevant, the configuration-dependant bits will be set as + * unspecified. + * + * Drivers should then call einter snd_pcm_fill_iec958_consumer() or + * snd_pcm_fill_iec958_consumer_hw_params() to replace these unspecified + * bits by their actual values. + * + * Drivers may wish to tweak the contents of the buffer after creation. + * + * Returns: length of buffer, or negative error code if something failed. + */ +int snd_pcm_create_iec958_consumer_default(u8 *cs, size_t len) { - unsigned int fs, ws; - if (len < 4) return -EINVAL; - switch (rate) { - case 32000: - fs = IEC958_AES3_CON_FS_32000; - break; - case 44100: - fs = IEC958_AES3_CON_FS_44100; - break; - case 48000: - fs = IEC958_AES3_CON_FS_48000; - break; - case 88200: - fs = IEC958_AES3_CON_FS_88200; - break; - case 96000: - fs = IEC958_AES3_CON_FS_96000; - break; - case 176400: - fs = IEC958_AES3_CON_FS_176400; - break; - case 192000: - fs = IEC958_AES3_CON_FS_192000; - break; - default: + memset(cs, 0, len); + + cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE; + cs[1] = IEC958_AES1_CON_GENERAL; + cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC | IEC958_AES2_CON_CHANNEL_UNSPEC; + cs[3] = IEC958_AES3_CON_CLOCK_1000PPM | IEC958_AES3_CON_FS_NOTID; + + if (len > 4) + cs[4] = IEC958_AES4_CON_WORDLEN_NOTID; + + return len; +} +EXPORT_SYMBOL_GPL(snd_pcm_create_iec958_consumer_default); + +static int fill_iec958_consumer(uint rate, uint sample_width, + u8 *cs, size_t len) +{ + if (len < 4) return -EINVAL; + + if ((cs[3] & IEC958_AES3_CON_FS) == IEC958_AES3_CON_FS_NOTID) { + unsigned int fs; + + switch (rate) { + case 32000: + fs = IEC958_AES3_CON_FS_32000; + break; + case 44100: + fs = IEC958_AES3_CON_FS_44100; + break; + case 48000: + fs = IEC958_AES3_CON_FS_48000; + break; + case 88200: + fs = IEC958_AES3_CON_FS_88200; + break; + case 96000: + fs = IEC958_AES3_CON_FS_96000; + break; + case 176400: + fs = IEC958_AES3_CON_FS_176400; + break; + case 192000: + fs = IEC958_AES3_CON_FS_192000; + break; + default: + return -EINVAL; + } + + cs[3] &= ~IEC958_AES3_CON_FS; + cs[3] |= fs; } - if (len > 4) { + if (len > 4 && + (cs[4] & IEC958_AES4_CON_WORDLEN) == IEC958_AES4_CON_WORDLEN_NOTID) { + unsigned int ws; + switch (sample_width) { case 16: ws = IEC958_AES4_CON_WORDLEN_20_16; @@ -64,21 +108,58 @@ static int create_iec958_consumer(uint rate, uint sample_width, default: return -EINVAL; } + + cs[4] &= ~IEC958_AES4_CON_WORDLEN; + cs[4] |= ws; } - memset(cs, 0, len); - - cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE; - cs[1] = IEC958_AES1_CON_GENERAL; - cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC | IEC958_AES2_CON_CHANNEL_UNSPEC; - cs[3] = IEC958_AES3_CON_CLOCK_1000PPM | fs; - - if (len > 4) - cs[4] = ws; - return len; } +/** + * snd_pcm_fill_iec958_consumer - Fill consumer format IEC958 channel status + * @runtime: pcm runtime structure with ->rate filled in + * @cs: channel status buffer, at least four bytes + * @len: length of channel status buffer + * + * Fill the unspecified bits in an IEC958 status bits array using the + * parameters of the PCM runtime @runtime. + * + * Drivers may wish to tweak the contents of the buffer after its been + * filled. + * + * Returns: length of buffer, or negative error code if something failed. + */ +int snd_pcm_fill_iec958_consumer(struct snd_pcm_runtime *runtime, + u8 *cs, size_t len) +{ + return fill_iec958_consumer(runtime->rate, + snd_pcm_format_width(runtime->format), + cs, len); +} +EXPORT_SYMBOL_GPL(snd_pcm_fill_iec958_consumer); + +/** + * snd_pcm_fill_iec958_consumer_hw_params - Fill consumer format IEC958 channel status + * @params: the hw_params instance for extracting rate and sample format + * @cs: channel status buffer, at least four bytes + * @len: length of channel status buffer + * + * Fill the unspecified bits in an IEC958 status bits array using the + * parameters of the PCM hardware parameters @params. + * + * Drivers may wish to tweak the contents of the buffer after its been + * filled.. + * + * Returns: length of buffer, or negative error code if something failed. + */ +int snd_pcm_fill_iec958_consumer_hw_params(struct snd_pcm_hw_params *params, + u8 *cs, size_t len) +{ + return fill_iec958_consumer(params_rate(params), params_width(params), cs, len); +} +EXPORT_SYMBOL_GPL(snd_pcm_fill_iec958_consumer_hw_params); + /** * snd_pcm_create_iec958_consumer - create consumer format IEC958 channel status * @runtime: pcm runtime structure with ->rate filled in @@ -95,9 +176,13 @@ static int create_iec958_consumer(uint rate, uint sample_width, int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs, size_t len) { - return create_iec958_consumer(runtime->rate, - snd_pcm_format_width(runtime->format), - cs, len); + int ret; + + ret = snd_pcm_create_iec958_consumer_default(cs, len); + if (ret < 0) + return ret; + + return snd_pcm_fill_iec958_consumer(runtime, cs, len); } EXPORT_SYMBOL(snd_pcm_create_iec958_consumer); @@ -117,7 +202,12 @@ EXPORT_SYMBOL(snd_pcm_create_iec958_consumer); int snd_pcm_create_iec958_consumer_hw_params(struct snd_pcm_hw_params *params, u8 *cs, size_t len) { - return create_iec958_consumer(params_rate(params), params_width(params), - cs, len); + int ret; + + ret = snd_pcm_create_iec958_consumer_default(cs, len); + if (ret < 0) + return ret; + + return fill_iec958_consumer(params_rate(params), params_width(params), cs, len); } EXPORT_SYMBOL(snd_pcm_create_iec958_consumer_hw_params); diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index 403d4c6a49a8..d0fb04ae372c 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -22,7 +22,6 @@ struct hdmi_codec_channel_map_table { unsigned char map; /* ALSA API channel map position */ - unsigned long spk_mask; /* speaker position bit mask */ }; /* @@ -278,10 +277,12 @@ struct hdmi_codec_priv { bool busy; struct snd_soc_jack *jack; unsigned int jack_status; + u8 iec_status[5]; }; static const struct snd_soc_dapm_widget hdmi_widgets[] = { SND_SOC_DAPM_OUTPUT("TX"), + SND_SOC_DAPM_OUTPUT("RX"), }; enum { @@ -385,10 +386,52 @@ static int hdmi_codec_chmap_ctl_get(struct snd_kcontrol *kcontrol, return 0; } +static int hdmi_codec_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 hdmi_codec_iec958_default_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct hdmi_codec_priv *hcp = snd_soc_component_get_drvdata(component); + + memcpy(ucontrol->value.iec958.status, hcp->iec_status, + sizeof(hcp->iec_status)); + + return 0; +} + +static int hdmi_codec_iec958_default_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct hdmi_codec_priv *hcp = snd_soc_component_get_drvdata(component); + + memcpy(hcp->iec_status, ucontrol->value.iec958.status, + sizeof(hcp->iec_status)); + + return 0; +} + +static int hdmi_codec_iec958_mask_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + memset(ucontrol->value.iec958.status, 0xff, + sizeof_field(struct hdmi_codec_priv, iec_status)); + + return 0; +} + static int hdmi_codec_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; int ret = 0; mutex_lock(&hcp->lock); @@ -404,7 +447,7 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream, goto err; } - if (hcp->hcd.ops->get_eld) { + if (tx && hcp->hcd.ops->get_eld) { ret = hcp->hcd.ops->get_eld(dai->dev->parent, hcp->hcd.data, hcp->eld, sizeof(hcp->eld)); if (ret) @@ -438,6 +481,42 @@ static void hdmi_codec_shutdown(struct snd_pcm_substream *substream, mutex_unlock(&hcp->lock); } +static int hdmi_codec_fill_codec_params(struct snd_soc_dai *dai, + unsigned int sample_width, + unsigned int sample_rate, + unsigned int channels, + struct hdmi_codec_params *hp) +{ + struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); + int idx; + + /* Select a channel allocation that matches with ELD and pcm channels */ + idx = hdmi_codec_get_ch_alloc_table_idx(hcp, channels); + if (idx < 0) { + dev_err(dai->dev, "Not able to map channels to speakers (%d)\n", + idx); + hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; + return idx; + } + + memset(hp, 0, sizeof(*hp)); + + hdmi_audio_infoframe_init(&hp->cea); + hp->cea.channels = channels; + hp->cea.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM; + hp->cea.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM; + hp->cea.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM; + hp->cea.channel_allocation = hdmi_codec_channel_alloc[idx].ca_id; + + hp->sample_width = sample_width; + hp->sample_rate = sample_rate; + hp->channels = channels; + + hcp->chmap_idx = hdmi_codec_channel_alloc[idx].ca_id; + + return 0; +} + static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -452,45 +531,73 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, .dig_subframe = { 0 }, } }; - int ret, idx; + int ret; + + if (!hcp->hcd.ops->hw_params) + return 0; dev_dbg(dai->dev, "%s() width %d rate %d channels %d\n", __func__, params_width(params), params_rate(params), params_channels(params)); - ret = snd_pcm_create_iec958_consumer_hw_params(params, hp.iec.status, - sizeof(hp.iec.status)); + ret = hdmi_codec_fill_codec_params(dai, + params_width(params), + params_rate(params), + params_channels(params), + &hp); + if (ret < 0) + return ret; + + memcpy(hp.iec.status, hcp->iec_status, sizeof(hp.iec.status)); + ret = snd_pcm_fill_iec958_consumer_hw_params(params, hp.iec.status, + sizeof(hp.iec.status)); if (ret < 0) { dev_err(dai->dev, "Creating IEC958 channel status failed %d\n", ret); return ret; } - hdmi_audio_infoframe_init(&hp.cea); - hp.cea.channels = params_channels(params); - hp.cea.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM; - hp.cea.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM; - hp.cea.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM; - - /* Select a channel allocation that matches with ELD and pcm channels */ - idx = hdmi_codec_get_ch_alloc_table_idx(hcp, hp.cea.channels); - if (idx < 0) { - dev_err(dai->dev, "Not able to map channels to speakers (%d)\n", - idx); - hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; - return idx; - } - hp.cea.channel_allocation = hdmi_codec_channel_alloc[idx].ca_id; - hcp->chmap_idx = hdmi_codec_channel_alloc[idx].ca_id; - - hp.sample_width = params_width(params); - hp.sample_rate = params_rate(params); - hp.channels = params_channels(params); - + cf->bit_fmt = params_format(params); return hcp->hcd.ops->hw_params(dai->dev->parent, hcp->hcd.data, cf, &hp); } +static int hdmi_codec_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); + struct hdmi_codec_daifmt *cf = dai->playback_dma_data; + struct snd_pcm_runtime *runtime = substream->runtime; + unsigned int channels = runtime->channels; + unsigned int width = snd_pcm_format_width(runtime->format); + unsigned int rate = runtime->rate; + struct hdmi_codec_params hp; + int ret; + + if (!hcp->hcd.ops->prepare) + return 0; + + dev_dbg(dai->dev, "%s() width %d rate %d channels %d\n", __func__, + width, rate, channels); + + ret = hdmi_codec_fill_codec_params(dai, width, rate, channels, &hp); + if (ret < 0) + return ret; + + memcpy(hp.iec.status, hcp->iec_status, sizeof(hp.iec.status)); + ret = snd_pcm_fill_iec958_consumer(runtime, hp.iec.status, + sizeof(hp.iec.status)); + if (ret < 0) { + dev_err(dai->dev, "Creating IEC958 channel status failed %d\n", + ret); + return ret; + } + + cf->bit_fmt = runtime->format; + return hcp->hcd.ops->prepare(dai->dev->parent, hcp->hcd.data, + cf, &hp); +} + static int hdmi_codec_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { @@ -582,6 +689,7 @@ static const struct snd_soc_dai_ops hdmi_codec_i2s_dai_ops = { .startup = hdmi_codec_startup, .shutdown = hdmi_codec_shutdown, .hw_params = hdmi_codec_hw_params, + .prepare = hdmi_codec_prepare, .set_fmt = hdmi_codec_i2s_set_fmt, .mute_stream = hdmi_codec_mute, }; @@ -615,23 +723,40 @@ static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = { SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE |\ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |\ - SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE) + SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |\ + SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE) + +static struct snd_kcontrol_new hdmi_codec_controls[] = { + { + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK), + .info = hdmi_codec_iec958_info, + .get = hdmi_codec_iec958_mask_get, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), + .info = hdmi_codec_iec958_info, + .get = hdmi_codec_iec958_default_get, + .put = hdmi_codec_iec958_default_put, + }, + { + .access = (SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE), + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "ELD", + .info = hdmi_eld_ctl_info, + .get = hdmi_eld_ctl_get, + }, +}; static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { struct snd_soc_dai_driver *drv = dai->driver; struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); - struct snd_kcontrol *kctl; - struct snd_kcontrol_new hdmi_eld_ctl = { - .access = SNDRV_CTL_ELEM_ACCESS_READ | - SNDRV_CTL_ELEM_ACCESS_VOLATILE, - .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = "ELD", - .info = hdmi_eld_ctl_info, - .get = hdmi_eld_ctl_get, - .device = rtd->pcm->device, - }; + unsigned int i; int ret; ret = snd_pcm_add_chmap_ctls(rtd->pcm, SNDRV_PCM_STREAM_PLAYBACK, @@ -648,26 +773,41 @@ static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd, hcp->chmap_info->chmap = hdmi_codec_stereo_chmaps; hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; - /* add ELD ctl with the device number corresponding to the PCM stream */ - kctl = snd_ctl_new1(&hdmi_eld_ctl, dai->component); - if (!kctl) - return -ENOMEM; + for (i = 0; i < ARRAY_SIZE(hdmi_codec_controls); i++) { + struct snd_kcontrol *kctl; - return snd_ctl_add(rtd->card->snd_card, kctl); + /* add ELD ctl with the device number corresponding to the PCM stream */ + kctl = snd_ctl_new1(&hdmi_codec_controls[i], dai->component); + if (!kctl) + return -ENOMEM; + + kctl->id.device = rtd->pcm->device; + ret = snd_ctl_add(rtd->card->snd_card, kctl); + if (ret < 0) + return ret; + } + + return 0; } static int hdmi_dai_probe(struct snd_soc_dai *dai) { struct snd_soc_dapm_context *dapm; struct hdmi_codec_daifmt *daifmt; - struct snd_soc_dapm_route route = { - .sink = "TX", - .source = dai->driver->playback.stream_name, + struct snd_soc_dapm_route route[] = { + { + .sink = "TX", + .source = dai->driver->playback.stream_name, + }, + { + .sink = dai->driver->capture.stream_name, + .source = "RX", + }, }; int ret; dapm = snd_soc_component_get_dapm(dai->component); - ret = snd_soc_dapm_add_routes(dapm, &route, 1); + ret = snd_soc_dapm_add_routes(dapm, route, 2); if (ret) return ret; @@ -692,10 +832,16 @@ static void plugged_cb(struct device *dev, bool plugged) { struct hdmi_codec_priv *hcp = dev_get_drvdata(dev); - if (plugged) + if (plugged) { + if (hcp->hcd.ops->get_eld) { + hcp->hcd.ops->get_eld(dev->parent, hcp->hcd.data, + hcp->eld, sizeof(hcp->eld)); + } hdmi_codec_jack_report(hcp, SND_JACK_LINEOUT); - else + } else { hdmi_codec_jack_report(hcp, 0); + memset(hcp->eld, 0, sizeof(hcp->eld)); + } } static int hdmi_codec_set_jack(struct snd_soc_component *component, @@ -703,7 +849,7 @@ static int hdmi_codec_set_jack(struct snd_soc_component *component, void *data) { struct hdmi_codec_priv *hcp = snd_soc_component_get_drvdata(component); - int ret = -EOPNOTSUPP; + int ret = -ENOTSUPP; if (hcp->hcd.ops->hook_plugged_cb) { hcp->jack = jack; @@ -719,7 +865,7 @@ static int hdmi_codec_set_jack(struct snd_soc_component *component, static int hdmi_dai_spdif_probe(struct snd_soc_dai *dai) { - struct hdmi_codec_daifmt *cf = dai->playback_dma_data; + struct hdmi_codec_daifmt *cf; int ret; ret = hdmi_dai_probe(dai); @@ -751,6 +897,14 @@ static const struct snd_soc_dai_driver hdmi_i2s_dai = { .formats = I2S_FORMATS, .sig_bits = 24, }, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 8, + .rates = HDMI_RATES, + .formats = I2S_FORMATS, + .sig_bits = 24, + }, .ops = &hdmi_codec_i2s_dai_ops, .pcm_new = hdmi_codec_pcm_new, }; @@ -767,6 +921,13 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = { .rates = HDMI_RATES, .formats = SPDIF_FORMATS, }, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 2, + .rates = HDMI_RATES, + .formats = SPDIF_FORMATS, + }, .ops = &hdmi_codec_spdif_dai_ops, .pcm_new = hdmi_codec_pcm_new, }; @@ -819,7 +980,8 @@ static int hdmi_codec_probe(struct platform_device *pdev) } dai_count = hcd->i2s + hcd->spdif; - if (dai_count < 1 || !hcd->ops || !hcd->ops->hw_params || + if (dai_count < 1 || !hcd->ops || + (!hcd->ops->hw_params && !hcd->ops->prepare) || !hcd->ops->audio_shutdown) { dev_err(dev, "%s: Invalid parameters\n", __func__); return -EINVAL; @@ -832,6 +994,11 @@ static int hdmi_codec_probe(struct platform_device *pdev) hcp->hcd = *hcd; mutex_init(&hcp->lock); + ret = snd_pcm_create_iec958_consumer_default(hcp->iec_status, + sizeof(hcp->iec_status)); + if (ret < 0) + return ret; + daidrv = devm_kcalloc(dev, dai_count, sizeof(*daidrv), GFP_KERNEL); if (!daidrv) return -ENOMEM;