summaryrefslogtreecommitdiff |
diff options
author | Petr Tesarik <ptesarik@suse.cz> | 2019-01-11 17:15:48 +0100 |
---|---|---|
committer | Petr Tesarik <ptesarik@suse.cz> | 2019-01-11 17:15:48 +0100 |
commit | 233a6f55ab6479ce319292bae60b5de93bca3f6d (patch) | |
tree | 6a57cfd87997f9ae788e8452f7e48391ecf3653f | |
parent | 22b35258f480b2fdccf2bab6efa10f3466eacd13 (diff) |
Revert alsa fixes from Takashi Iwai
This reverts changes pulled with merge commit
1f2c22ffd207d2f4725fd6feec155229d70213eb.
suse-commit: 097dbea51c1e2cd7a1130a8cef279085b6a16eab
147 files changed, 3316 insertions, 6184 deletions
diff --git a/Documentation/sound/alsa-configuration.rst b/Documentation/sound/alsa-configuration.rst index b1052e18292d..aed6b4fb8e46 100644 --- a/Documentation/sound/alsa-configuration.rst +++ b/Documentation/sound/alsa-configuration.rst @@ -2224,13 +2224,6 @@ quirk_alias Quirk alias list, pass strings like ``0123abcd:5678beef``, which applies the existing quirk for the device 5678:beef to a new device 0123:abcd. -use_vmalloc - Use vmalloc() for allocations of the PCM buffers (default: yes). - For architectures with non-coherent memory like ARM or MIPS, the - mmap access may give inconsistent results with vmalloc'ed - buffers. If mmap is used on such architectures, turn off this - option, so that the DMA-coherent buffers are allocated and used - instead. This module supports multiple devices, autoprobe and hotplugging. diff --git a/include/linux/usb/audio-v2.h b/include/linux/usb/audio-v2.h index bfc5659a9e28..76706391ce6d 100644 --- a/include/linux/usb/audio-v2.h +++ b/include/linux/usb/audio-v2.h @@ -33,14 +33,14 @@ * */ -static inline bool uac_v2v3_control_is_readable(u32 bmControls, u8 control) +static inline bool uac2_control_is_readable(u32 bmControls, u8 control) { - return (bmControls >> ((control - 1) * 2)) & 0x1; + return (bmControls >> (control * 2)) & 0x1; } -static inline bool uac_v2v3_control_is_writeable(u32 bmControls, u8 control) +static inline bool uac2_control_is_writeable(u32 bmControls, u8 control) { - return (bmControls >> ((control - 1) * 2)) & 0x2; + return (bmControls >> (control * 2)) & 0x2; } /* 4.7.2 Class-Specific AC Interface Descriptor */ @@ -115,13 +115,13 @@ struct uac2_input_terminal_descriptor { __u8 bDescriptorType; __u8 bDescriptorSubtype; __u8 bTerminalID; - __le16 wTerminalType; + __u16 wTerminalType; __u8 bAssocTerminal; __u8 bCSourceID; __u8 bNrChannels; - __le32 bmChannelConfig; + __u32 bmChannelConfig; __u8 iChannelNames; - __le16 bmControls; + __u16 bmControls; __u8 iTerminal; } __attribute__((packed)); @@ -132,11 +132,11 @@ struct uac2_output_terminal_descriptor { __u8 bDescriptorType; __u8 bDescriptorSubtype; __u8 bTerminalID; - __le16 wTerminalType; + __u16 wTerminalType; __u8 bAssocTerminal; __u8 bSourceID; __u8 bCSourceID; - __le16 bmControls; + __u16 bmControls; __u8 iTerminal; } __attribute__((packed)); @@ -164,9 +164,9 @@ struct uac2_as_header_descriptor { __u8 bTerminalLink; __u8 bmControls; __u8 bFormatType; - __le32 bmFormats; + __u32 bmFormats; __u8 bNrChannels; - __le32 bmChannelConfig; + __u32 bmChannelConfig; __u8 iChannelNames; } __attribute__((packed)); @@ -188,13 +188,6 @@ struct uac2_iso_endpoint_descriptor { #define UAC2_CONTROL_DATA_OVERRUN (3 << 2) #define UAC2_CONTROL_DATA_UNDERRUN (3 << 4) -/* 5.2.5.4.2 Connector Control Parameter Block */ -struct uac2_connectors_ctl_blk { - __u8 bNrChannels; - __le32 bmChannelConfig; - __u8 iChannelNames; -} __attribute__((packed)); - /* 6.1 Interrupt Data Message */ #define UAC2_INTERRUPT_DATA_MSG_VENDOR (1 << 0) diff --git a/include/linux/usb/audio-v3.h b/include/linux/usb/audio-v3.h deleted file mode 100644 index 6b708434b7f9..000000000000 --- a/include/linux/usb/audio-v3.h +++ /dev/null @@ -1,454 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 2017 Ruslan Bilovol <ruslan.bilovol@gmail.com> - * - * This file holds USB constants and structures defined - * by the USB DEVICE CLASS DEFINITION FOR AUDIO DEVICES Release 3.0. - */ - -#ifndef __LINUX_USB_AUDIO_V3_H -#define __LINUX_USB_AUDIO_V3_H - -#include <linux/types.h> - -/* - * v1.0, v2.0 and v3.0 of this standard have many things in common. For the rest - * of the definitions, please refer to audio.h and audio-v2.h - */ - -/* All High Capability descriptors have these 2 fields at the beginning */ -struct uac3_hc_descriptor_header { - __le16 wLength; - __u8 bDescriptorType; - __u8 bDescriptorSubtype; - __le16 wDescriptorID; -} __attribute__ ((packed)); - -/* 4.3.1 CLUSTER DESCRIPTOR HEADER */ -struct uac3_cluster_header_descriptor { - __le16 wLength; - __u8 bDescriptorType; - __u8 bDescriptorSubtype; - __le16 wDescriptorID; - __u8 bNrChannels; -} __attribute__ ((packed)); - -/* 4.3.2.1 SEGMENTS */ -struct uac3_cluster_segment_descriptor { - __le16 wLength; - __u8 bSegmentType; - /* __u8[0]; segment-specific data */ -} __attribute__ ((packed)); - -/* 4.3.2.1.1 END SEGMENT */ -struct uac3_cluster_end_segment_descriptor { - __le16 wLength; - __u8 bSegmentType; /* Constant END_SEGMENT */ -} __attribute__ ((packed)); - -/* 4.3.2.1.3.1 INFORMATION SEGMENT */ -struct uac3_cluster_information_segment_descriptor { - __le16 wLength; - __u8 bSegmentType; - __u8 bChPurpose; - __u8 bChRelationship; - __u8 bChGroupID; -} __attribute__ ((packed)); - -/* 4.5.2 CLASS-SPECIFIC AC INTERFACE DESCRIPTOR */ -struct uac3_ac_header_descriptor { - __u8 bLength; /* 10 */ - __u8 bDescriptorType; /* CS_INTERFACE descriptor type */ - __u8 bDescriptorSubtype; /* HEADER descriptor subtype */ - __u8 bCategory; - - /* includes Clock Source, Unit, Terminal, and Power Domain desc. */ - __le16 wTotalLength; - - __le32 bmControls; -} __attribute__ ((packed)); - -/* 4.5.2.1 INPUT TERMINAL DESCRIPTOR */ -struct uac3_input_terminal_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubtype; - __u8 bTerminalID; - __le16 wTerminalType; - __u8 bAssocTerminal; - __u8 bCSourceID; - __le32 bmControls; - __le16 wClusterDescrID; - __le16 wExTerminalDescrID; - __le16 wConnectorsDescrID; - __le16 wTerminalDescrStr; -} __attribute__((packed)); - -/* 4.5.2.2 OUTPUT TERMINAL DESCRIPTOR */ -struct uac3_output_terminal_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubtype; - __u8 bTerminalID; - __le16 wTerminalType; - __u8 bAssocTerminal; - __u8 bSourceID; - __u8 bCSourceID; - __le32 bmControls; - __le16 wExTerminalDescrID; - __le16 wConnectorsDescrID; - __le16 wTerminalDescrStr; -} __attribute__((packed)); - -/* 4.5.2.7 FEATURE UNIT DESCRIPTOR */ -struct uac3_feature_unit_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubtype; - __u8 bUnitID; - __u8 bSourceID; - /* bmaControls is actually u32, - * but u8 is needed for the hybrid parser */ - __u8 bmaControls[0]; /* variable length */ - /* wFeatureDescrStr omitted */ -} __attribute__((packed)); - -#define UAC3_DT_FEATURE_UNIT_SIZE(ch) (7 + ((ch) + 1) * 4) - -/* As above, but more useful for defining your own descriptors */ -#define DECLARE_UAC3_FEATURE_UNIT_DESCRIPTOR(ch) \ -struct uac3_feature_unit_descriptor_##ch { \ - __u8 bLength; \ - __u8 bDescriptorType; \ - __u8 bDescriptorSubtype; \ - __u8 bUnitID; \ - __u8 bSourceID; \ - __le32 bmaControls[ch + 1]; \ - __le16 wFeatureDescrStr; \ -} __attribute__ ((packed)) - -/* 4.5.2.12 CLOCK SOURCE DESCRIPTOR */ -struct uac3_clock_source_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubtype; - __u8 bClockID; - __u8 bmAttributes; - __le32 bmControls; - __u8 bReferenceTerminal; - __le16 wClockSourceStr; -} __attribute__((packed)); - -/* bmAttribute fields */ -#define UAC3_CLOCK_SOURCE_TYPE_EXT 0x0 -#define UAC3_CLOCK_SOURCE_TYPE_INT 0x1 -#define UAC3_CLOCK_SOURCE_ASYNC (0 << 2) -#define UAC3_CLOCK_SOURCE_SYNCED_TO_SOF (1 << 1) - -/* 4.5.2.13 CLOCK SELECTOR DESCRIPTOR */ -struct uac3_clock_selector_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubtype; - __u8 bClockID; - __u8 bNrInPins; - __u8 baCSourceID[]; - /* bmControls and wCSelectorDescrStr omitted */ -} __attribute__((packed)); - -/* 4.5.2.14 CLOCK MULTIPLIER DESCRIPTOR */ -struct uac3_clock_multiplier_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubtype; - __u8 bClockID; - __u8 bCSourceID; - __le32 bmControls; - __le16 wCMultiplierDescrStr; -} __attribute__((packed)); - -/* 4.5.2.15 POWER DOMAIN DESCRIPTOR */ -struct uac3_power_domain_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubtype; - __u8 bPowerDomainID; - __le16 waRecoveryTime1; - __le16 waRecoveryTime2; - __u8 bNrEntities; - __u8 baEntityID[]; - /* wPDomainDescrStr omitted */ -} __attribute__((packed)); - -/* As above, but more useful for defining your own descriptors */ -#define DECLARE_UAC3_POWER_DOMAIN_DESCRIPTOR(n) \ -struct uac3_power_domain_descriptor_##n { \ - __u8 bLength; \ - __u8 bDescriptorType; \ - __u8 bDescriptorSubtype; \ - __u8 bPowerDomainID; \ - __le16 waRecoveryTime1; \ - __le16 waRecoveryTime2; \ - __u8 bNrEntities; \ - __u8 baEntityID[n]; \ - __le16 wPDomainDescrStr; \ -} __attribute__ ((packed)) - -/* 4.7.2 CLASS-SPECIFIC AS INTERFACE DESCRIPTOR */ -struct uac3_as_header_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubtype; - __u8 bTerminalLink; - __le32 bmControls; - __le16 wClusterDescrID; - __le64 bmFormats; - __u8 bSubslotSize; - __u8 bBitResolution; - __le16 bmAuxProtocols; - __u8 bControlSize; -} __attribute__((packed)); - -#define UAC3_FORMAT_TYPE_I_RAW_DATA (1 << 6) - -/* 4.8.1.2 CLASS-SPECIFIC AS ISOCHRONOUS AUDIO DATA ENDPOINT DESCRIPTOR */ -struct uac3_iso_endpoint_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubtype; - __le32 bmControls; - __u8 bLockDelayUnits; - __le16 wLockDelay; -} __attribute__((packed)); - -/* 5.2.1.6.1 INSERTION CONTROL PARAMETER BLOCK */ -struct uac3_insertion_ctl_blk { - __u8 bSize; - __u8 bmConInserted; -} __attribute__ ((packed)); - -/* 6.1 INTERRUPT DATA MESSAGE */ -struct uac3_interrupt_data_msg { - __u8 bInfo; - __u8 bSourceType; - __le16 wValue; - __le16 wIndex; -} __attribute__((packed)); - -/* A.2 AUDIO AUDIO FUNCTION SUBCLASS CODES */ -#define UAC3_FUNCTION_SUBCLASS_UNDEFINED 0x00 -#define UAC3_FUNCTION_SUBCLASS_FULL_ADC_3_0 0x01 -/* BADD profiles */ -#define UAC3_FUNCTION_SUBCLASS_GENERIC_IO 0x20 -#define UAC3_FUNCTION_SUBCLASS_HEADPHONE 0x21 -#define UAC3_FUNCTION_SUBCLASS_SPEAKER 0x22 -#define UAC3_FUNCTION_SUBCLASS_MICROPHONE 0x23 -#define UAC3_FUNCTION_SUBCLASS_HEADSET 0x24 -#define UAC3_FUNCTION_SUBCLASS_HEADSET_ADAPTER 0x25 -#define UAC3_FUNCTION_SUBCLASS_SPEAKERPHONE 0x26 - -/* A.7 AUDIO FUNCTION CATEGORY CODES */ -#define UAC3_FUNCTION_SUBCLASS_UNDEFINED 0x00 -#define UAC3_FUNCTION_DESKTOP_SPEAKER 0x01 -#define UAC3_FUNCTION_HOME_THEATER 0x02 -#define UAC3_FUNCTION_MICROPHONE 0x03 -#define UAC3_FUNCTION_HEADSET 0x04 -#define UAC3_FUNCTION_TELEPHONE 0x05 -#define UAC3_FUNCTION_CONVERTER 0x06 -#define UAC3_FUNCTION_SOUND_RECORDER 0x07 -#define UAC3_FUNCTION_IO_BOX 0x08 -#define UAC3_FUNCTION_MUSICAL_INSTRUMENT 0x09 -#define UAC3_FUNCTION_PRO_AUDIO 0x0a -#define UAC3_FUNCTION_AUDIO_VIDEO 0x0b -#define UAC3_FUNCTION_CONTROL_PANEL 0x0c -#define UAC3_FUNCTION_HEADPHONE 0x0d -#define UAC3_FUNCTION_GENERIC_SPEAKER 0x0e -#define UAC3_FUNCTION_HEADSET_ADAPTER 0x0f -#define UAC3_FUNCTION_SPEAKERPHONE 0x10 -#define UAC3_FUNCTION_OTHER 0xff - -/* A.8 AUDIO CLASS-SPECIFIC DESCRIPTOR TYPES */ -#define UAC3_CS_UNDEFINED 0x20 -#define UAC3_CS_DEVICE 0x21 -#define UAC3_CS_CONFIGURATION 0x22 -#define UAC3_CS_STRING 0x23 -#define UAC3_CS_INTERFACE 0x24 -#define UAC3_CS_ENDPOINT 0x25 -#define UAC3_CS_CLUSTER 0x26 - -/* A.10 CLUSTER DESCRIPTOR SEGMENT TYPES */ -#define UAC3_SEGMENT_UNDEFINED 0x00 -#define UAC3_CLUSTER_DESCRIPTION 0x01 -#define UAC3_CLUSTER_VENDOR_DEFINED 0x1F -#define UAC3_CHANNEL_INFORMATION 0x20 -#define UAC3_CHANNEL_AMBISONIC 0x21 -#define UAC3_CHANNEL_DESCRIPTION 0x22 -#define UAC3_CHANNEL_VENDOR_DEFINED 0xFE -#define UAC3_END_SEGMENT 0xFF - -/* A.11 CHANNEL PURPOSE DEFINITIONS */ -#define UAC3_PURPOSE_UNDEFINED 0x00 -#define UAC3_PURPOSE_GENERIC_AUDIO 0x01 -#define UAC3_PURPOSE_VOICE 0x02 -#define UAC3_PURPOSE_SPEECH 0x03 -#define UAC3_PURPOSE_AMBIENT 0x04 -#define UAC3_PURPOSE_REFERENCE 0x05 -#define UAC3_PURPOSE_ULTRASONIC 0x06 -#define UAC3_PURPOSE_VIBROKINETIC 0x07 -#define UAC3_PURPOSE_NON_AUDIO 0xFF - -/* A.12 CHANNEL RELATIONSHIP DEFINITIONS */ -#define UAC3_CH_RELATIONSHIP_UNDEFINED 0x00 -#define UAC3_CH_MONO 0x01 -#define UAC3_CH_LEFT 0x02 -#define UAC3_CH_RIGHT 0x03 -#define UAC3_CH_ARRAY 0x04 -#define UAC3_CH_PATTERN_X 0x20 -#define UAC3_CH_PATTERN_Y 0x21 -#define UAC3_CH_PATTERN_A 0x22 -#define UAC3_CH_PATTERN_B 0x23 -#define UAC3_CH_PATTERN_M 0x24 -#define UAC3_CH_PATTERN_S 0x25 -#define UAC3_CH_FRONT_LEFT 0x80 -#define UAC3_CH_FRONT_RIGHT 0x81 -#define UAC3_CH_FRONT_CENTER 0x82 -#define UAC3_CH_FRONT_LEFT_OF_CENTER 0x83 -#define UAC3_CH_FRONT_RIGHT_OF_CENTER 0x84 -#define UAC3_CH_FRONT_WIDE_LEFT 0x85 -#define UAC3_CH_FRONT_WIDE_RIGHT 0x86 -#define UAC3_CH_SIDE_LEFT 0x87 -#define UAC3_CH_SIDE_RIGHT 0x88 -#define UAC3_CH_SURROUND_ARRAY_LEFT 0x89 -#define UAC3_CH_SURROUND_ARRAY_RIGHT 0x8A -#define UAC3_CH_BACK_LEFT 0x8B -#define UAC3_CH_BACK_RIGHT 0x8C -#define UAC3_CH_BACK_CENTER 0x8D -#define UAC3_CH_BACK_LEFT_OF_CENTER 0x8E -#define UAC3_CH_BACK_RIGHT_OF_CENTER 0x8F -#define UAC3_CH_BACK_WIDE_LEFT 0x90 -#define UAC3_CH_BACK_WIDE_RIGHT 0x91 -#define UAC3_CH_TOP_CENTER 0x92 -#define UAC3_CH_TOP_FRONT_LEFT 0x93 -#define UAC3_CH_TOP_FRONT_RIGHT 0x94 -#define UAC3_CH_TOP_FRONT_CENTER 0x95 -#define UAC3_CH_TOP_FRONT_LOC 0x96 -#define UAC3_CH_TOP_FRONT_ROC 0x97 -#define UAC3_CH_TOP_FRONT_WIDE_LEFT 0x98 -#define UAC3_CH_TOP_FRONT_WIDE_RIGHT 0x99 -#define UAC3_CH_TOP_SIDE_LEFT 0x9A -#define UAC3_CH_TOP_SIDE_RIGHT 0x9B -#define UAC3_CH_TOP_SURR_ARRAY_LEFT 0x9C -#define UAC3_CH_TOP_SURR_ARRAY_RIGHT 0x9D -#define UAC3_CH_TOP_BACK_LEFT 0x9E -#define UAC3_CH_TOP_BACK_RIGHT 0x9F -#define UAC3_CH_TOP_BACK_CENTER 0xA0 -#define UAC3_CH_TOP_BACK_LOC 0xA1 -#define UAC3_CH_TOP_BACK_ROC 0xA2 -#define UAC3_CH_TOP_BACK_WIDE_LEFT 0xA3 -#define UAC3_CH_TOP_BACK_WIDE_RIGHT 0xA4 -#define UAC3_CH_BOTTOM_CENTER 0xA5 -#define UAC3_CH_BOTTOM_FRONT_LEFT 0xA6 -#define UAC3_CH_BOTTOM_FRONT_RIGHT 0xA7 -#define UAC3_CH_BOTTOM_FRONT_CENTER 0xA8 -#define UAC3_CH_BOTTOM_FRONT_LOC 0xA9 -#define UAC3_CH_BOTTOM_FRONT_ROC 0xAA -#define UAC3_CH_BOTTOM_FRONT_WIDE_LEFT 0xAB -#define UAC3_CH_BOTTOM_FRONT_WIDE_RIGHT 0xAC -#define UAC3_CH_BOTTOM_SIDE_LEFT 0xAD -#define UAC3_CH_BOTTOM_SIDE_RIGHT 0xAE -#define UAC3_CH_BOTTOM_SURR_ARRAY_LEFT 0xAF -#define UAC3_CH_BOTTOM_SURR_ARRAY_RIGHT 0xB0 -#define UAC3_CH_BOTTOM_BACK_LEFT 0xB1 -#define UAC3_CH_BOTTOM_BACK_RIGHT 0xB2 -#define UAC3_CH_BOTTOM_BACK_CENTER 0xB3 -#define UAC3_CH_BOTTOM_BACK_LOC 0xB4 -#define UAC3_CH_BOTTOM_BACK_ROC 0xB5 -#define UAC3_CH_BOTTOM_BACK_WIDE_LEFT 0xB6 -#define UAC3_CH_BOTTOM_BACK_WIDE_RIGHT 0xB7 -#define UAC3_CH_LOW_FREQUENCY_EFFECTS 0xB8 -#define UAC3_CH_LFE_LEFT 0xB9 -#define UAC3_CH_LFE_RIGHT 0xBA -#define UAC3_CH_HEADPHONE_LEFT 0xBB -#define UAC3_CH_HEADPHONE_RIGHT 0xBC - -/* A.15 AUDIO CLASS-SPECIFIC AC INTERFACE DESCRIPTOR SUBTYPES */ -/* see audio.h for the rest, which is identical to v1 */ -#define UAC3_EXTENDED_TERMINAL 0x04 -#define UAC3_MIXER_UNIT 0x05 -#define UAC3_SELECTOR_UNIT 0x06 -#define UAC3_FEATURE_UNIT 0x07 -#define UAC3_EFFECT_UNIT 0x08 -#define UAC3_PROCESSING_UNIT 0x09 -#define UAC3_EXTENSION_UNIT 0x0a -#define UAC3_CLOCK_SOURCE 0x0b -#define UAC3_CLOCK_SELECTOR 0x0c -#define UAC3_CLOCK_MULTIPLIER 0x0d -#define UAC3_SAMPLE_RATE_CONVERTER 0x0e -#define UAC3_CONNECTORS 0x0f -#define UAC3_POWER_DOMAIN 0x10 - -/* A.20 PROCESSING UNIT PROCESS TYPES */ -#define UAC3_PROCESS_UNDEFINED 0x00 -#define UAC3_PROCESS_UP_DOWNMIX 0x01 -#define UAC3_PROCESS_STEREO_EXTENDER 0x02 -#define UAC3_PROCESS_MULTI_FUNCTION 0x03 - -/* A.22 AUDIO CLASS-SPECIFIC REQUEST CODES */ -/* see audio-v2.h for the rest, which is identical to v2 */ -#define UAC3_CS_REQ_INTEN 0x04 -#define UAC3_CS_REQ_STRING 0x05 -#define UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR 0x06 - -/* A.23.1 AUDIOCONTROL INTERFACE CONTROL SELECTORS */ -#define UAC3_AC_CONTROL_UNDEFINED 0x00 -#define UAC3_AC_ACTIVE_INTERFACE_CONTROL 0x01 -#define UAC3_AC_POWER_DOMAIN_CONTROL 0x02 - -/* A.23.5 TERMINAL CONTROL SELECTORS */ -#define UAC3_TE_UNDEFINED 0x00 -#define UAC3_TE_INSERTION 0x01 -#define UAC3_TE_OVERLOAD 0x02 -#define UAC3_TE_UNDERFLOW 0x03 -#define UAC3_TE_OVERFLOW 0x04 -#define UAC3_TE_LATENCY 0x05 - -/* A.23.10 PROCESSING UNITS CONTROL SELECTROS */ - -/* Up/Down Mixer */ -#define UAC3_UD_MODE_SELECT 0x01 - -/* Stereo Extender */ -#define UAC3_EXT_WIDTH_CONTROL 0x01 - - -/* BADD predefined Unit/Terminal values */ -#define UAC3_BADD_IT_ID1 1 /* Input Terminal ID1: bTerminalID = 1 */ -#define UAC3_BADD_FU_ID2 2 /* Feature Unit ID2: bUnitID = 2 */ -#define UAC3_BADD_OT_ID3 3 /* Output Terminal ID3: bTerminalID = 3 */ -#define UAC3_BADD_IT_ID4 4 /* Input Terminal ID4: bTerminalID = 4 */ -#define UAC3_BADD_FU_ID5 5 /* Feature Unit ID5: bUnitID = 5 */ -#define UAC3_BADD_OT_ID6 6 /* Output Terminal ID6: bTerminalID = 6 */ -#define UAC3_BADD_FU_ID7 7 /* Feature Unit ID7: bUnitID = 7 */ -#define UAC3_BADD_MU_ID8 8 /* Mixer Unit ID8: bUnitID = 8 */ -#define UAC3_BADD_CS_ID9 9 /* Clock Source Entity ID9: bClockID = 9 */ -#define UAC3_BADD_PD_ID10 10 /* Power Domain ID10: bPowerDomainID = 10 */ -#define UAC3_BADD_PD_ID11 11 /* Power Domain ID11: bPowerDomainID = 11 */ - -/* BADD wMaxPacketSize of AS endpoints */ -#define UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_16 0x0060 -#define UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_16 0x0062 -#define UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_24 0x0090 -#define UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_24 0x0093 -#define UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_16 0x00C0 -#define UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_16 0x00C4 -#define UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_24 0x0120 -#define UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_24 0x0126 - -/* BADD sample rate is always fixed to 48kHz */ -#define UAC3_BADD_SAMPLING_RATE 48000 - -/* BADD power domains recovery times in 50us increments */ -#define UAC3_BADD_PD_RECOVER_D1D0 0x0258 /* 30ms */ -#define UAC3_BADD_PD_RECOVER_D2D0 0x1770 /* 300ms */ - -#endif /* __LINUX_USB_AUDIO_V3_H */ diff --git a/include/sound/core.h b/include/sound/core.h index 36a5934cf4b1..f1f0c148cc9d 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -118,6 +118,8 @@ struct snd_card { int user_ctl_count; /* count of all user controls */ struct list_head controls; /* all controls for this card */ struct list_head ctl_files; /* active control files */ + struct mutex user_ctl_lock; /* protects user controls against + concurrent access */ struct snd_info_entry *proc_root; /* root for soundcard specific files */ struct snd_info_entry *proc_id; /* the card id */ @@ -133,14 +135,14 @@ struct snd_card { struct device card_dev; /* cardX object for sysfs */ const struct attribute_group *dev_groups[4]; /* assigned sysfs attr */ bool registered; /* card_dev is registered? */ - wait_queue_head_t remove_sleep; #ifdef CONFIG_PM unsigned int power_state; /* power state */ + struct mutex power_lock; /* power lock */ wait_queue_head_t power_sleep; #endif -#if IS_ENABLED(CONFIG_SND_MIXER_OSS) +#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) struct snd_mixer_oss *mixer_oss; int mixer_oss_change_count; #endif @@ -149,6 +151,16 @@ struct snd_card { #define dev_to_snd_card(p) container_of(p, struct snd_card, card_dev) #ifdef CONFIG_PM +static inline void snd_power_lock(struct snd_card *card) +{ + mutex_lock(&card->power_lock); +} + +static inline void snd_power_unlock(struct snd_card *card) +{ + mutex_unlock(&card->power_lock); +} + static inline unsigned int snd_power_get_state(struct snd_card *card) { return card->power_state; @@ -165,6 +177,8 @@ int snd_power_wait(struct snd_card *card, unsigned int power_state); #else /* ! CONFIG_PM */ +#define snd_power_lock(card) do { (void)(card); } while (0) +#define snd_power_unlock(card) do { (void)(card); } while (0) static inline int snd_power_wait(struct snd_card *card, unsigned int state) { return 0; } #define snd_power_get_state(card) ({ (void)(card); SNDRV_CTL_POWER_D0; }) #define snd_power_change_state(card, state) do { (void)(card); } while (0) @@ -229,7 +243,7 @@ int copy_from_user_toio(volatile void __iomem *dst, const void __user *src, size extern struct snd_card *snd_cards[SNDRV_CARDS]; int snd_card_locked(int card); -#if IS_ENABLED(CONFIG_SND_MIXER_OSS) +#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) #define SND_MIXER_OSS_NOTIFY_REGISTER 0 #define SND_MIXER_OSS_NOTIFY_DISCONNECT 1 #define SND_MIXER_OSS_NOTIFY_FREE 2 @@ -241,7 +255,6 @@ int snd_card_new(struct device *parent, int idx, const char *xid, struct snd_card **card_ret); int snd_card_disconnect(struct snd_card *card); -void snd_card_disconnect_sync(struct snd_card *card); int snd_card_free(struct snd_card *card); int snd_card_free_when_closed(struct snd_card *card); void snd_card_set_id(struct snd_card *card, const char *id); @@ -381,7 +394,7 @@ static inline void snd_printdd(const char *format, ...) {} #define SNDRV_OSS_VERSION ((3<<16)|(8<<8)|(1<<4)|(0)) /* 3.8.1a */ /* for easier backward-porting */ -#if IS_ENABLED(CONFIG_GAMEPORT) +#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE) #define gameport_set_dev_parent(gp,xdev) ((gp)->dev.parent = (xdev)) #define gameport_set_port_data(gp,r) ((gp)->port_data = (r)) #define gameport_get_port_data(gp) (gp)->port_data diff --git a/include/sound/emux_synth.h b/include/sound/emux_synth.h index 19a0cb561ffc..a0a40b74bf13 100644 --- a/include/sound/emux_synth.h +++ b/include/sound/emux_synth.h @@ -25,7 +25,9 @@ #include <sound/seq_device.h> #include <sound/soundfont.h> #include <sound/seq_midi_emul.h> +#ifdef CONFIG_SND_SEQUENCER_OSS #include <sound/seq_oss.h> +#endif #include <sound/emux_legacy.h> #include <sound/seq_virmidi.h> @@ -64,7 +66,7 @@ struct snd_emux_operators { const void __user *data, long count); void (*sysex)(struct snd_emux *emu, char *buf, int len, int parsed, struct snd_midi_channel_set *chset); -#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS) +#ifdef CONFIG_SND_SEQUENCER_OSS int (*oss_ioctl)(struct snd_emux *emu, int cmd, int p1, int p2); #endif }; @@ -127,7 +129,7 @@ struct snd_emux { struct snd_info_entry *proc; #endif -#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS) +#ifdef CONFIG_SND_SEQUENCER_OSS struct snd_seq_device *oss_synth; #endif }; @@ -148,7 +150,7 @@ struct snd_emux_port { #ifdef SNDRV_EMUX_USE_RAW_EFFECT struct snd_emux_effect_table *effect; #endif -#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS) +#ifdef CONFIG_SND_SEQUENCER_OSS struct snd_seq_oss_arg *oss_arg; #endif }; diff --git a/include/sound/mixer_oss.h b/include/sound/mixer_oss.h index 930da10fb65b..13cb0b430a1b 100644 --- a/include/sound/mixer_oss.h +++ b/include/sound/mixer_oss.h @@ -22,7 +22,7 @@ * */ -#if IS_ENABLED(CONFIG_SND_MIXER_OSS) +#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) #define SNDRV_OSS_MAX_MIXERS 32 diff --git a/include/sound/opl3.h b/include/sound/opl3.h index a4a593590cff..6ba670707831 100644 --- a/include/sound/opl3.h +++ b/include/sound/opl3.h @@ -55,8 +55,10 @@ #include <sound/hwdep.h> #include <sound/timer.h> #include <sound/seq_midi_emul.h> +#ifdef CONFIG_SND_SEQUENCER_OSS #include <sound/seq_oss.h> #include <sound/seq_oss_legacy.h> +#endif #include <sound/seq_device.h> #include <sound/asound_fm.h> @@ -319,7 +321,7 @@ struct snd_opl3 { unsigned char fm_mode; /* OPL mode, see SNDRV_DM_FM_MODE_XXX */ unsigned char rhythm; /* percussion mode flag */ unsigned char max_voices; /* max number of voices */ -#if IS_ENABLED(CONFIG_SND_SEQUENCER) +#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE) #define SNDRV_OPL3_MODE_SYNTH 0 /* OSS - voices allocated by application */ #define SNDRV_OPL3_MODE_SEQ 1 /* ALSA - driver handles voice allocation */ int synth_mode; /* synth mode */ @@ -328,7 +330,7 @@ struct snd_opl3 { struct snd_seq_device *seq_dev; /* sequencer device */ struct snd_midi_channel_set * chset; -#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS) +#ifdef CONFIG_SND_SEQUENCER_OSS struct snd_seq_device *oss_seq_dev; /* OSS sequencer device */ struct snd_midi_channel_set * oss_chset; #endif @@ -372,7 +374,7 @@ int snd_opl3_release(struct snd_hwdep * hw, struct file *file); void snd_opl3_reset(struct snd_opl3 * opl3); -#if IS_ENABLED(CONFIG_SND_SEQUENCER) +#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE) long snd_opl3_write(struct snd_hwdep *hw, const char __user *buf, long count, loff_t *offset); int snd_opl3_load_patch(struct snd_opl3 *opl3, diff --git a/include/sound/pcm.h b/include/sound/pcm.h index cebbe0cfd80c..361749e60799 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -34,7 +34,7 @@ #define snd_pcm_substream_chip(substream) ((substream)->private_data) #define snd_pcm_chip(pcm) ((pcm)->private_data) -#if IS_ENABLED(CONFIG_SND_PCM_OSS) +#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) #include <sound/pcm_oss.h> #endif @@ -78,13 +78,11 @@ struct snd_pcm_ops { struct timespec *system_ts, struct timespec *audio_ts, struct snd_pcm_audio_tstamp_config *audio_tstamp_config, struct snd_pcm_audio_tstamp_report *audio_tstamp_report); - int (*fill_silence)(struct snd_pcm_substream *substream, int channel, - unsigned long pos, unsigned long bytes); - int (*copy_user)(struct snd_pcm_substream *substream, int channel, - unsigned long pos, void __user *buf, - unsigned long bytes); - int (*copy_kernel)(struct snd_pcm_substream *substream, int channel, - unsigned long pos, void *buf, unsigned long bytes); + int (*copy)(struct snd_pcm_substream *substream, int channel, + snd_pcm_uframes_t pos, + void __user *buf, snd_pcm_uframes_t count); + int (*silence)(struct snd_pcm_substream *substream, int channel, + snd_pcm_uframes_t pos, snd_pcm_uframes_t count); struct page *(*page)(struct snd_pcm_substream *substream, unsigned long offset); int (*mmap)(struct snd_pcm_substream *substream, struct vm_area_struct *vma); @@ -102,9 +100,9 @@ struct snd_pcm_ops { #endif #define SNDRV_PCM_IOCTL1_RESET 0 -/* 1 is absent slot. */ +#define SNDRV_PCM_IOCTL1_INFO 1 #define SNDRV_PCM_IOCTL1_CHANNEL_INFO 2 -/* 3 is absent slot. */ +#define SNDRV_PCM_IOCTL1_GSTATE 3 #define SNDRV_PCM_IOCTL1_FIFO_SIZE 4 #define SNDRV_PCM_TRIGGER_STOP 0 @@ -169,10 +167,6 @@ struct snd_pcm_ops { #define SNDRV_PCM_FMTBIT_IMA_ADPCM _SNDRV_PCM_FMTBIT(IMA_ADPCM) #define SNDRV_PCM_FMTBIT_MPEG _SNDRV_PCM_FMTBIT(MPEG) #define SNDRV_PCM_FMTBIT_GSM _SNDRV_PCM_FMTBIT(GSM) -#define SNDRV_PCM_FMTBIT_S20_LE _SNDRV_PCM_FMTBIT(S20_LE) -#define SNDRV_PCM_FMTBIT_U20_LE _SNDRV_PCM_FMTBIT(U20_LE) -#define SNDRV_PCM_FMTBIT_S20_BE _SNDRV_PCM_FMTBIT(S20_BE) -#define SNDRV_PCM_FMTBIT_U20_BE _SNDRV_PCM_FMTBIT(U20_BE) #define SNDRV_PCM_FMTBIT_SPECIAL _SNDRV_PCM_FMTBIT(SPECIAL) #define SNDRV_PCM_FMTBIT_S24_3LE _SNDRV_PCM_FMTBIT(S24_3LE) #define SNDRV_PCM_FMTBIT_U24_3LE _SNDRV_PCM_FMTBIT(U24_3LE) @@ -206,8 +200,6 @@ struct snd_pcm_ops { #define SNDRV_PCM_FMTBIT_FLOAT SNDRV_PCM_FMTBIT_FLOAT_LE #define SNDRV_PCM_FMTBIT_FLOAT64 SNDRV_PCM_FMTBIT_FLOAT64_LE #define SNDRV_PCM_FMTBIT_IEC958_SUBFRAME SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE -#define SNDRV_PCM_FMTBIT_S20 SNDRV_PCM_FMTBIT_S20_LE -#define SNDRV_PCM_FMTBIT_U20 SNDRV_PCM_FMTBIT_U20_LE #endif #ifdef SNDRV_BIG_ENDIAN #define SNDRV_PCM_FMTBIT_S16 SNDRV_PCM_FMTBIT_S16_BE @@ -219,14 +211,11 @@ struct snd_pcm_ops { #define SNDRV_PCM_FMTBIT_FLOAT SNDRV_PCM_FMTBIT_FLOAT_BE #define SNDRV_PCM_FMTBIT_FLOAT64 SNDRV_PCM_FMTBIT_FLOAT64_BE #define SNDRV_PCM_FMTBIT_IEC958_SUBFRAME SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE -#define SNDRV_PCM_FMTBIT_S20 SNDRV_PCM_FMTBIT_S20_BE -#define SNDRV_PCM_FMTBIT_U20 SNDRV_PCM_FMTBIT_U20_BE #endif struct snd_pcm_file { struct snd_pcm_substream *substream; int no_compat_mmap; - unsigned int user_pversion; /* supported protocol version */ }; struct snd_pcm_hw_rule; @@ -429,7 +418,7 @@ struct snd_pcm_runtime { struct snd_pcm_audio_tstamp_report audio_tstamp_report; struct timespec driver_tstamp; -#if IS_ENABLED(CONFIG_SND_PCM_OSS) +#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) /* -- OSS things -- */ struct snd_pcm_oss_runtime oss; #endif @@ -462,7 +451,6 @@ struct snd_pcm_substream { /* -- timer section -- */ struct snd_timer *timer; /* timer */ unsigned timer_running: 1; /* time is running */ - long wait_time; /* time in ms for R/W to wait for avail */ /* -- next substream -- */ struct snd_pcm_substream *next; /* -- linked substreams -- */ @@ -476,7 +464,7 @@ struct snd_pcm_substream { unsigned int f_flags; void (*pcm_release)(struct snd_pcm_substream *); struct pid *pid; -#if IS_ENABLED(CONFIG_SND_PCM_OSS) +#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) /* -- OSS things -- */ struct snd_pcm_oss_substream oss; #endif @@ -506,7 +494,7 @@ struct snd_pcm_str { unsigned int substream_count; unsigned int substream_opened; struct snd_pcm_substream *substream; -#if IS_ENABLED(CONFIG_SND_PCM_OSS) +#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) /* -- OSS things -- */ struct snd_pcm_oss_stream oss; #endif @@ -538,11 +526,18 @@ struct snd_pcm { void (*private_free) (struct snd_pcm *pcm); bool internal; /* pcm is for internal use only */ bool nonatomic; /* whole PCM operations are in non-atomic context */ -#if IS_ENABLED(CONFIG_SND_PCM_OSS) +#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) struct snd_pcm_oss oss; #endif }; +struct snd_pcm_notify { + int (*n_register) (struct snd_pcm * pcm); + int (*n_disconnect) (struct snd_pcm * pcm); + int (*n_unregister) (struct snd_pcm * pcm); + struct list_head list; +}; + /* * Registering */ @@ -557,15 +552,7 @@ int snd_pcm_new_internal(struct snd_card *card, const char *id, int device, struct snd_pcm **rpcm); int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count); -#if IS_ENABLED(CONFIG_SND_PCM_OSS) -struct snd_pcm_notify { - int (*n_register) (struct snd_pcm * pcm); - int (*n_disconnect) (struct snd_pcm * pcm); - int (*n_unregister) (struct snd_pcm * pcm); - struct list_head list; -}; int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree); -#endif /* * Native I/O @@ -981,6 +968,12 @@ static inline unsigned int params_buffer_bytes(const struct snd_pcm_hw_params *p } int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v); +void snd_interval_mul(const struct snd_interval *a, const struct snd_interval *b, struct snd_interval *c); +void snd_interval_div(const struct snd_interval *a, const struct snd_interval *b, struct snd_interval *c); +void snd_interval_muldivk(const struct snd_interval *a, const struct snd_interval *b, + unsigned int k, struct snd_interval *c); +void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k, + const struct snd_interval *b, struct snd_interval *c); int snd_interval_list(struct snd_interval *i, unsigned int count, const unsigned int *list, unsigned int mask); int snd_interval_ranges(struct snd_interval *i, unsigned int count, @@ -991,9 +984,15 @@ int snd_interval_ratnum(struct snd_interval *i, void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params); void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params, snd_pcm_hw_param_t var); +int snd_pcm_hw_params_choose(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params); int snd_pcm_hw_refine(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params); +int snd_pcm_hw_constraints_init(struct snd_pcm_substream *substream); +int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream); + +int snd_pcm_hw_constraint_mask(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var, + u_int32_t mask); int snd_pcm_hw_constraint_mask64(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var, u_int64_t mask); int snd_pcm_hw_constraint_minmax(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var, @@ -1055,7 +1054,7 @@ int snd_pcm_format_unsigned(snd_pcm_format_t format); int snd_pcm_format_linear(snd_pcm_format_t format); int snd_pcm_format_little_endian(snd_pcm_format_t format); int snd_pcm_format_big_endian(snd_pcm_format_t format); -#if 0 /* just for kernel-doc */ +#if 0 /* just for DocBook */ /** * snd_pcm_format_cpu_endian - Check the PCM format is CPU-endian * @format: the format to check @@ -1081,66 +1080,22 @@ void snd_pcm_set_ops(struct snd_pcm * pcm, int direction, void snd_pcm_set_sync(struct snd_pcm_substream *substream); int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg); +int snd_pcm_update_state(struct snd_pcm_substream *substream, + struct snd_pcm_runtime *runtime); +int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream); +void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_uframes_t new_hw_ptr); void snd_pcm_period_elapsed(struct snd_pcm_substream *substream); -snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, - void *buf, bool interleaved, - snd_pcm_uframes_t frames, bool in_kernel); - -static inline snd_pcm_sframes_t -snd_pcm_lib_write(struct snd_pcm_substream *substream, - const void __user *buf, snd_pcm_uframes_t frames) -{ - return __snd_pcm_lib_xfer(substream, (void __force *)buf, true, frames, false); -} - -static inline snd_pcm_sframes_t -snd_pcm_lib_read(struct snd_pcm_substream *substream, - void __user *buf, snd_pcm_uframes_t frames) -{ - return __snd_pcm_lib_xfer(substream, (void __force *)buf, true, frames, false); -} - -static inline snd_pcm_sframes_t -snd_pcm_lib_writev(struct snd_pcm_substream *substream, - void __user **bufs, snd_pcm_uframes_t frames) -{ - return __snd_pcm_lib_xfer(substream, (void *)bufs, false, frames, false); -} - -static inline snd_pcm_sframes_t -snd_pcm_lib_readv(struct snd_pcm_substream *substream, - void __user **bufs, snd_pcm_uframes_t frames) -{ - return __snd_pcm_lib_xfer(substream, (void *)bufs, false, frames, false); -} - -static inline snd_pcm_sframes_t -snd_pcm_kernel_write(struct snd_pcm_substream *substream, - const void *buf, snd_pcm_uframes_t frames) -{ - return __snd_pcm_lib_xfer(substream, (void *)buf, true, frames, true); -} - -static inline snd_pcm_sframes_t -snd_pcm_kernel_read(struct snd_pcm_substream *substream, - void *buf, snd_pcm_uframes_t frames) -{ - return __snd_pcm_lib_xfer(substream, buf, true, frames, true); -} - -static inline snd_pcm_sframes_t -snd_pcm_kernel_writev(struct snd_pcm_substream *substream, - void **bufs, snd_pcm_uframes_t frames) -{ - return __snd_pcm_lib_xfer(substream, bufs, false, frames, true); -} - -static inline snd_pcm_sframes_t -snd_pcm_kernel_readv(struct snd_pcm_substream *substream, - void **bufs, snd_pcm_uframes_t frames) -{ - return __snd_pcm_lib_xfer(substream, bufs, false, frames, true); -} +snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, + const void __user *buf, + snd_pcm_uframes_t frames); +snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, + void __user *buf, snd_pcm_uframes_t frames); +snd_pcm_sframes_t snd_pcm_lib_writev(struct snd_pcm_substream *substream, + void __user **bufs, snd_pcm_uframes_t frames); +snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream, + void __user **bufs, snd_pcm_uframes_t frames); + +extern const struct snd_pcm_hw_constraint_list snd_pcm_known_rates; int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime); unsigned int snd_pcm_rate_to_rate_bit(unsigned int rate); @@ -1175,6 +1130,20 @@ static inline void snd_pcm_set_runtime_buffer(struct snd_pcm_substream *substrea } } +/* + * Timer interface + */ + +#ifdef CONFIG_SND_PCM_TIMER +void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream); +void snd_pcm_timer_init(struct snd_pcm_substream *substream); +void snd_pcm_timer_done(struct snd_pcm_substream *substream); +#else +static inline void +snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream) {} +static inline void snd_pcm_timer_init(struct snd_pcm_substream *substream) {} +static inline void snd_pcm_timer_done(struct snd_pcm_substream *substream) {} +#endif /** * snd_pcm_gettime - Fill the timespec depending on the timestamp mode * @runtime: PCM runtime instance diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h index 3b5a061132b6..492a3ca7f17b 100644 --- a/include/sound/rawmidi.h +++ b/include/sound/rawmidi.h @@ -30,7 +30,7 @@ #include <linux/workqueue.h> #include <linux/device.h> -#if IS_ENABLED(CONFIG_SND_SEQUENCER) +#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE) #include <sound/seq_device.h> #endif @@ -144,7 +144,7 @@ struct snd_rawmidi { struct snd_info_entry *proc_entry; -#if IS_ENABLED(CONFIG_SND_SEQUENCER) +#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE) struct snd_seq_device *seq_dev; #endif }; @@ -171,7 +171,6 @@ int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, unsigned char *buffer, int count); int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count); -int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream); /* main midi functions */ diff --git a/include/sound/seq_midi_event.h b/include/sound/seq_midi_event.h index 2f135bccf457..e40f43e6fc7b 100644 --- a/include/sound/seq_midi_event.h +++ b/include/sound/seq_midi_event.h @@ -43,8 +43,10 @@ void snd_midi_event_free(struct snd_midi_event *dev); void snd_midi_event_reset_encode(struct snd_midi_event *dev); void snd_midi_event_reset_decode(struct snd_midi_event *dev); void snd_midi_event_no_status(struct snd_midi_event *dev, int on); -bool snd_midi_event_encode_byte(struct snd_midi_event *dev, unsigned char c, - struct snd_seq_event *ev); +/* encode from byte stream - return number of written bytes if success */ +long snd_midi_event_encode(struct snd_midi_event *dev, unsigned char *buf, long count, + struct snd_seq_event *ev); +int snd_midi_event_encode_byte(struct snd_midi_event *dev, int c, struct snd_seq_event *ev); /* decode from event to bytes - return number of written bytes if success */ long snd_midi_event_decode(struct snd_midi_event *dev, unsigned char *buf, long count, struct snd_seq_event *ev); diff --git a/include/sound/seq_virmidi.h b/include/sound/seq_virmidi.h index 796ce7772213..695257ae64ac 100644 --- a/include/sound/seq_virmidi.h +++ b/include/sound/seq_virmidi.h @@ -36,12 +36,11 @@ struct snd_virmidi { int seq_mode; int client; int port; - bool trigger; + unsigned int trigger: 1; struct snd_midi_event *parser; struct snd_seq_event event; struct snd_virmidi_dev *rdev; struct snd_rawmidi_substream *substream; - struct work_struct output_work; }; #define SNDRV_VIRMIDI_SUBSCRIBE (1<<0) diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index d970879944fc..58acd00cae19 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -102,8 +102,6 @@ struct snd_compr_stream; SNDRV_PCM_FMTBIT_S16_BE |\ SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S20_3BE |\ - SNDRV_PCM_FMTBIT_S20_LE |\ - SNDRV_PCM_FMTBIT_S20_BE |\ SNDRV_PCM_FMTBIT_S24_3LE |\ SNDRV_PCM_FMTBIT_S24_3BE |\ SNDRV_PCM_FMTBIT_S32_LE |\ diff --git a/include/uapi/linux/usb/audio.h b/include/uapi/linux/usb/audio.h index 77b0748b71e3..19f9dc2c06f6 100644 --- a/include/uapi/linux/usb/audio.h +++ b/include/uapi/linux/usb/audio.h @@ -26,7 +26,6 @@ /* bInterfaceProtocol values to denote the version of the standard used */ #define UAC_VERSION_1 0x00 #define UAC_VERSION_2 0x20 -#define UAC_VERSION_3 0x30 /* A.2 Audio Interface Subclass Codes */ #define USB_SUBCLASS_AUDIOCONTROL 0x01 @@ -229,14 +228,6 @@ struct uac1_output_terminal_descriptor { #define UAC_OUTPUT_TERMINAL_COMMUNICATION_SPEAKER 0x306 #define UAC_OUTPUT_TERMINAL_LOW_FREQ_EFFECTS_SPEAKER 0x307 -/* Terminals - 2.4 Bi-directional Terminal Types */ -#define UAC_BIDIR_TERMINAL_UNDEFINED 0x400 -#define UAC_BIDIR_TERMINAL_HANDSET 0x401 -#define UAC_BIDIR_TERMINAL_HEADSET 0x402 -#define UAC_BIDIR_TERMINAL_SPEAKER_PHONE 0x403 -#define UAC_BIDIR_TERMINAL_ECHO_SUPPRESSING 0x404 -#define UAC_BIDIR_TERMINAL_ECHO_CANCELING 0x405 - /* Set bControlSize = 2 as default setting */ #define UAC_DT_FEATURE_UNIT_SIZE(ch) (7 + ((ch) + 1) * 2) @@ -292,22 +283,9 @@ static inline __u8 uac_mixer_unit_iChannelNames(struct uac_mixer_unit_descriptor static inline __u8 *uac_mixer_unit_bmControls(struct uac_mixer_unit_descriptor *desc, int protocol) { - switch (protocol) { - case UAC_VERSION_1: - return &desc->baSourceID[desc->bNrInPins + 4]; - case UAC_VERSION_2: - return &desc->baSourceID[desc->bNrInPins + 6]; - case UAC_VERSION_3: - return &desc->baSourceID[desc->bNrInPins + 2]; - default: - return NULL; - } -} - -static inline __u16 uac3_mixer_unit_wClusterDescrID(struct uac_mixer_unit_descriptor *desc) -{ - return (desc->baSourceID[desc->bNrInPins + 1] << 8) | - desc->baSourceID[desc->bNrInPins]; + return (protocol == UAC_VERSION_1) ? + &desc->baSourceID[desc->bNrInPins + 4] : + &desc->baSourceID[desc->bNrInPins + 6]; } static inline __u8 uac_mixer_unit_iMixer(struct uac_mixer_unit_descriptor *desc) @@ -355,7 +333,7 @@ struct uac_processing_unit_descriptor { __u8 bDescriptorType; __u8 bDescriptorSubtype; __u8 bUnitID; - __le16 wProcessType; + __u16 wProcessType; __u8 bNrInPins; __u8 baSourceID[]; } __attribute__ ((packed)); @@ -389,64 +367,33 @@ static inline __u8 uac_processing_unit_iChannelNames(struct uac_processing_unit_ static inline __u8 uac_processing_unit_bControlSize(struct uac_processing_unit_descriptor *desc, int protocol) { - switch (protocol) { - case UAC_VERSION_1: - return desc->baSourceID[desc->bNrInPins + 4]; - case UAC_VERSION_2: - return 2; /* in UAC2, this value is constant */ - case UAC_VERSION_3: - return 4; /* in UAC3, this value is constant */ - default: - return 1; - } + return (protocol == UAC_VERSION_1) ? + desc->baSourceID[desc->bNrInPins + 4] : + 2; /* in UAC2, this value is constant */ } static inline __u8 *uac_processing_unit_bmControls(struct uac_processing_unit_descriptor *desc, int protocol) { - switch (protocol) { - case UAC_VERSION_1: - return &desc->baSourceID[desc->bNrInPins + 5]; - case UAC_VERSION_2: - return &desc->baSourceID[desc->bNrInPins + 6]; - case UAC_VERSION_3: - return &desc->baSourceID[desc->bNrInPins + 2]; - default: - return NULL; - } + return (protocol == UAC_VERSION_1) ? + &desc->baSourceID[desc->bNrInPins + 5] : + &desc->baSourceID[desc->bNrInPins + 6]; } static inline __u8 uac_processing_unit_iProcessing(struct uac_processing_unit_descriptor *desc, int protocol) { __u8 control_size = uac_processing_unit_bControlSize(desc, protocol); - - switch (protocol) { - case UAC_VERSION_1: - case UAC_VERSION_2: - default: - return *(uac_processing_unit_bmControls(desc, protocol) - + control_size); - case UAC_VERSION_3: - return 0; /* UAC3 does not have this field */ - } + return *(uac_processing_unit_bmControls(desc, protocol) + + control_size); } static inline __u8 *uac_processing_unit_specific(struct uac_processing_unit_descriptor *desc, int protocol) { __u8 control_size = uac_processing_unit_bControlSize(desc, protocol); - - switch (protocol) { - case UAC_VERSION_1: - case UAC_VERSION_2: - default: - return uac_processing_unit_bmControls(desc, protocol) + return uac_processing_unit_bmControls(desc, protocol) + control_size + 1; - case UAC_VERSION_3: - return uac_processing_unit_bmControls(desc, protocol) - + control_size; - } } /* 4.5.2 Class-Specific AS Interface Descriptor */ @@ -544,8 +491,8 @@ struct uac_format_type_ii_ext_descriptor { __u8 bDescriptorType; __u8 bDescriptorSubtype; __u8 bFormatType; - __le16 wMaxBitRate; - __le16 wSamplesPerFrame; + __u16 wMaxBitRate; + __u16 wSamplesPerFrame; __u8 bHeaderLength; __u8 bSideBandProtocol; } __attribute__((packed)); diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index ae51aaf11e10..67a839a12e3c 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -152,7 +152,7 @@ struct snd_hwdep_dsp_image { * * *****************************************************************************/ -#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 14) +#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 13) typedef unsigned long snd_pcm_uframes_t; typedef signed long snd_pcm_sframes_t; @@ -213,11 +213,6 @@ typedef int __bitwise snd_pcm_format_t; #define SNDRV_PCM_FORMAT_IMA_ADPCM ((__force snd_pcm_format_t) 22) #define SNDRV_PCM_FORMAT_MPEG ((__force snd_pcm_format_t) 23) #define SNDRV_PCM_FORMAT_GSM ((__force snd_pcm_format_t) 24) -#define SNDRV_PCM_FORMAT_S20_LE ((__force snd_pcm_format_t) 25) /* in four bytes, LSB justified */ -#define SNDRV_PCM_FORMAT_S20_BE ((__force snd_pcm_format_t) 26) /* in four bytes, LSB justified */ -#define SNDRV_PCM_FORMAT_U20_LE ((__force snd_pcm_format_t) 27) /* in four bytes, LSB justified */ -#define SNDRV_PCM_FORMAT_U20_BE ((__force snd_pcm_format_t) 28) /* in four bytes, LSB justified */ -/* gap in the numbering for a future standard linear format */ #define SNDRV_PCM_FORMAT_SPECIAL ((__force snd_pcm_format_t) 31) #define SNDRV_PCM_FORMAT_S24_3LE ((__force snd_pcm_format_t) 32) /* in three bytes */ #define SNDRV_PCM_FORMAT_S24_3BE ((__force snd_pcm_format_t) 33) /* in three bytes */ @@ -252,8 +247,6 @@ typedef int __bitwise snd_pcm_format_t; #define SNDRV_PCM_FORMAT_FLOAT SNDRV_PCM_FORMAT_FLOAT_LE #define SNDRV_PCM_FORMAT_FLOAT64 SNDRV_PCM_FORMAT_FLOAT64_LE #define SNDRV_PCM_FORMAT_IEC958_SUBFRAME SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE -#define SNDRV_PCM_FORMAT_S20 SNDRV_PCM_FORMAT_S20_LE -#define SNDRV_PCM_FORMAT_U20 SNDRV_PCM_FORMAT_U20_LE #endif #ifdef SNDRV_BIG_ENDIAN #define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_BE @@ -265,8 +258,6 @@ typedef int __bitwise snd_pcm_format_t; #define SNDRV_PCM_FORMAT_FLOAT SNDRV_PCM_FORMAT_FLOAT_BE #define SNDRV_PCM_FORMAT_FLOAT64 SNDRV_PCM_FORMAT_FLOAT64_BE #define SNDRV_PCM_FORMAT_IEC958_SUBFRAME SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE -#define SNDRV_PCM_FORMAT_S20 SNDRV_PCM_FORMAT_S20_BE -#define SNDRV_PCM_FORMAT_U20 SNDRV_PCM_FORMAT_U20_BE #endif typedef int __bitwise snd_pcm_subformat_t; @@ -277,7 +268,6 @@ typedef int __bitwise snd_pcm_subformat_t; #define SNDRV_PCM_INFO_MMAP_VALID 0x00000002 /* period data are valid during transfer */ #define SNDRV_PCM_INFO_DOUBLE 0x00000004 /* Double buffering needed for PCM start/stop */ #define SNDRV_PCM_INFO_BATCH 0x00000010 /* double buffering */ -#define SNDRV_PCM_INFO_SYNC_APPLPTR 0x00000020 /* need the explicit sync of appl_ptr update */ #define SNDRV_PCM_INFO_INTERLEAVED 0x00000100 /* channels are interleaved */ #define SNDRV_PCM_INFO_NONINTERLEAVED 0x00000200 /* channels are not interleaved */ #define SNDRV_PCM_INFO_COMPLEX 0x00000400 /* complex frame organization (mmap only) */ @@ -573,7 +563,6 @@ enum { #define SNDRV_PCM_IOCTL_INFO _IOR('A', 0x01, struct snd_pcm_info) #define SNDRV_PCM_IOCTL_TSTAMP _IOW('A', 0x02, int) #define SNDRV_PCM_IOCTL_TTSTAMP _IOW('A', 0x03, int) -#define SNDRV_PCM_IOCTL_USER_PVERSION _IOW('A', 0x04, int) #define SNDRV_PCM_IOCTL_HW_REFINE _IOWR('A', 0x10, struct snd_pcm_hw_params) #define SNDRV_PCM_IOCTL_HW_PARAMS _IOWR('A', 0x11, struct snd_pcm_hw_params) #define SNDRV_PCM_IOCTL_HW_FREE _IO('A', 0x12) diff --git a/sound/aoa/codecs/tas.c b/sound/aoa/codecs/tas.c index 733b6365dad6..78ed1ffbf786 100644 --- a/sound/aoa/codecs/tas.c +++ b/sound/aoa/codecs/tas.c @@ -271,7 +271,7 @@ static int tas_snd_vol_put(struct snd_kcontrol *kcontrol, return 1; } -static const struct snd_kcontrol_new volume_control = { +static struct snd_kcontrol_new volume_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Volume", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, @@ -314,7 +314,7 @@ static int tas_snd_mute_put(struct snd_kcontrol *kcontrol, return 1; } -static const struct snd_kcontrol_new mute_control = { +static struct snd_kcontrol_new mute_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, @@ -426,7 +426,7 @@ static int tas_snd_drc_range_put(struct snd_kcontrol *kcontrol, return 1; } -static const struct snd_kcontrol_new drc_range_control = { +static struct snd_kcontrol_new drc_range_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "DRC Range", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, @@ -466,7 +466,7 @@ static int tas_snd_drc_switch_put(struct snd_kcontrol *kcontrol, return 1; } -static const struct snd_kcontrol_new drc_switch_control = { +static struct snd_kcontrol_new drc_switch_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "DRC Range Switch", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, @@ -524,7 +524,7 @@ static int tas_snd_capture_source_put(struct snd_kcontrol *kcontrol, return 1; } -static const struct snd_kcontrol_new capture_source_control = { +static struct snd_kcontrol_new capture_source_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* If we name this 'Input Source', it properly shows up in * alsamixer as a selection, * but it's shown under the @@ -586,7 +586,7 @@ static int tas_snd_treble_put(struct snd_kcontrol *kcontrol, return 1; } -static const struct snd_kcontrol_new treble_control = { +static struct snd_kcontrol_new treble_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Treble", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, @@ -637,7 +637,7 @@ static int tas_snd_bass_put(struct snd_kcontrol *kcontrol, return 1; } -static const struct snd_kcontrol_new bass_control = { +static struct snd_kcontrol_new bass_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Bass", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, diff --git a/sound/aoa/fabrics/layout.c b/sound/aoa/fabrics/layout.c index 1eddf8fa188f..a0c4a5de809c 100644 --- a/sound/aoa/fabrics/layout.c +++ b/sound/aoa/fabrics/layout.c @@ -707,7 +707,7 @@ static int detect_choice_put(struct snd_kcontrol *kcontrol, return 1; } -static const struct snd_kcontrol_new headphone_detect_choice = { +static struct snd_kcontrol_new headphone_detect_choice = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Headphone Detect Autoswitch", .info = control_info, @@ -717,7 +717,7 @@ static const struct snd_kcontrol_new headphone_detect_choice = { .private_value = 0, }; -static const struct snd_kcontrol_new lineout_detect_choice = { +static struct snd_kcontrol_new lineout_detect_choice = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Line-Out Detect Autoswitch", .info = control_info, @@ -749,7 +749,7 @@ static int detected_get(struct snd_kcontrol *kcontrol, return 0; } -static const struct snd_kcontrol_new headphone_detected = { +static struct snd_kcontrol_new headphone_detected = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Headphone Detected", .info = control_info, @@ -758,7 +758,7 @@ static const struct snd_kcontrol_new headphone_detected = { .private_value = 0, }; -static const struct snd_kcontrol_new lineout_detected = { +static struct snd_kcontrol_new lineout_detected = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Line-Out Detected", .info = control_info, diff --git a/sound/core/Kconfig b/sound/core/Kconfig index 6e937a8146a1..9749f9e8b45c 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -18,12 +18,8 @@ config SND_DMAENGINE_PCM config SND_HWDEP tristate -config SND_SEQ_DEVICE - tristate - config SND_RAWMIDI tristate - select SND_SEQ_DEVICE if SND_SEQUENCER != n config SND_COMPRESS_OFFLOAD tristate @@ -37,15 +33,38 @@ config SND_JACK_INPUT_DEV depends on SND_JACK default y if INPUT=y || INPUT=SND +config SND_SEQUENCER + tristate "Sequencer support" + select SND_TIMER + help + Say Y or M to enable MIDI sequencer and router support. This + feature allows routing and enqueueing of MIDI events. Events + can be processed at a given time. + + Many programs require this feature, so you should enable it + unless you know what you're doing. + +config SND_SEQ_DUMMY + tristate "Sequencer dummy client" + depends on SND_SEQUENCER + help + Say Y here to enable the dummy sequencer client. This client + is a simple MIDI-through client: all normal input events are + redirected to the output port immediately. + + You don't need this unless you want to connect many MIDI + devices or applications together. + + To compile this driver as a module, choose M here: the module + will be called snd-seq-dummy. + config SND_OSSEMUL - bool "Enable OSS Emulation" select SOUND_OSS_CORE - help - This option enables the build of OSS emulation layer. + bool config SND_MIXER_OSS tristate "OSS Mixer API" - depends on SND_OSSEMUL + select SND_OSSEMUL help To enable OSS mixer API emulation (/dev/mixer*), say Y here and read <file:Documentation/sound/alsa/OSS-Emulation.txt>. @@ -57,7 +76,7 @@ config SND_MIXER_OSS config SND_PCM_OSS tristate "OSS PCM (digital audio) API" - depends on SND_OSSEMUL + select SND_OSSEMUL select SND_PCM help To enable OSS digital audio (PCM) emulation (/dev/dsp*), say Y @@ -88,6 +107,20 @@ config SND_PCM_TIMER For some embedded devices, we may disable it to reduce memory footprint, about 20KB on x86_64 platform. +config SND_SEQUENCER_OSS + bool "OSS Sequencer API" + depends on SND_SEQUENCER + select SND_OSSEMUL + help + Say Y here to enable OSS sequencer emulation (both + /dev/sequencer and /dev/music interfaces). + + Many programs still use the OSS API, so say Y. + + If you choose M in "Sequencer support" (SND_SEQUENCER), + this will be compiled as a module. The module will be called + snd-seq-oss. + config SND_HRTIMER tristate "HR-timer backend support" depends on HIGH_RES_TIMERS @@ -100,6 +133,14 @@ config SND_HRTIMER To compile this driver as a module, choose M here: the module will be called snd-hrtimer. +config SND_SEQ_HRTIMER_DEFAULT + bool "Use HR-timer as default sequencer timer" + depends on SND_HRTIMER && SND_SEQUENCER + default y + help + Say Y here to use the HR-timer backend as the default sequencer + timer. + config SND_DYNAMIC_MINORS bool "Dynamic device file minor numbers" help diff --git a/sound/core/Makefile b/sound/core/Makefile index e2066e2ef9f8..e85d9dd12c2d 100644 --- a/sound/core/Makefile +++ b/sound/core/Makefile @@ -22,7 +22,6 @@ snd-pcm-$(CONFIG_SND_PCM_IEC958) += pcm_iec958.o # for trace-points CFLAGS_pcm_lib.o := -I$(src) -CFLAGS_pcm_native.o := -I$(src) snd-pcm-dmaengine-objs := pcm_dmaengine.o @@ -31,7 +30,6 @@ snd-timer-objs := timer.o snd-hrtimer-objs := hrtimer.o snd-rtctimer-objs := rtctimer.o snd-hwdep-objs := hwdep.o -snd-seq-device-objs := seq_device.o snd-compress-objs := compress_offload.o @@ -41,7 +39,6 @@ obj-$(CONFIG_SND_TIMER) += snd-timer.o obj-$(CONFIG_SND_HRTIMER) += snd-hrtimer.o obj-$(CONFIG_SND_PCM) += snd-pcm.o obj-$(CONFIG_SND_DMAENGINE_PCM) += snd-pcm-dmaengine.o -obj-$(CONFIG_SND_SEQ_DEVICE) += snd-seq-device.o obj-$(CONFIG_SND_RAWMIDI) += snd-rawmidi.o obj-$(CONFIG_SND_OSSEMUL) += oss/ diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index 809d220f08e5..4490a699030b 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -1160,6 +1160,18 @@ int snd_compress_deregister(struct snd_compr *device) } EXPORT_SYMBOL_GPL(snd_compress_deregister); +static int __init snd_compress_init(void) +{ + return 0; +} + +static void __exit snd_compress_exit(void) +{ +} + +module_init(snd_compress_init); +module_exit(snd_compress_exit); + MODULE_DESCRIPTION("ALSA Compressed offload framework"); MODULE_AUTHOR("Vinod Koul <vinod.koul@linux.intel.com>"); MODULE_LICENSE("GPL v2"); diff --git a/sound/core/control.c b/sound/core/control.c index f0f69aa2f26e..5a097cd149c3 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -104,7 +104,7 @@ static void snd_ctl_empty_read_queue(struct snd_ctl_file * ctl) { unsigned long flags; struct snd_kctl_event *cread; - + spin_lock_irqsave(&ctl->read_lock, flags); while (!list_empty(&ctl->events)) { cread = snd_kctl_event(ctl->events.next); @@ -158,7 +158,7 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask, unsigned long flags; struct snd_ctl_file *ctl; struct snd_kctl_event *ev; - + if (snd_BUG_ON(!card || !id)) return; if (card->shutdown) @@ -212,7 +212,7 @@ static int snd_ctl_new(struct snd_kcontrol **kctl, unsigned int count, { unsigned int size; unsigned int idx; - + if (count == 0 || count > MAX_CONTROL_COUNT) return -EINVAL; @@ -237,7 +237,7 @@ static int snd_ctl_new(struct snd_kcontrol **kctl, unsigned int count, * @ncontrol: the initialization record * @private_data: the private data to set * - * Allocates a new struct snd_kcontrol instance and initialize from the given + * Allocates a new struct snd_kcontrol instance and initialize from the given * template. When the access field of ncontrol is 0, it's assumed as * READWRITE access. When the count field is 0, it's assumes as one. * @@ -250,7 +250,7 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol, unsigned int count; unsigned int access; int err; - + if (snd_BUG_ON(!ncontrol || !ncontrol->info)) return NULL; @@ -347,41 +347,22 @@ static int snd_ctl_find_hole(struct snd_card *card, unsigned int count) return 0; } -enum snd_ctl_add_mode { - CTL_ADD_EXCLUSIVE, CTL_REPLACE, CTL_ADD_ON_REPLACE, -}; - -/* add/replace a new kcontrol object; call with card->controls_rwsem locked */ -static int __snd_ctl_add_replace(struct snd_card *card, - struct snd_kcontrol *kcontrol, - enum snd_ctl_add_mode mode) +/* add a new kcontrol object; call with card->controls_rwsem locked */ +static int __snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) { struct snd_ctl_elem_id id; unsigned int idx; unsigned int count; - struct snd_kcontrol *old; - int err; id = kcontrol->id; if (id.index > UINT_MAX - kcontrol->count) return -EINVAL; - old = snd_ctl_find_id(card, &id); - if (!old) { - if (mode == CTL_REPLACE) - return -EINVAL; - } else { - if (mode == CTL_ADD_EXCLUSIVE) { - dev_err(card->dev, - "control %i:%i:%i:%s:%i is already present\n", - id.iface, id.device, id.subdevice, id.name, - id.index); - return -EBUSY; - } - - err = snd_ctl_remove(card, old); - if (err < 0) - return err; + if (snd_ctl_find_id(card, &id)) { + dev_err(card->dev, + "control %i:%i:%i:%s:%i is already present\n", + id.iface, id.device, id.subdevice, id.name, id.index); + return -EBUSY; } if (snd_ctl_find_hole(card, kcontrol->count) < 0) @@ -400,9 +381,21 @@ static int __snd_ctl_add_replace(struct snd_card *card, return 0; } -static int snd_ctl_add_replace(struct snd_card *card, - struct snd_kcontrol *kcontrol, - enum snd_ctl_add_mode mode) +/** + * snd_ctl_add - add the control instance to the card + * @card: the card instance + * @kcontrol: the control instance to add + * + * Adds the control instance created via snd_ctl_new() or + * snd_ctl_new1() to the given card. Assigns also an unique + * numid used for fast search. + * + * It frees automatically the control which cannot be added. + * + * Return: Zero if successful, or a negative error code on failure. + * + */ +int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) { int err = -EINVAL; @@ -412,7 +405,7 @@ static int snd_ctl_add_replace(struct snd_card *card, goto error; down_write(&card->controls_rwsem); - err = __snd_ctl_add_replace(card, kcontrol, mode); + err = __snd_ctl_add(card, kcontrol); up_write(&card->controls_rwsem); if (err < 0) goto error; @@ -422,25 +415,6 @@ static int snd_ctl_add_replace(struct snd_card *card, snd_ctl_free_one(kcontrol); return err; } - -/** - * snd_ctl_add - add the control instance to the card - * @card: the card instance - * @kcontrol: the control instance to add - * - * Adds the control instance created via snd_ctl_new() or - * snd_ctl_new1() to the given card. Assigns also an unique - * numid used for fast search. - * - * It frees automatically the control which cannot be added. - * - * Return: Zero if successful, or a negative error code on failure. - * - */ -int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) -{ - return snd_ctl_add_replace(card, kcontrol, CTL_ADD_EXCLUSIVE); -} EXPORT_SYMBOL(snd_ctl_add); /** @@ -460,8 +434,53 @@ EXPORT_SYMBOL(snd_ctl_add); int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol, bool add_on_replace) { - return snd_ctl_add_replace(card, kcontrol, - add_on_replace ? CTL_ADD_ON_REPLACE : CTL_REPLACE); + struct snd_ctl_elem_id id; + unsigned int count; + unsigned int idx; + struct snd_kcontrol *old; + int ret; + + if (!kcontrol) + return -EINVAL; + if (snd_BUG_ON(!card || !kcontrol->info)) { + ret = -EINVAL; + goto error; + } + id = kcontrol->id; + down_write(&card->controls_rwsem); + old = snd_ctl_find_id(card, &id); + if (!old) { + if (add_on_replace) + goto add; + up_write(&card->controls_rwsem); + ret = -EINVAL; + goto error; + } + ret = snd_ctl_remove(card, old); + if (ret < 0) { + up_write(&card->controls_rwsem); + goto error; + } +add: + if (snd_ctl_find_hole(card, kcontrol->count) < 0) { + up_write(&card->controls_rwsem); + ret = -ENOMEM; + goto error; + } + list_add_tail(&kcontrol->list, &card->controls); + card->controls_count += kcontrol->count; + kcontrol->id.numid = card->last_numid + 1; + card->last_numid += kcontrol->count; + id = kcontrol->id; + count = kcontrol->count; + up_write(&card->controls_rwsem); + for (idx = 0; idx < count; idx++, id.index++, id.numid++) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id); + return 0; + +error: + snd_ctl_free_one(kcontrol); + return ret; } EXPORT_SYMBOL(snd_ctl_replace); @@ -735,45 +754,65 @@ static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl, static int snd_ctl_elem_list(struct snd_card *card, struct snd_ctl_elem_list __user *_list) { + struct list_head *plist; struct snd_ctl_elem_list list; struct snd_kcontrol *kctl; - struct snd_ctl_elem_id id; + struct snd_ctl_elem_id *dst, *id; unsigned int offset, space, jidx; - int err = 0; - + if (copy_from_user(&list, _list, sizeof(list))) return -EFAULT; offset = list.offset; space = list.space; - - down_read(&card->controls_rwsem); - list.count = card->controls_count; - list.used = 0; + /* try limit maximum space */ + if (space > 16384) + return -ENOMEM; if (space > 0) { - list_for_each_entry(kctl, &card->controls, list) { - if (offset >= kctl->count) { - offset -= kctl->count; - continue; - } - for (jidx = offset; jidx < kctl->count; jidx++) { - snd_ctl_build_ioff(&id, kctl, jidx); - if (copy_to_user(list.pids + list.used, &id, - sizeof(id))) { - err = -EFAULT; - goto out; - } + /* allocate temporary buffer for atomic operation */ + dst = vmalloc(space * sizeof(struct snd_ctl_elem_id)); + if (dst == NULL) + return -ENOMEM; + down_read(&card->controls_rwsem); + list.count = card->controls_count; + plist = card->controls.next; + while (plist != &card->controls) { + if (offset == 0) + break; + kctl = snd_kcontrol(plist); + if (offset < kctl->count) + break; + offset -= kctl->count; + plist = plist->next; + } + list.used = 0; + id = dst; + while (space > 0 && plist != &card->controls) { + kctl = snd_kcontrol(plist); + for (jidx = offset; space > 0 && jidx < kctl->count; jidx++) { + snd_ctl_build_ioff(id, kctl, jidx); + id++; + space--; list.used++; - if (!--space) - goto out; } + plist = plist->next; offset = 0; } + up_read(&card->controls_rwsem); + if (list.used > 0 && + copy_to_user(list.pids, dst, + list.used * sizeof(struct snd_ctl_elem_id))) { + vfree(dst); + return -EFAULT; + } + vfree(dst); + } else { + down_read(&card->controls_rwsem); + list.count = card->controls_count; + up_read(&card->controls_rwsem); } - out: - up_read(&card->controls_rwsem); - if (!err && copy_to_user(_list, &list, sizeof(list))) - err = -EFAULT; - return err; + if (copy_to_user(_list, &list, sizeof(list))) + return -EFAULT; + return 0; } static bool validate_element_member_dimension(struct snd_ctl_elem_info *info) @@ -814,7 +853,7 @@ static int snd_ctl_elem_info(struct snd_ctl_file *ctl, struct snd_kcontrol_volatile *vd; unsigned int index_offset; int result; - + down_read(&card->controls_rwsem); kctl = snd_ctl_find_id(card, &info->id); if (kctl == NULL) { @@ -852,14 +891,14 @@ static int snd_ctl_elem_info_user(struct snd_ctl_file *ctl, if (copy_from_user(&info, _info, sizeof(info))) return -EFAULT; + snd_power_lock(ctl->card); result = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0); - if (result < 0) - return result; - result = snd_ctl_elem_info(ctl, &info); - if (result < 0) - return result; - if (copy_to_user(_info, &info, sizeof(info))) - return -EFAULT; + if (result >= 0) + result = snd_ctl_elem_info(ctl, &info); + snd_power_unlock(ctl->card); + if (result >= 0) + if (copy_to_user(_info, &info, sizeof(info))) + return -EFAULT; return result; } @@ -869,18 +908,24 @@ static int snd_ctl_elem_read(struct snd_card *card, struct snd_kcontrol *kctl; struct snd_kcontrol_volatile *vd; unsigned int index_offset; + int result; + down_read(&card->controls_rwsem); kctl = snd_ctl_find_id(card, &control->id); - if (kctl == NULL) - return -ENOENT; - - index_offset = snd_ctl_get_ioff(kctl, &control->id); - vd = &kctl->vd[index_offset]; - if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) || kctl->get == NULL) - return -EPERM; - - snd_ctl_build_ioff(&control->id, kctl, index_offset); - return kctl->get(kctl, control); + if (kctl == NULL) { + result = -ENOENT; + } else { + index_offset = snd_ctl_get_ioff(kctl, &control->id); + vd = &kctl->vd[index_offset]; + if ((vd->access & SNDRV_CTL_ELEM_ACCESS_READ) && + kctl->get != NULL) { + snd_ctl_build_ioff(&control->id, kctl, index_offset); + result = kctl->get(kctl, control); + } else + result = -EPERM; + } + up_read(&card->controls_rwsem); + return result; } static int snd_ctl_elem_read_user(struct snd_card *card, @@ -893,19 +938,14 @@ static int snd_ctl_elem_read_user(struct snd_card *card, if (IS_ERR(control)) return PTR_ERR(control); + snd_power_lock(card); result = snd_power_wait(card, SNDRV_CTL_POWER_D0); - if (result < 0) - goto error; - - down_read(&card->controls_rwsem); - result = snd_ctl_elem_read(card, control); - up_read(&card->controls_rwsem); - if (result < 0) - goto error; - - if (copy_to_user(_control, control, sizeof(*control))) - result = -EFAULT; - error: + if (result >= 0) + result = snd_ctl_elem_read(card, control); + snd_power_unlock(card); + if (result >= 0) + if (copy_to_user(_control, control, sizeof(*control))) + result = -EFAULT; kfree(control); return result; } @@ -918,28 +958,30 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, unsigned int index_offset; int result; + down_read(&card->controls_rwsem); kctl = snd_ctl_find_id(card, &control->id); - if (kctl == NULL) - return -ENOENT; - - index_offset = snd_ctl_get_ioff(kctl, &control->id); - vd = &kctl->vd[index_offset]; - if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_WRITE) || kctl->put == NULL || - (file && vd->owner && vd->owner != file)) { - return -EPERM; - } - - snd_ctl_build_ioff(&control->id, kctl, index_offset); - result = kctl->put(kctl, control); - if (result < 0) - return result; - - if (result > 0) { - struct snd_ctl_elem_id id = control->id; - snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &id); + if (kctl == NULL) { + result = -ENOENT; + } else { + index_offset = snd_ctl_get_ioff(kctl, &control->id); + vd = &kctl->vd[index_offset]; + if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_WRITE) || + kctl->put == NULL || + (file && vd->owner && vd->owner != file)) { + result = -EPERM; + } else { + snd_ctl_build_ioff(&control->id, kctl, index_offset); + result = kctl->put(kctl, control); + } + if (result > 0) { + struct snd_ctl_elem_id id = control->id; + up_read(&card->controls_rwsem); + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &id); + return 0; + } } - - return 0; + up_read(&card->controls_rwsem); + return result; } static int snd_ctl_elem_write_user(struct snd_ctl_file *file, @@ -954,19 +996,14 @@ static int snd_ctl_elem_write_user(struct snd_ctl_file *file, return PTR_ERR(control); card = file->card; + snd_power_lock(card); result = snd_power_wait(card, SNDRV_CTL_POWER_D0); - if (result < 0) - goto error; - - down_write(&card->controls_rwsem); - result = snd_ctl_elem_write(card, file, control); - up_write(&card->controls_rwsem); - if (result < 0) - goto error; - - if (copy_to_user(_control, control, sizeof(*control))) - result = -EFAULT; - error: + if (result >= 0) + result = snd_ctl_elem_write(card, file, control); + snd_power_unlock(card); + if (result >= 0) + if (copy_to_user(_control, control, sizeof(*control))) + result = -EFAULT; kfree(control); return result; } @@ -979,7 +1016,7 @@ static int snd_ctl_elem_lock(struct snd_ctl_file *file, struct snd_kcontrol *kctl; struct snd_kcontrol_volatile *vd; int result; - + if (copy_from_user(&id, _id, sizeof(id))) return -EFAULT; down_write(&card->controls_rwsem); @@ -1007,7 +1044,7 @@ static int snd_ctl_elem_unlock(struct snd_ctl_file *file, struct snd_kcontrol *kctl; struct snd_kcontrol_volatile *vd; int result; - + if (copy_from_user(&id, _id, sizeof(id))) return -EFAULT; down_write(&card->controls_rwsem); @@ -1085,7 +1122,9 @@ static int snd_ctl_elem_user_get(struct snd_kcontrol *kcontrol, char *src = ue->elem_data + snd_ctl_get_ioff(kcontrol, &ucontrol->id) * size; + mutex_lock(&ue->card->user_ctl_lock); memcpy(&ucontrol->value, src, size); + mutex_unlock(&ue->card->user_ctl_lock); return 0; } @@ -1098,83 +1137,60 @@ static int snd_ctl_elem_user_put(struct snd_kcontrol *kcontrol, char *dst = ue->elem_data + snd_ctl_get_ioff(kcontrol, &ucontrol->id) * size; + mutex_lock(&ue->card->user_ctl_lock); change = memcmp(&ucontrol->value, dst, size) != 0; if (change) memcpy(dst, &ucontrol->value, size); + mutex_unlock(&ue->card->user_ctl_lock); return change; } -static int replace_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf, - unsigned int size) +static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kcontrol, + int op_flag, + unsigned int size, + unsigned int __user *tlv) { - struct user_element *ue = kctl->private_data; - unsigned int *container; - struct snd_ctl_elem_id id; - unsigned int mask = 0; - int i; - int change; - - if (size > 1024 * 128) /* sane value */ - return -EINVAL; - - container = memdup_user(buf, size); - if (IS_ERR(container)) - return PTR_ERR(container); - - change = ue->tlv_data_size != size; - if (!change) - change = memcmp(ue->tlv_data, container, size); - if (!change) { - kfree(container); - return 0; - } + struct user_element *ue = kcontrol->private_data; + int change = 0; + void *new_data; - if (ue->tlv_data == NULL) { - /* Now TLV data is available. */ - for (i = 0; i < kctl->count; ++i) - kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; - mask = SNDRV_CTL_EVENT_MASK_INFO; - } + if (op_flag == SNDRV_CTL_TLV_OP_WRITE) { + if (size > 1024 * 128) /* sane value */ + return -EINVAL; - kfree(ue->tlv_data); - ue->tlv_data = container; - ue->tlv_data_size = size; + new_data = memdup_user(tlv, size); + if (IS_ERR(new_data)) + return PTR_ERR(new_data); + mutex_lock(&ue->card->user_ctl_lock); + change = ue->tlv_data_size != size; + if (!change) + change = memcmp(ue->tlv_data, new_data, size) != 0; + kfree(ue->tlv_data); + ue->tlv_data = new_data; + ue->tlv_data_size = size; + mutex_unlock(&ue->card->user_ctl_lock); + } else { + int ret = 0; - mask |= SNDRV_CTL_EVENT_MASK_TLV; - for (i = 0; i < kctl->count; ++i) { - snd_ctl_build_ioff(&id, kctl, i); - snd_ctl_notify(ue->card, mask, &id); + mutex_lock(&ue->card->user_ctl_lock); + if (!ue->tlv_data_size || !ue->tlv_data) { + ret = -ENXIO; + goto err_unlock; + } + if (size < ue->tlv_data_size) { + ret = -ENOSPC; + goto err_unlock; + } + if (copy_to_user(tlv, ue->tlv_data, ue->tlv_data_size)) + ret = -EFAULT; +err_unlock: + mutex_unlock(&ue->card->user_ctl_lock); + if (ret) + return ret; } - return change; } -static int read_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf, - unsigned int size) -{ - struct user_element *ue = kctl->private_data; - - if (ue->tlv_data_size == 0 || ue->tlv_data == NULL) - return -ENXIO; - - if (size < ue->tlv_data_size) - return -ENOSPC; - - if (copy_to_user(buf, ue->tlv_data, ue->tlv_data_size)) - return -EFAULT; - - return 0; -} - -static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kctl, int op_flag, - unsigned int size, unsigned int __user *buf) -{ - if (op_flag == SNDRV_CTL_TLV_OP_WRITE) - return replace_user_tlv(kctl, buf, size); - else - return read_user_tlv(kctl, buf, size); -} - static int snd_ctl_elem_init_enum_names(struct user_element *ue) { char *names, *p; @@ -1278,10 +1294,8 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, access = SNDRV_CTL_ELEM_ACCESS_READWRITE; access &= (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE | - SNDRV_CTL_ELEM_ACCESS_TLV_WRITE); - - /* In initial state, nothing is available as TLV container. */ - if (access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) + SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE); + if (access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) access |= SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; access |= SNDRV_CTL_ELEM_ACCESS_USER; @@ -1344,12 +1358,12 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, kctl->get = snd_ctl_elem_user_get; if (access & SNDRV_CTL_ELEM_ACCESS_WRITE) kctl->put = snd_ctl_elem_user_put; - if (access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) + if (access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) kctl->tlv.c = snd_ctl_elem_user_tlv; /* This function manage to free the instance on failure. */ down_write(&card->controls_rwsem); - err = __snd_ctl_add_replace(card, kctl, CTL_ADD_EXCLUSIVE); + err = __snd_ctl_add(card, kctl); if (err < 0) { snd_ctl_free_one(kctl); goto unlock; @@ -1421,107 +1435,71 @@ static int snd_ctl_subscribe_events(struct snd_ctl_file *file, int __user *ptr) return 0; } -static int call_tlv_handler(struct snd_ctl_file *file, int op_flag, - struct snd_kcontrol *kctl, - struct snd_ctl_elem_id *id, - unsigned int __user *buf, unsigned int size) -{ - static const struct { - int op; - int perm; - } pairs[] = { - {SNDRV_CTL_TLV_OP_READ, SNDRV_CTL_ELEM_ACCESS_TLV_READ}, - {SNDRV_CTL_TLV_OP_WRITE, SNDRV_CTL_ELEM_ACCESS_TLV_WRITE}, - {SNDRV_CTL_TLV_OP_CMD, SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND}, - }; - struct snd_kcontrol_volatile *vd = &kctl->vd[snd_ctl_get_ioff(kctl, id)]; - int i; - - /* Check support of the request for this element. */ - for (i = 0; i < ARRAY_SIZE(pairs); ++i) { - if (op_flag == pairs[i].op && (vd->access & pairs[i].perm)) - break; - } - if (i == ARRAY_SIZE(pairs)) - return -ENXIO; - - if (kctl->tlv.c == NULL) - return -ENXIO; - - /* When locked, this is unavailable. */ - if (vd->owner != NULL && vd->owner != file) - return -EPERM; - - return kctl->tlv.c(kctl, op_flag, size, buf); -} - -static int read_tlv_buf(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id, - unsigned int __user *buf, unsigned int size) -{ - struct snd_kcontrol_volatile *vd = &kctl->vd[snd_ctl_get_ioff(kctl, id)]; - unsigned int len; - - if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ)) - return -ENXIO; - - if (kctl->tlv.p == NULL) - return -ENXIO; - - len = sizeof(unsigned int) * 2 + kctl->tlv.p[1]; - if (size < len) - return -ENOMEM; - - if (copy_to_user(buf, kctl->tlv.p, len)) - return -EFAULT; - - return 0; -} - static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, - struct snd_ctl_tlv __user *buf, + struct snd_ctl_tlv __user *_tlv, int op_flag) { - struct snd_ctl_tlv header; - unsigned int __user *container; - unsigned int container_size; + struct snd_card *card = file->card; + struct snd_ctl_tlv tlv; struct snd_kcontrol *kctl; - struct snd_ctl_elem_id id; struct snd_kcontrol_volatile *vd; + unsigned int len; + int err = 0; - if (copy_from_user(&header, buf, sizeof(header))) + if (copy_from_user(&tlv, _tlv, sizeof(tlv))) return -EFAULT; - - /* In design of control core, numerical ID starts at 1. */ - if (header.numid == 0) + if (tlv.length < sizeof(unsigned int) * 2) return -EINVAL; - - /* At least, container should include type and length fields. */ - if (header.length < sizeof(unsigned int) * 2) + if (!tlv.numid) return -EINVAL; - container_size = header.length; - container = buf->tlv; - - kctl = snd_ctl_find_numid(file->card, header.numid); - if (kctl == NULL) - return -ENOENT; - - /* Calculate index of the element in this set. */ - id = kctl->id; - snd_ctl_build_ioff(&id, kctl, header.numid - id.numid); - vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)]; - + down_read(&card->controls_rwsem); + kctl = snd_ctl_find_numid(card, tlv.numid); + if (kctl == NULL) { + err = -ENOENT; + goto __kctl_end; + } + if (kctl->tlv.p == NULL) { + err = -ENXIO; + goto __kctl_end; + } + vd = &kctl->vd[tlv.numid - kctl->id.numid]; + if ((op_flag == SNDRV_CTL_TLV_OP_READ && + (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) == 0) || + (op_flag == SNDRV_CTL_TLV_OP_WRITE && + (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) == 0) || + (op_flag == SNDRV_CTL_TLV_OP_CMD && + (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND) == 0)) { + err = -ENXIO; + goto __kctl_end; + } if (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { - return call_tlv_handler(file, op_flag, kctl, &id, container, - container_size); + if (vd->owner != NULL && vd->owner != file) { + err = -EPERM; + goto __kctl_end; + } + err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv); + if (err > 0) { + struct snd_ctl_elem_id id = kctl->id; + up_read(&card->controls_rwsem); + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &id); + return 0; + } } else { - if (op_flag == SNDRV_CTL_TLV_OP_READ) { - return read_tlv_buf(kctl, &id, container, - container_size); + if (op_flag != SNDRV_CTL_TLV_OP_READ) { + err = -ENXIO; + goto __kctl_end; + } + len = kctl->tlv.p[1] + 2 * sizeof(unsigned int); + if (tlv.length < len) { + err = -ENOMEM; + goto __kctl_end; } + if (copy_to_user(_tlv->tlv, kctl->tlv.p, len)) + err = -EFAULT; } - - /* Not supported. */ - return -ENXIO; + __kctl_end: + up_read(&card->controls_rwsem); + return err; } static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) @@ -1563,20 +1541,11 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS: return snd_ctl_subscribe_events(ctl, ip); case SNDRV_CTL_IOCTL_TLV_READ: - down_read(&ctl->card->controls_rwsem); - err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_READ); - up_read(&ctl->card->controls_rwsem); - return err; + return snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_READ); case SNDRV_CTL_IOCTL_TLV_WRITE: - down_write(&ctl->card->controls_rwsem); - err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_WRITE); - up_write(&ctl->card->controls_rwsem); - return err; + return snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_WRITE); case SNDRV_CTL_IOCTL_TLV_COMMAND: - down_write(&ctl->card->controls_rwsem); - err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_CMD); - up_write(&ctl->card->controls_rwsem); - return err; + return snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_CMD); case SNDRV_CTL_IOCTL_POWER: return -ENOPROTOOPT; case SNDRV_CTL_IOCTL_POWER_STATE: diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c index 507fd5210c1c..84ee29c3b1a0 100644 --- a/sound/core/control_compat.c +++ b/sound/core/control_compat.c @@ -111,10 +111,12 @@ static int snd_ctl_elem_info_compat(struct snd_ctl_file *ctl, if (get_user(data->value.enumerated.item, &data32->value.enumerated.item)) goto error; + snd_power_lock(ctl->card); err = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0); - if (err < 0) - goto error; - err = snd_ctl_elem_info(ctl, data); + if (err >= 0) + err = snd_ctl_elem_info(ctl, data); + snd_power_unlock(ctl->card); + if (err < 0) goto error; /* restore info to 32bit */ @@ -313,13 +315,14 @@ static int ctl_elem_read_user(struct snd_card *card, if (err < 0) goto error; + snd_power_lock(card); err = snd_power_wait(card, SNDRV_CTL_POWER_D0); - if (err < 0) - goto error; - err = snd_ctl_elem_read(card, data); - if (err < 0) - goto error; - err = copy_ctl_value_to_user(userdata, valuep, data, type, count); + if (err >= 0) + err = snd_ctl_elem_read(card, data); + snd_power_unlock(card); + if (err >= 0) + err = copy_ctl_value_to_user(userdata, valuep, data, + type, count); error: kfree(data); return err; @@ -341,13 +344,14 @@ static int ctl_elem_write_user(struct snd_ctl_file *file, if (err < 0) goto error; + snd_power_lock(card); err = snd_power_wait(card, SNDRV_CTL_POWER_D0); - if (err < 0) - goto error; - err = snd_ctl_elem_write(card, file, data); - if (err < 0) - goto error; - err = copy_ctl_value_to_user(userdata, valuep, data, type, count); + if (err >= 0) + err = snd_ctl_elem_write(card, file, data); + snd_power_unlock(card); + if (err >= 0) + err = copy_ctl_value_to_user(userdata, valuep, data, + type, count); error: kfree(data); return err; diff --git a/sound/core/ctljack.c b/sound/core/ctljack.c index 0249d5e6ac23..84a3cd683068 100644 --- a/sound/core/ctljack.c +++ b/sound/core/ctljack.c @@ -23,7 +23,7 @@ static int jack_detect_kctl_get(struct snd_kcontrol *kcontrol, return 0; } -static const struct snd_kcontrol_new jack_detect_kctl = { +static struct snd_kcontrol_new jack_detect_kctl = { /* name is filled later */ .iface = SNDRV_CTL_ELEM_IFACE_CARD, .access = SNDRV_CTL_ELEM_ACCESS_READ, diff --git a/sound/core/device.c b/sound/core/device.c index 535102d564e3..12d5cbefd85e 100644 --- a/sound/core/device.c +++ b/sound/core/device.c @@ -128,7 +128,7 @@ void snd_device_disconnect(struct snd_card *card, void *device_data) if (dev) __snd_device_disconnect(dev); else - dev_dbg(card->dev, "device disconnect %p (from %pS), not found\n", + dev_dbg(card->dev, "device disconnect %p (from %pF), not found\n", device_data, __builtin_return_address(0)); } EXPORT_SYMBOL_GPL(snd_device_disconnect); @@ -152,7 +152,7 @@ void snd_device_free(struct snd_card *card, void *device_data) if (dev) __snd_device_free(dev); else - dev_dbg(card->dev, "device free %p (from %pS), not found\n", + dev_dbg(card->dev, "device free %p (from %pF), not found\n", device_data, __builtin_return_address(0)); } EXPORT_SYMBOL(snd_device_free); diff --git a/sound/core/hrtimer.c b/sound/core/hrtimer.c index 18cb6f476bf4..6e47b823bcaa 100644 --- a/sound/core/hrtimer.c +++ b/sound/core/hrtimer.c @@ -127,7 +127,7 @@ static int snd_hrtimer_stop(struct snd_timer *t) return 0; } -static const struct snd_timer_hardware hrtimer_hw __initconst = { +static struct snd_timer_hardware hrtimer_hw = { .flags = SNDRV_TIMER_HW_AUTO | SNDRV_TIMER_HW_TASKLET, .open = snd_hrtimer_open, .close = snd_hrtimer_close, diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index 25b8f2234fc7..a73baa1242be 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c @@ -228,11 +228,11 @@ static int snd_hwdep_dsp_load(struct snd_hwdep *hw, memset(&info, 0, sizeof(info)); if (copy_from_user(&info, _info, sizeof(info))) return -EFAULT; - if (info.index >= 32) - return -EINVAL; /* check whether the dsp was already loaded */ if (hw->dsp_loaded & (1 << info.index)) return -EBUSY; + if (!access_ok(VERIFY_READ, info.image, info.length)) + return -EFAULT; err = hw->ops.dsp_load(hw, &info); if (err < 0) return err; diff --git a/sound/core/info.c b/sound/core/info.c index bcf6a48cc70d..8ab72e0f5932 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -344,12 +344,12 @@ static ssize_t snd_info_text_entry_write(struct file *file, } } if (next > buf->len) { - char *nbuf = kvzalloc(PAGE_ALIGN(next), GFP_KERNEL); + char *nbuf = krealloc(buf->buffer, PAGE_ALIGN(next), + GFP_KERNEL | __GFP_ZERO); if (!nbuf) { err = -ENOMEM; goto error; } - kvfree(buf->buffer); buf->buffer = nbuf; buf->len = PAGE_ALIGN(next); } @@ -427,7 +427,7 @@ static int snd_info_text_entry_release(struct inode *inode, struct file *file) single_release(inode, file); kfree(data->rbuffer); if (data->wbuffer) { - kvfree(data->wbuffer->buffer); + kfree(data->wbuffer->buffer); kfree(data->wbuffer); } @@ -652,6 +652,7 @@ int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len) *line = '\0'; return 0; } + EXPORT_SYMBOL(snd_info_get_line); /** @@ -689,6 +690,7 @@ const char *snd_info_get_str(char *dest, const char *src, int len) src++; return src; } + EXPORT_SYMBOL(snd_info_get_str); /* @@ -746,6 +748,7 @@ struct snd_info_entry *snd_info_create_module_entry(struct module * module, entry->module = module; return entry; } + EXPORT_SYMBOL(snd_info_create_module_entry); /** @@ -769,6 +772,7 @@ struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card, } return entry; } + EXPORT_SYMBOL(snd_info_create_card_entry); static void snd_info_disconnect(struct snd_info_entry *entry) @@ -811,6 +815,7 @@ void snd_info_free_entry(struct snd_info_entry * entry) entry->private_free(entry); kfree(entry); } + EXPORT_SYMBOL(snd_info_free_entry); /** @@ -853,6 +858,7 @@ int snd_info_register(struct snd_info_entry * entry) mutex_unlock(&info_mutex); return 0; } + EXPORT_SYMBOL(snd_info_register); /* diff --git a/sound/core/info_oss.c b/sound/core/info_oss.c index f479374b6bd8..1478c8dfd473 100644 --- a/sound/core/info_oss.c +++ b/sound/core/info_oss.c @@ -61,6 +61,7 @@ int snd_oss_info_register(int dev, int num, char *string) mutex_unlock(&strings); return 0; } + EXPORT_SYMBOL(snd_oss_info_register); static int snd_sndstat_show_strings(struct snd_info_buffer *buf, char *id, int dev) diff --git a/sound/core/init.c b/sound/core/init.c index 4a51a068d42e..d61d2b3cd521 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -248,14 +248,15 @@ int snd_card_new(struct device *parent, int idx, const char *xid, INIT_LIST_HEAD(&card->devices); init_rwsem(&card->controls_rwsem); rwlock_init(&card->ctl_files_rwlock); + mutex_init(&card->user_ctl_lock); INIT_LIST_HEAD(&card->controls); INIT_LIST_HEAD(&card->ctl_files); spin_lock_init(&card->files_lock); INIT_LIST_HEAD(&card->files_list); #ifdef CONFIG_PM + mutex_init(&card->power_lock); init_waitqueue_head(&card->power_sleep); #endif - init_waitqueue_head(&card->remove_sleep); device_initialize(&card->card_dev); card->card_dev.parent = parent; @@ -451,36 +452,8 @@ int snd_card_disconnect(struct snd_card *card) #endif return 0; } -EXPORT_SYMBOL(snd_card_disconnect); - -/** - * snd_card_disconnect_sync - disconnect card and wait until files get closed - * @card: card object to disconnect - * - * This calls snd_card_disconnect() for disconnecting all belonging components - * and waits until all pending files get closed. - * It assures that all accesses from user-space finished so that the driver - * can release its resources gracefully. - */ -void snd_card_disconnect_sync(struct snd_card *card) -{ - int err; - - err = snd_card_disconnect(card); - if (err < 0) { - dev_err(card->dev, - "snd_card_disconnect error (%d), skipping sync\n", - err); - return; - } - spin_lock_irq(&card->files_lock); - wait_event_lock_irq(card->remove_sleep, - list_empty(&card->files_list), - card->files_lock); - spin_unlock_irq(&card->files_lock); -} -EXPORT_SYMBOL_GPL(snd_card_disconnect_sync); +EXPORT_SYMBOL(snd_card_disconnect); static int snd_card_do_free(struct snd_card *card) { @@ -670,7 +643,7 @@ card_id_show_attr(struct device *dev, struct device_attribute *attr, char *buf) { struct snd_card *card = container_of(dev, struct snd_card, card_dev); - return scnprintf(buf, PAGE_SIZE, "%s\n", card->id); + return snprintf(buf, PAGE_SIZE, "%s\n", card->id); } static ssize_t @@ -710,7 +683,7 @@ card_number_show_attr(struct device *dev, struct device_attribute *attr, char *buf) { struct snd_card *card = container_of(dev, struct snd_card, card_dev); - return scnprintf(buf, PAGE_SIZE, "%i\n", card->number); + return snprintf(buf, PAGE_SIZE, "%i\n", card->number); } static DEVICE_ATTR(number, S_IRUGO, card_number_show_attr, NULL); @@ -745,7 +718,7 @@ int snd_card_add_dev_attr(struct snd_card *card, dev_err(card->dev, "Too many groups assigned\n"); return -ENOSPC; -} +}; EXPORT_SYMBOL_GPL(snd_card_add_dev_attr); /** @@ -802,6 +775,7 @@ int snd_card_register(struct snd_card *card) #endif return 0; } + EXPORT_SYMBOL(snd_card_register); #ifdef CONFIG_SND_PROC_FS @@ -921,6 +895,7 @@ int snd_component_add(struct snd_card *card, const char *component) strcat(card->components, component); return 0; } + EXPORT_SYMBOL(snd_component_add); /** @@ -955,6 +930,7 @@ int snd_card_file_add(struct snd_card *card, struct file *file) spin_unlock(&card->files_lock); return 0; } + EXPORT_SYMBOL(snd_card_file_add); /** @@ -987,8 +963,6 @@ int snd_card_file_remove(struct snd_card *card, struct file *file) break; } } - if (list_empty(&card->files_list)) - wake_up_all(&card->remove_sleep); spin_unlock(&card->files_lock); if (!found) { dev_err(card->dev, "card file remove problem (%p)\n", file); @@ -998,6 +972,7 @@ int snd_card_file_remove(struct snd_card *card, struct file *file) put_device(&card->card_dev); return 0; } + EXPORT_SYMBOL(snd_card_file_remove); #ifdef CONFIG_PM @@ -1009,6 +984,8 @@ EXPORT_SYMBOL(snd_card_file_remove); * Waits until the power-state is changed. * * Return: Zero if successful, or a negative error code. + * + * Note: the power lock must be active before call. */ int snd_power_wait(struct snd_card *card, unsigned int power_state) { @@ -1028,10 +1005,13 @@ int snd_power_wait(struct snd_card *card, unsigned int power_state) if (snd_power_get_state(card) == power_state) break; set_current_state(TASK_UNINTERRUPTIBLE); + snd_power_unlock(card); schedule_timeout(30 * HZ); + snd_power_lock(card); } remove_wait_queue(&card->power_sleep, &wait); return result; } + EXPORT_SYMBOL(snd_power_wait); #endif /* CONFIG_PM */ diff --git a/sound/core/isadma.c b/sound/core/isadma.c index 7a8515abb5f9..31e8544d7f2d 100644 --- a/sound/core/isadma.c +++ b/sound/core/isadma.c @@ -55,6 +55,7 @@ void snd_dma_program(unsigned long dma, enable_dma(dma); release_dma_lock(flags); } + EXPORT_SYMBOL(snd_dma_program); /** @@ -72,6 +73,7 @@ void snd_dma_disable(unsigned long dma) disable_dma(dma); release_dma_lock(flags); } + EXPORT_SYMBOL(snd_dma_disable); /** @@ -111,4 +113,5 @@ unsigned int snd_dma_pointer(unsigned long dma, unsigned int size) else return size - result; } + EXPORT_SYMBOL(snd_dma_pointer); diff --git a/sound/core/jack.c b/sound/core/jack.c index 84c2a17c56ee..f652e90efd7e 100644 --- a/sound/core/jack.c +++ b/sound/core/jack.c @@ -310,7 +310,7 @@ EXPORT_SYMBOL(snd_jack_set_parent); * @type: Jack report type for this key * @keytype: Input layer key type to be reported * - * Map a SND_JACK_BTN_* button type to an input layer key, allowing + * Map a SND_JACK_BTN_ button type to an input layer key, allowing * reporting of keys on accessories via the jack abstraction. If no * mapping is provided but keys are enabled in the jack type then * BTN_n numeric buttons will be reported. diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index 59a4adc286ed..bb50e0e2a1b5 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -57,7 +57,6 @@ void *snd_malloc_pages(size_t size, gfp_t gfp_flags) pg = get_order(size); return (void *) __get_free_pages(gfp_flags, pg); } -EXPORT_SYMBOL(snd_malloc_pages); /** * snd_free_pages - release the pages @@ -75,7 +74,6 @@ void snd_free_pages(void *ptr, size_t size) pg = get_order(size); free_pages((unsigned long) ptr, pg); } -EXPORT_SYMBOL(snd_free_pages); /* * @@ -226,7 +224,6 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size, dmab->bytes = size; return 0; } -EXPORT_SYMBOL(snd_dma_alloc_pages); /** * snd_dma_alloc_pages_fallback - allocate the buffer area according to the given type with fallback @@ -260,7 +257,6 @@ int snd_dma_alloc_pages_fallback(int type, struct device *device, size_t size, return -ENOMEM; return 0; } -EXPORT_SYMBOL(snd_dma_alloc_pages_fallback); /** @@ -296,4 +292,13 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab) pr_err("snd-malloc: invalid device type %d\n", dmab->dev.type); } } + +/* + * exports + */ +EXPORT_SYMBOL(snd_dma_alloc_pages); +EXPORT_SYMBOL(snd_dma_alloc_pages_fallback); EXPORT_SYMBOL(snd_dma_free_pages); + +EXPORT_SYMBOL(snd_malloc_pages); +EXPORT_SYMBOL(snd_free_pages); diff --git a/sound/core/memory.c b/sound/core/memory.c index 19c9ea90d9bf..4cd664efad77 100644 --- a/sound/core/memory.c +++ b/sound/core/memory.c @@ -55,6 +55,7 @@ int copy_to_user_fromio(void __user *dst, const volatile void __iomem *src, size return 0; #endif } + EXPORT_SYMBOL(copy_to_user_fromio); /** @@ -87,4 +88,5 @@ int copy_from_user_toio(volatile void __iomem *dst, const void __user *src, size return 0; #endif } + EXPORT_SYMBOL(copy_from_user_toio); diff --git a/sound/core/misc.c b/sound/core/misc.c index 0f818d593c9e..21b228046e88 100644 --- a/sound/core/misc.c +++ b/sound/core/misc.c @@ -48,6 +48,7 @@ void release_and_free_resource(struct resource *res) kfree(res); } } + EXPORT_SYMBOL(release_and_free_resource); #ifdef CONFIG_SND_VERBOSE_PRINTK diff --git a/sound/core/oss/io.c b/sound/core/oss/io.c index d870b2d93135..6faa1d719206 100644 --- a/sound/core/oss/io.c +++ b/sound/core/oss/io.c @@ -26,9 +26,9 @@ #include "pcm_plugin.h" #define pcm_write(plug,buf,count) snd_pcm_oss_write3(plug,buf,count,1) -#define pcm_writev(plug,vec,count) snd_pcm_oss_writev3(plug,vec,count) +#define pcm_writev(plug,vec,count) snd_pcm_oss_writev3(plug,vec,count,1) #define pcm_read(plug,buf,count) snd_pcm_oss_read3(plug,buf,count,1) -#define pcm_readv(plug,vec,count) snd_pcm_oss_readv3(plug,vec,count) +#define pcm_readv(plug,vec,count) snd_pcm_oss_readv3(plug,vec,count,1) /* * Basic io plugin diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index 379bf486ccc7..2ff9c12d664a 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -395,7 +395,6 @@ int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned l fmixer.mixer = card->mixer_oss; return snd_mixer_oss_ioctl1(&fmixer, cmd, arg); } -EXPORT_SYMBOL(snd_mixer_oss_ioctl_card); #ifdef CONFIG_COMPAT /* all compatible */ @@ -1426,3 +1425,5 @@ static void __exit alsa_mixer_oss_exit(void) module_init(alsa_mixer_oss_init) module_exit(alsa_mixer_oss_exit) + +EXPORT_SYMBOL(snd_mixer_oss_ioctl_card); diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index da21ee2e6e38..45ced1d81287 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -67,6 +67,18 @@ static int snd_pcm_oss_get_rate(struct snd_pcm_oss_file *pcm_oss_file); static int snd_pcm_oss_get_channels(struct snd_pcm_oss_file *pcm_oss_file); static int snd_pcm_oss_get_format(struct snd_pcm_oss_file *pcm_oss_file); +static inline mm_segment_t snd_enter_user(void) +{ + mm_segment_t fs = get_fs(); + set_fs(get_ds()); + return fs; +} + +static inline void snd_leave_user(mm_segment_t fs) +{ + set_fs(fs); +} + /* * helper functions to process hw_params */ @@ -186,7 +198,7 @@ static int _snd_pcm_hw_param_mask(struct snd_pcm_hw_params *params, { int changed; changed = snd_mask_refine(hw_param_mask(params, var), val); - if (changed > 0) { + if (changed) { params->cmask |= 1 << var; params->rmask |= 1 << var; } @@ -233,7 +245,7 @@ static int _snd_pcm_hw_param_min(struct snd_pcm_hw_params *params, val, open); else return -EINVAL; - if (changed > 0) { + if (changed) { params->cmask |= 1 << var; params->rmask |= 1 << var; } @@ -294,7 +306,7 @@ static int _snd_pcm_hw_param_max(struct snd_pcm_hw_params *params, val, open); else return -EINVAL; - if (changed > 0) { + if (changed) { params->cmask |= 1 << var; params->rmask |= 1 << var; } @@ -499,7 +511,7 @@ static int _snd_pcm_hw_param_set(struct snd_pcm_hw_params *params, } } else return -EINVAL; - if (changed > 0) { + if (changed) { params->cmask |= 1 << var; params->rmask |= 1 << var; } @@ -539,7 +551,7 @@ static int _snd_pcm_hw_param_setinteger(struct snd_pcm_hw_params *params, { int changed; changed = snd_interval_setinteger(hw_param_interval(params, var)); - if (changed > 0) { + if (changed) { params->cmask |= 1 << var; params->rmask |= 1 << var; } @@ -786,7 +798,7 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream, static int choose_rate(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, unsigned int best_rate) { - const struct snd_interval *it; + struct snd_interval *it; struct snd_pcm_hw_params *save; unsigned int rate, prev; @@ -794,7 +806,7 @@ static int choose_rate(struct snd_pcm_substream *substream, if (save == NULL) return -ENOMEM; *save = *params; - it = hw_param_interval_c(save, SNDRV_PCM_HW_PARAM_RATE); + it = hw_param_interval(save, SNDRV_PCM_HW_PARAM_RATE); /* try multiples of the best rate */ rate = best_rate; @@ -852,7 +864,7 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream) int direct; snd_pcm_format_t format, sformat; int n; - const struct snd_mask *sformat_mask; + struct snd_mask sformat_mask; struct snd_mask mask; if (!runtime->oss.params) @@ -892,18 +904,18 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream) format = snd_pcm_oss_format_from(runtime->oss.format); - sformat_mask = hw_param_mask_c(sparams, SNDRV_PCM_HW_PARAM_FORMAT); + sformat_mask = *hw_param_mask(sparams, SNDRV_PCM_HW_PARAM_FORMAT); if (direct) sformat = format; else - sformat = snd_pcm_plug_slave_format(format, sformat_mask); + sformat = snd_pcm_plug_slave_format(format, &sformat_mask); if ((__force int)sformat < 0 || - !snd_mask_test(sformat_mask, (__force int)sformat)) { + !snd_mask_test(&sformat_mask, (__force int)sformat)) { for (sformat = (__force snd_pcm_format_t)0; (__force int)sformat <= (__force int)SNDRV_PCM_FORMAT_LAST; sformat = (__force snd_pcm_format_t)((__force int)sformat + 1)) { - if (snd_mask_test(sformat_mask, (__force int)sformat) && + if (snd_mask_test(&sformat_mask, (__force int)sformat) && snd_pcm_oss_format_to(sformat) >= 0) break; } @@ -1234,8 +1246,14 @@ snd_pcm_sframes_t snd_pcm_oss_write3(struct snd_pcm_substream *substream, const if (ret < 0) break; } - ret = __snd_pcm_lib_xfer(substream, (void *)ptr, true, - frames, in_kernel); + if (in_kernel) { + mm_segment_t fs; + fs = snd_enter_user(); + ret = snd_pcm_lib_write(substream, (void __force __user *)ptr, frames); + snd_leave_user(fs); + } else { + ret = snd_pcm_lib_write(substream, (void __force __user *)ptr, frames); + } if (ret != -EPIPE && ret != -ESTRPIPE) break; /* test, if we can't store new data, because the stream */ @@ -1271,8 +1289,14 @@ snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *p ret = snd_pcm_oss_capture_position_fixup(substream, &delay); if (ret < 0) break; - ret = __snd_pcm_lib_xfer(substream, (void *)ptr, true, - frames, in_kernel); + if (in_kernel) { + mm_segment_t fs; + fs = snd_enter_user(); + ret = snd_pcm_lib_read(substream, (void __force __user *)ptr, frames); + snd_leave_user(fs); + } else { + ret = snd_pcm_lib_read(substream, (void __force __user *)ptr, frames); + } if (ret == -EPIPE) { if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) { ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL); @@ -1287,8 +1311,7 @@ snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *p return ret; } -#ifdef CONFIG_SND_PCM_OSS_PLUGINS -snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames) +snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel) { struct snd_pcm_runtime *runtime = substream->runtime; int ret; @@ -1305,7 +1328,14 @@ snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void if (ret < 0) break; } - ret = snd_pcm_kernel_writev(substream, bufs, frames); + if (in_kernel) { + mm_segment_t fs; + fs = snd_enter_user(); + ret = snd_pcm_lib_writev(substream, (void __user **)bufs, frames); + snd_leave_user(fs); + } else { + ret = snd_pcm_lib_writev(substream, (void __user **)bufs, frames); + } if (ret != -EPIPE && ret != -ESTRPIPE) break; @@ -1317,7 +1347,7 @@ snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void return ret; } -snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames) +snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel) { struct snd_pcm_runtime *runtime = substream->runtime; int ret; @@ -1338,13 +1368,19 @@ snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, void * if (ret < 0) break; } - ret = snd_pcm_kernel_readv(substream, bufs, frames); + if (in_kernel) { + mm_segment_t fs; + fs = snd_enter_user(); + ret = snd_pcm_lib_readv(substream, (void __user **)bufs, frames); + snd_leave_user(fs); + } else { + ret = snd_pcm_lib_readv(substream, (void __user **)bufs, frames); + } if (ret != -EPIPE && ret != -ESTRPIPE) break; } return ret; } -#endif /* CONFIG_SND_PCM_OSS_PLUGINS */ static ssize_t snd_pcm_oss_write2(struct snd_pcm_substream *substream, const char *buf, size_t bytes, int in_kernel) { @@ -1691,10 +1727,27 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) size = runtime->control->appl_ptr % runtime->period_size; if (size > 0) { size = runtime->period_size - size; - if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) - snd_pcm_lib_write(substream, NULL, size); - else if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) - snd_pcm_lib_writev(substream, NULL, size); + if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) { + size = (runtime->frame_bits * size) / 8; + while (size > 0) { + mm_segment_t fs; + size_t size1 = size < runtime->oss.period_bytes ? size : runtime->oss.period_bytes; + size -= size1; + size1 *= 8; + size1 /= runtime->sample_bits; + snd_pcm_format_set_silence(runtime->format, + runtime->oss.buffer, + size1); + size1 /= runtime->channels; /* frames */ + fs = snd_enter_user(); + snd_pcm_lib_write(substream, (void __force __user *)runtime->oss.buffer, size1); + snd_leave_user(fs); + } + } else if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) { + void __user *buffers[runtime->channels]; + memset(buffers, 0, runtime->channels * sizeof(void *)); + snd_pcm_lib_writev(substream, buffers, size); + } } unlock: mutex_unlock(&runtime->oss.params_lock); @@ -1824,7 +1877,7 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file) int direct; struct snd_pcm_hw_params *params; unsigned int formats = 0; - const struct snd_mask *format_mask; + struct snd_mask format_mask; int fmt; if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0) @@ -1846,20 +1899,18 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file) return -ENOMEM; _snd_pcm_hw_params_any(params); err = snd_pcm_hw_refine(substream, params); + format_mask = *hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + kfree(params); if (err < 0) - goto error; - format_mask = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT); + return err; for (fmt = 0; fmt < 32; ++fmt) { - if (snd_mask_test(format_mask, fmt)) { - int f = snd_pcm_oss_format_to((__force snd_pcm_format_t)fmt); + if (snd_mask_test(&format_mask, fmt)) { + int f = snd_pcm_oss_format_to(fmt); if (f >= 0) formats |= f; } } - - error: - kfree(params); - return err < 0 ? err : formats; + return formats; } static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int format) diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c index 31cb2acf8afc..194b7f7ae830 100644 --- a/sound/core/oss/pcm_plugin.c +++ b/sound/core/oss/pcm_plugin.c @@ -111,7 +111,7 @@ int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames) while (plugin->next) { if (plugin->dst_frames) frames = plugin->dst_frames(plugin, frames); - if (snd_BUG_ON((snd_pcm_sframes_t)frames <= 0)) + if (snd_BUG_ON(frames <= 0)) return -ENXIO; plugin = plugin->next; err = snd_pcm_plugin_alloc(plugin, frames); @@ -123,7 +123,7 @@ int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames) while (plugin->prev) { if (plugin->src_frames) frames = plugin->src_frames(plugin, frames); - if (snd_BUG_ON((snd_pcm_sframes_t)frames <= 0)) + if (snd_BUG_ON(frames <= 0)) return -ENXIO; plugin = plugin->prev; err = snd_pcm_plugin_alloc(plugin, frames); @@ -266,8 +266,7 @@ snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *plug, snd_pc return frames; } -static int snd_pcm_plug_formats(const struct snd_mask *mask, - snd_pcm_format_t format) +static int snd_pcm_plug_formats(struct snd_mask *mask, snd_pcm_format_t format) { struct snd_mask formats = *mask; u64 linfmts = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | @@ -281,10 +280,10 @@ static int snd_pcm_plug_formats(const struct snd_mask *mask, SNDRV_PCM_FMTBIT_U32_BE | SNDRV_PCM_FMTBIT_S32_BE); snd_mask_set(&formats, (__force int)SNDRV_PCM_FORMAT_MU_LAW); - if (formats.bits[0] & lower_32_bits(linfmts)) - formats.bits[0] |= lower_32_bits(linfmts); - if (formats.bits[1] & upper_32_bits(linfmts)) - formats.bits[1] |= upper_32_bits(linfmts); + if (formats.bits[0] & (u32)linfmts) + formats.bits[0] |= (u32)linfmts; + if (formats.bits[1] & (u32)(linfmts >> 32)) + formats.bits[1] |= (u32)(linfmts >> 32); return snd_mask_test(&formats, (__force int)format); } @@ -310,7 +309,7 @@ static snd_pcm_format_t preferred_formats[] = { }; snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format, - const struct snd_mask *format_mask) + struct snd_mask *format_mask) { int i; @@ -353,7 +352,6 @@ snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format, if (snd_mask_test(format_mask, (__force int)format1)) return format1; } - /* fall through */ default: return (__force snd_pcm_format_t)-EINVAL; } diff --git a/sound/core/oss/pcm_plugin.h b/sound/core/oss/pcm_plugin.h index c9cd29d86efd..a5035c2369a6 100644 --- a/sound/core/oss/pcm_plugin.h +++ b/sound/core/oss/pcm_plugin.h @@ -126,7 +126,7 @@ int snd_pcm_plug_format_plugins(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *slave_params); snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format, - const struct snd_mask *format_mask); + struct snd_mask *format_mask); int snd_pcm_plugin_append(struct snd_pcm_plugin *plugin); @@ -162,15 +162,17 @@ snd_pcm_sframes_t snd_pcm_oss_write3(struct snd_pcm_substream *substream, snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *ptr, snd_pcm_uframes_t size, int in_kernel); snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, - void **bufs, snd_pcm_uframes_t frames); + void **bufs, snd_pcm_uframes_t frames, + int in_kernel); snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, - void **bufs, snd_pcm_uframes_t frames); + void **bufs, snd_pcm_uframes_t frames, + int in_kernel); #else static inline snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t drv_size) { return drv_size; } static inline snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t clt_size) { return clt_size; } -static inline int snd_pcm_plug_slave_format(int format, const struct snd_mask *format_mask) { return format; } +static inline int snd_pcm_plug_slave_format(int format, struct snd_mask *format_mask) { return format; } #endif diff --git a/sound/core/pcm.c b/sound/core/pcm.c index cdf41c403763..cdff5f976480 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -33,17 +33,13 @@ #include <sound/control.h> #include <sound/info.h> -#include "pcm_local.h" - MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Abramo Bagnara <abramo@alsa-project.org>"); MODULE_DESCRIPTION("Midlevel PCM code for ALSA."); MODULE_LICENSE("GPL"); static LIST_HEAD(snd_pcm_devices); -static DEFINE_MUTEX(register_mutex); -#if IS_ENABLED(CONFIG_SND_PCM_OSS) static LIST_HEAD(snd_pcm_notify_list); -#endif +static DEFINE_MUTEX(register_mutex); static int snd_pcm_free(struct snd_pcm *pcm); static int snd_pcm_dev_free(struct snd_device *device); @@ -494,8 +490,13 @@ static void snd_pcm_xrun_injection_write(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct snd_pcm_substream *substream = entry->private_data; + struct snd_pcm_runtime *runtime; - snd_pcm_stop_xrun(substream); + snd_pcm_stream_lock_irq(substream); + runtime = substream->runtime; + if (runtime && runtime->status->state == SNDRV_PCM_STATE_RUNNING) + snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); + snd_pcm_stream_unlock_irq(substream); } static void snd_pcm_xrun_debug_read(struct snd_info_entry *entry, @@ -523,9 +524,7 @@ static int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr) sprintf(name, "pcm%i%c", pcm->device, pstr->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c'); - entry = snd_info_create_card_entry(pcm->card, name, - pcm->card->proc_root); - if (!entry) + if ((entry = snd_info_create_card_entry(pcm->card, name, pcm->card->proc_root)) == NULL) return -ENOMEM; entry->mode = S_IFDIR | S_IRUGO | S_IXUGO; if (snd_info_register(entry) < 0) { @@ -533,8 +532,8 @@ static int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr) return -ENOMEM; } pstr->proc_root = entry; - entry = snd_info_create_card_entry(pcm->card, "info", pstr->proc_root); - if (entry) { + + if ((entry = snd_info_create_card_entry(pcm->card, "info", pstr->proc_root)) != NULL) { snd_info_set_text_ops(entry, pstr, snd_pcm_stream_proc_info_read); if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); @@ -544,9 +543,8 @@ static int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr) pstr->proc_info_entry = entry; #ifdef CONFIG_SND_PCM_XRUN_DEBUG - entry = snd_info_create_card_entry(pcm->card, "xrun_debug", - pstr->proc_root); - if (entry) { + if ((entry = snd_info_create_card_entry(pcm->card, "xrun_debug", + pstr->proc_root)) != NULL) { entry->c.text.read = snd_pcm_xrun_debug_read; entry->c.text.write = snd_pcm_xrun_debug_write; entry->mode |= S_IWUSR; @@ -583,9 +581,7 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) card = substream->pcm->card; sprintf(name, "sub%i", substream->number); - entry = snd_info_create_card_entry(card, name, - substream->pstr->proc_root); - if (!entry) + if ((entry = snd_info_create_card_entry(card, name, substream->pstr->proc_root)) == NULL) return -ENOMEM; entry->mode = S_IFDIR | S_IRUGO | S_IXUGO; if (snd_info_register(entry) < 0) { @@ -593,8 +589,8 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) return -ENOMEM; } substream->proc_root = entry; - entry = snd_info_create_card_entry(card, "info", substream->proc_root); - if (entry) { + + if ((entry = snd_info_create_card_entry(card, "info", substream->proc_root)) != NULL) { snd_info_set_text_ops(entry, substream, snd_pcm_substream_proc_info_read); if (snd_info_register(entry) < 0) { @@ -603,9 +599,8 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) } } substream->proc_info_entry = entry; - entry = snd_info_create_card_entry(card, "hw_params", - substream->proc_root); - if (entry) { + + if ((entry = snd_info_create_card_entry(card, "hw_params", substream->proc_root)) != NULL) { snd_info_set_text_ops(entry, substream, snd_pcm_substream_proc_hw_params_read); if (snd_info_register(entry) < 0) { @@ -614,9 +609,8 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) } } substream->proc_hw_params_entry = entry; - entry = snd_info_create_card_entry(card, "sw_params", - substream->proc_root); - if (entry) { + + if ((entry = snd_info_create_card_entry(card, "sw_params", substream->proc_root)) != NULL) { snd_info_set_text_ops(entry, substream, snd_pcm_substream_proc_sw_params_read); if (snd_info_register(entry) < 0) { @@ -625,9 +619,8 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) } } substream->proc_sw_params_entry = entry; - entry = snd_info_create_card_entry(card, "status", - substream->proc_root); - if (entry) { + + if ((entry = snd_info_create_card_entry(card, "status", substream->proc_root)) != NULL) { snd_info_set_text_ops(entry, substream, snd_pcm_substream_proc_status_read); if (snd_info_register(entry) < 0) { @@ -775,9 +768,6 @@ static int _snd_pcm_new(struct snd_card *card, const char *id, int device, .dev_register = snd_pcm_dev_register, .dev_disconnect = snd_pcm_dev_disconnect, }; - static struct snd_device_ops internal_ops = { - .dev_free = snd_pcm_dev_free, - }; if (snd_BUG_ON(!card)) return -ENXIO; @@ -794,28 +784,21 @@ static int _snd_pcm_new(struct snd_card *card, const char *id, int device, INIT_LIST_HEAD(&pcm->list); if (id) strlcpy(pcm->id, id, sizeof(pcm->id)); - - err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, - playback_count); - if (err < 0) - goto free_pcm; - - err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_CAPTURE, capture_count); - if (err < 0) - goto free_pcm; - - err = snd_device_new(card, SNDRV_DEV_PCM, pcm, - internal ? &internal_ops : &ops); - if (err < 0) - goto free_pcm; - + if ((err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, playback_count)) < 0) { + snd_pcm_free(pcm); + return err; + } + if ((err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_CAPTURE, capture_count)) < 0) { + snd_pcm_free(pcm); + return err; + } + if ((err = snd_device_new(card, SNDRV_DEV_PCM, pcm, &ops)) < 0) { + snd_pcm_free(pcm); + return err; + } if (rpcm) *rpcm = pcm; return 0; - -free_pcm: - snd_pcm_free(pcm); - return err; } /** @@ -906,23 +889,16 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr) put_device(&pstr->dev); } -#if IS_ENABLED(CONFIG_SND_PCM_OSS) -#define pcm_call_notify(pcm, call) \ - do { \ - struct snd_pcm_notify *_notify; \ - list_for_each_entry(_notify, &snd_pcm_notify_list, list) \ - _notify->call(pcm); \ - } while (0) -#else -#define pcm_call_notify(pcm, call) do {} while (0) -#endif - static int snd_pcm_free(struct snd_pcm *pcm) { + struct snd_pcm_notify *notify; + if (!pcm) return 0; - if (!pcm->internal) - pcm_call_notify(pcm, n_unregister); + if (!pcm->internal) { + list_for_each_entry(notify, &snd_pcm_notify_list, list) + notify->n_unregister(pcm); + } if (pcm->private_free) pcm->private_free(pcm); snd_pcm_lib_preallocate_free_for_all(pcm); @@ -1090,7 +1066,7 @@ static struct attribute *pcm_dev_attrs[] = { NULL }; -static const struct attribute_group pcm_dev_attr_group = { +static struct attribute_group pcm_dev_attr_group = { .attrs = pcm_dev_attrs, }; @@ -1103,11 +1079,14 @@ static int snd_pcm_dev_register(struct snd_device *device) { int cidx, err; struct snd_pcm_substream *substream; + struct snd_pcm_notify *notify; struct snd_pcm *pcm; if (snd_BUG_ON(!device || !device->device_data)) return -ENXIO; pcm = device->device_data; + if (pcm->internal) + return 0; mutex_lock(®ister_mutex); err = snd_pcm_add(pcm); @@ -1138,7 +1117,8 @@ static int snd_pcm_dev_register(struct snd_device *device) snd_pcm_timer_init(substream); } - pcm_call_notify(pcm, n_register); + list_for_each_entry(notify, &snd_pcm_notify_list, list) + notify->n_register(pcm); unlock: mutex_unlock(®ister_mutex); @@ -1148,6 +1128,7 @@ static int snd_pcm_dev_register(struct snd_device *device) static int snd_pcm_dev_disconnect(struct snd_device *device) { struct snd_pcm *pcm = device->device_data; + struct snd_pcm_notify *notify; struct snd_pcm_substream *substream; int cidx; @@ -1159,10 +1140,6 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) { snd_pcm_stream_lock_irq(substream); if (substream->runtime) { - if (snd_pcm_running(substream)) - snd_pcm_stop(substream, - SNDRV_PCM_STATE_DISCONNECTED); - /* to be sure, set the state unconditionally */ substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED; wake_up(&substream->runtime->sleep); wake_up(&substream->runtime->tsleep); @@ -1170,10 +1147,13 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) snd_pcm_stream_unlock_irq(substream); } } - - pcm_call_notify(pcm, n_disconnect); + if (!pcm->internal) { + list_for_each_entry(notify, &snd_pcm_notify_list, list) + notify->n_disconnect(pcm); + } for (cidx = 0; cidx < 2; cidx++) { - snd_unregister_device(&pcm->streams[cidx].dev); + if (!pcm->internal) + snd_unregister_device(&pcm->streams[cidx].dev); free_chmap(&pcm->streams[cidx]); } mutex_unlock(&pcm->open_mutex); @@ -1181,7 +1161,6 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) return 0; } -#if IS_ENABLED(CONFIG_SND_PCM_OSS) /** * snd_pcm_notify - Add/remove the notify list * @notify: PCM notify list @@ -1214,7 +1193,6 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree) return 0; } EXPORT_SYMBOL(snd_pcm_notify); -#endif /* CONFIG_SND_PCM_OSS */ #ifdef CONFIG_SND_PROC_FS /* @@ -1247,8 +1225,7 @@ static void snd_pcm_proc_init(void) { struct snd_info_entry *entry; - entry = snd_info_create_module_entry(THIS_MODULE, "pcm", NULL); - if (entry) { + if ((entry = snd_info_create_module_entry(THIS_MODULE, "pcm", NULL)) != NULL) { snd_info_set_text_ops(entry, NULL, snd_pcm_proc_read); if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c index 39d853bfa5ac..7ae080bae15c 100644 --- a/sound/core/pcm_compat.c +++ b/sound/core/pcm_compat.c @@ -27,14 +27,17 @@ static int snd_pcm_ioctl_delay_compat(struct snd_pcm_substream *substream, s32 __user *src) { snd_pcm_sframes_t delay; + mm_segment_t fs; int err; + fs = snd_enter_user(); err = snd_pcm_delay(substream, &delay); - if (err) + snd_leave_user(fs); + if (err < 0) return err; if (put_user(delay, src)) return -EFAULT; - return 0; + return err; } static int snd_pcm_ioctl_rewind_compat(struct snd_pcm_substream *substream, @@ -45,7 +48,10 @@ static int snd_pcm_ioctl_rewind_compat(struct snd_pcm_substream *substream, if (get_user(frames, src)) return -EFAULT; - err = snd_pcm_rewind(substream, frames); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + err = snd_pcm_playback_rewind(substream, frames); + else + err = snd_pcm_capture_rewind(substream, frames); if (put_user(err, src)) return -EFAULT; return err < 0 ? err : 0; @@ -59,7 +65,10 @@ static int snd_pcm_ioctl_forward_compat(struct snd_pcm_substream *substream, if (get_user(frames, src)) return -EFAULT; - err = snd_pcm_forward(substream, frames); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + err = snd_pcm_playback_forward(substream, frames); + else + err = snd_pcm_capture_forward(substream, frames); if (put_user(err, src)) return -EFAULT; return err < 0 ? err : 0; @@ -544,7 +553,6 @@ struct snd_pcm_mmap_status_x32 { u32 pad2; /* alignment */ struct timespec tstamp; s32 suspended_state; - s32 pad3; struct timespec audio_tstamp; } __packed; @@ -674,7 +682,6 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l case SNDRV_PCM_IOCTL_INFO: case SNDRV_PCM_IOCTL_TSTAMP: case SNDRV_PCM_IOCTL_TTSTAMP: - case SNDRV_PCM_IOCTL_USER_PVERSION: case SNDRV_PCM_IOCTL_HWSYNC: case SNDRV_PCM_IOCTL_PREPARE: case SNDRV_PCM_IOCTL_RESET: @@ -687,7 +694,10 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l case SNDRV_PCM_IOCTL_XRUN: case SNDRV_PCM_IOCTL_LINK: case SNDRV_PCM_IOCTL_UNLINK: - return snd_pcm_common_ioctl(file, substream, cmd, argp); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + return snd_pcm_playback_ioctl1(file, substream, cmd, argp); + else + return snd_pcm_capture_ioctl1(file, substream, cmd, argp); case SNDRV_PCM_IOCTL_HW_REFINE32: return snd_pcm_ioctl_hw_params_compat(substream, 1, argp); case SNDRV_PCM_IOCTL_HW_PARAMS32: diff --git a/sound/core/pcm_drm_eld.c b/sound/core/pcm_drm_eld.c index 9881d087756f..e70379fb63d0 100644 --- a/sound/core/pcm_drm_eld.c +++ b/sound/core/pcm_drm_eld.c @@ -29,13 +29,13 @@ static int eld_limit_rates(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { struct snd_interval *r = hw_param_interval(params, rule->var); - const struct snd_interval *c; + struct snd_interval *c; unsigned int rate_mask = 7, i; const u8 *sad, *eld = rule->private; sad = drm_eld_sad(eld); if (sad) { - c = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS); + c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); for (i = drm_eld_sad_count(eld); i > 0; i--, sad += 3) { unsigned max_channels = sad_max_channels(sad); @@ -57,7 +57,7 @@ static int eld_limit_channels(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { struct snd_interval *c = hw_param_interval(params, rule->var); - const struct snd_interval *r; + struct snd_interval *r; struct snd_interval t = { .min = 1, .max = 2, .integer = 1, }; unsigned int i; const u8 *sad, *eld = rule->private; @@ -67,7 +67,7 @@ static int eld_limit_channels(struct snd_pcm_hw_params *params, unsigned int rate_mask = 0; /* Convert the rate interval to a mask */ - r = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE); + r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); for (i = 0; i < ARRAY_SIZE(eld_rates); i++) if (r->min <= eld_rates[i] && r->max >= eld_rates[i]) rate_mask |= BIT(i); diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 40013b26f671..936b83970a0f 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -33,8 +33,6 @@ #include <sound/pcm_params.h> #include <sound/timer.h> -#include "pcm_local.h" - #ifdef CONFIG_SND_PCM_XRUN_DEBUG #define CREATE_TRACE_POINTS #include "pcm_trace.h" @@ -42,12 +40,8 @@ #define trace_hwptr(substream, pos, in_interrupt) #define trace_xrun(substream) #define trace_hw_ptr_error(substream, reason) -#define trace_applptr(substream, prev, curr) #endif -static int fill_silence_frames(struct snd_pcm_substream *substream, - snd_pcm_uframes_t off, snd_pcm_uframes_t frames); - /* * fill ring buffer with silence * runtime->silence_start: starting pointer to silence area @@ -61,7 +55,6 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram { struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_uframes_t frames, ofs, transfer; - int err; if (runtime->silence_size < runtime->boundary) { snd_pcm_sframes_t noise_dist, n; @@ -115,8 +108,33 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram ofs = runtime->silence_start % runtime->buffer_size; while (frames > 0) { transfer = ofs + frames > runtime->buffer_size ? runtime->buffer_size - ofs : frames; - err = fill_silence_frames(substream, ofs, transfer); - snd_BUG_ON(err < 0); + if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED || + runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) { + if (substream->ops->silence) { + int err; + err = substream->ops->silence(substream, -1, ofs, transfer); + snd_BUG_ON(err < 0); + } else { + char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, ofs); + snd_pcm_format_set_silence(runtime->format, hwbuf, transfer * runtime->channels); + } + } else { + unsigned int c; + unsigned int channels = runtime->channels; + if (substream->ops->silence) { + for (c = 0; c < channels; ++c) { + int err; + err = substream->ops->silence(substream, c, ofs, transfer); + snd_BUG_ON(err < 0); + } + } else { + size_t dma_csize = runtime->dma_bytes / channels; + for (c = 0; c < channels; ++c) { + char *hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, ofs); + snd_pcm_format_set_silence(runtime->format, hwbuf, transfer); + } + } + } runtime->silence_filled += transfer; frames -= transfer; ofs = 0; @@ -153,8 +171,7 @@ EXPORT_SYMBOL(snd_pcm_debug_name); dump_stack(); \ } while (0) -/* call with stream lock held */ -void __snd_pcm_xrun(struct snd_pcm_substream *substream) +static void xrun(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -192,7 +209,10 @@ int snd_pcm_update_state(struct snd_pcm_substream *substream, { snd_pcm_uframes_t avail; - avail = snd_pcm_avail(substream); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + avail = snd_pcm_playback_avail(runtime); + else + avail = snd_pcm_capture_avail(runtime); if (avail > runtime->avail_max) runtime->avail_max = avail; if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) { @@ -202,7 +222,7 @@ int snd_pcm_update_state(struct snd_pcm_substream *substream, } } else { if (avail >= runtime->stop_threshold) { - __snd_pcm_xrun(substream); + xrun(substream); return -EPIPE; } } @@ -298,7 +318,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, } if (pos == SNDRV_PCM_POS_XRUN) { - __snd_pcm_xrun(substream); + xrun(substream); return -EPIPE; } if (pos >= runtime->buffer_size) { @@ -491,6 +511,7 @@ void snd_pcm_set_ops(struct snd_pcm *pcm, int direction, for (substream = stream->substream; substream != NULL; substream = substream->next) substream->ops = ops; } + EXPORT_SYMBOL(snd_pcm_set_ops); /** @@ -508,6 +529,7 @@ void snd_pcm_set_sync(struct snd_pcm_substream *substream) runtime->sync.id32[2] = -1; runtime->sync.id32[3] = -1; } + EXPORT_SYMBOL(snd_pcm_set_sync); /* @@ -623,6 +645,7 @@ int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v) } return changed; } + EXPORT_SYMBOL(snd_interval_refine); static int snd_interval_refine_first(struct snd_interval *i) @@ -891,6 +914,7 @@ int snd_interval_ratnum(struct snd_interval *i, } return err; } + EXPORT_SYMBOL(snd_interval_ratnum); /** @@ -1028,6 +1052,7 @@ int snd_interval_list(struct snd_interval *i, unsigned int count, } return snd_interval_refine(i, &list_range); } + EXPORT_SYMBOL(snd_interval_list); /** @@ -1133,12 +1158,16 @@ int snd_pcm_hw_rule_add(struct snd_pcm_runtime *runtime, unsigned int cond, if (constrs->rules_num >= constrs->rules_all) { struct snd_pcm_hw_rule *new; unsigned int new_rules = constrs->rules_all + 16; - new = krealloc(constrs->rules, new_rules * sizeof(*c), - GFP_KERNEL); + new = kcalloc(new_rules, sizeof(*c), GFP_KERNEL); if (!new) { va_end(args); return -ENOMEM; } + if (constrs->rules) { + memcpy(new, constrs->rules, + constrs->rules_num * sizeof(*c)); + kfree(constrs->rules); + } constrs->rules = new; constrs->rules_all = new_rules; } @@ -1162,6 +1191,7 @@ int snd_pcm_hw_rule_add(struct snd_pcm_runtime *runtime, unsigned int cond, va_end(args); return 0; } + EXPORT_SYMBOL(snd_pcm_hw_rule_add); /** @@ -1225,6 +1255,7 @@ int snd_pcm_hw_constraint_integer(struct snd_pcm_runtime *runtime, snd_pcm_hw_pa struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints; return snd_interval_setinteger(constrs_interval(constrs, var)); } + EXPORT_SYMBOL(snd_pcm_hw_constraint_integer); /** @@ -1250,6 +1281,7 @@ int snd_pcm_hw_constraint_minmax(struct snd_pcm_runtime *runtime, snd_pcm_hw_par t.integer = 0; return snd_interval_refine(constrs_interval(constrs, var), &t); } + EXPORT_SYMBOL(snd_pcm_hw_constraint_minmax); static int snd_pcm_hw_rule_list(struct snd_pcm_hw_params *params, @@ -1280,6 +1312,7 @@ int snd_pcm_hw_constraint_list(struct snd_pcm_runtime *runtime, snd_pcm_hw_rule_list, (void *)l, var, -1); } + EXPORT_SYMBOL(snd_pcm_hw_constraint_list); static int snd_pcm_hw_rule_ranges(struct snd_pcm_hw_params *params, @@ -1346,6 +1379,7 @@ int snd_pcm_hw_constraint_ratnums(struct snd_pcm_runtime *runtime, snd_pcm_hw_rule_ratnums, (void *)r, var, -1); } + EXPORT_SYMBOL(snd_pcm_hw_constraint_ratnums); static int snd_pcm_hw_rule_ratdens(struct snd_pcm_hw_params *params, @@ -1380,6 +1414,7 @@ int snd_pcm_hw_constraint_ratdens(struct snd_pcm_runtime *runtime, snd_pcm_hw_rule_ratdens, (void *)r, var, -1); } + EXPORT_SYMBOL(snd_pcm_hw_constraint_ratdens); static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params, @@ -1388,8 +1423,7 @@ static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params, unsigned int l = (unsigned long) rule->private; int width = l & 0xffff; unsigned int msbits = l >> 16; - const struct snd_interval *i = - hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); + struct snd_interval *i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); if (!snd_interval_single(i)) return 0; @@ -1426,6 +1460,7 @@ int snd_pcm_hw_constraint_msbits(struct snd_pcm_runtime *runtime, (void*) l, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1); } + EXPORT_SYMBOL(snd_pcm_hw_constraint_msbits); static int snd_pcm_hw_rule_step(struct snd_pcm_hw_params *params, @@ -1453,6 +1488,7 @@ int snd_pcm_hw_constraint_step(struct snd_pcm_runtime *runtime, snd_pcm_hw_rule_step, (void *) step, var, -1); } + EXPORT_SYMBOL(snd_pcm_hw_constraint_step); static int snd_pcm_hw_rule_pow2(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) @@ -1483,6 +1519,7 @@ int snd_pcm_hw_constraint_pow2(struct snd_pcm_runtime *runtime, snd_pcm_hw_rule_pow2, NULL, var, -1); } + EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2); static int snd_pcm_hw_rule_noresample_func(struct snd_pcm_hw_params *params, @@ -1541,6 +1578,7 @@ void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params) _snd_pcm_hw_param_any(params, k); params->info = ~0U; } + EXPORT_SYMBOL(_snd_pcm_hw_params_any); /** @@ -1573,6 +1611,7 @@ int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params, } return -EINVAL; } + EXPORT_SYMBOL(snd_pcm_hw_param_value); void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params, @@ -1590,6 +1629,7 @@ void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params, snd_BUG(); } } + EXPORT_SYMBOL(_snd_pcm_hw_param_setempty); static int _snd_pcm_hw_param_first(struct snd_pcm_hw_params *params, @@ -1602,7 +1642,7 @@ static int _snd_pcm_hw_param_first(struct snd_pcm_hw_params *params, changed = snd_interval_refine_first(hw_param_interval(params, var)); else return -EINVAL; - if (changed > 0) { + if (changed) { params->cmask |= 1 << var; params->rmask |= 1 << var; } @@ -1636,6 +1676,7 @@ int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm, } return snd_pcm_hw_param_value(params, var, dir); } + EXPORT_SYMBOL(snd_pcm_hw_param_first); static int _snd_pcm_hw_param_last(struct snd_pcm_hw_params *params, @@ -1648,7 +1689,7 @@ static int _snd_pcm_hw_param_last(struct snd_pcm_hw_params *params, changed = snd_interval_refine_last(hw_param_interval(params, var)); else return -EINVAL; - if (changed > 0) { + if (changed) { params->cmask |= 1 << var; params->rmask |= 1 << var; } @@ -1682,8 +1723,48 @@ int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm, } return snd_pcm_hw_param_value(params, var, dir); } + EXPORT_SYMBOL(snd_pcm_hw_param_last); +/** + * snd_pcm_hw_param_choose - choose a configuration defined by @params + * @pcm: PCM instance + * @params: the hw_params instance + * + * Choose one configuration from configuration space defined by @params. + * The configuration chosen is that obtained fixing in this order: + * first access, first format, first subformat, min channels, + * min rate, min period time, max buffer size, min tick time + * + * Return: Zero if successful, or a negative error code on failure. + */ +int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm, + struct snd_pcm_hw_params *params) +{ + static int vars[] = { + SNDRV_PCM_HW_PARAM_ACCESS, + SNDRV_PCM_HW_PARAM_FORMAT, + SNDRV_PCM_HW_PARAM_SUBFORMAT, + SNDRV_PCM_HW_PARAM_CHANNELS, + SNDRV_PCM_HW_PARAM_RATE, + SNDRV_PCM_HW_PARAM_PERIOD_TIME, + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, + SNDRV_PCM_HW_PARAM_TICK_TIME, + -1 + }; + int err, *v; + + for (v = vars; *v != -1; v++) { + if (*v != SNDRV_PCM_HW_PARAM_BUFFER_SIZE) + err = snd_pcm_hw_param_first(pcm, params, *v, NULL); + else + err = snd_pcm_hw_param_last(pcm, params, *v, NULL); + if (snd_BUG_ON(err < 0)) + return err; + } + return 0; +} + static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream, void *arg) { @@ -1770,6 +1851,8 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg) { switch (cmd) { + case SNDRV_PCM_IOCTL1_INFO: + return 0; case SNDRV_PCM_IOCTL1_RESET: return snd_pcm_lib_ioctl_reset(substream, arg); case SNDRV_PCM_IOCTL1_CHANNEL_INFO: @@ -1779,6 +1862,7 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, } return -ENXIO; } + EXPORT_SYMBOL(snd_pcm_lib_ioctl); /** @@ -1814,6 +1898,7 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream) kill_fasync(&runtime->fasync, SIGIO, POLL_IN); snd_pcm_stream_unlock_irqrestore(substream, flags); } + EXPORT_SYMBOL(snd_pcm_period_elapsed); /* @@ -1839,19 +1924,12 @@ static int wait_for_avail(struct snd_pcm_substream *substream, if (runtime->no_period_wakeup) wait_time = MAX_SCHEDULE_TIMEOUT; else { - /* use wait time from substream if available */ - if (substream->wait_time) { - wait_time = substream->wait_time; - } else { - wait_time = 10; - - if (runtime->rate) { - long t = runtime->period_size * 2 / - runtime->rate; - wait_time = max(t, wait_time); - } - wait_time = msecs_to_jiffies(wait_time * 1000); + wait_time = 10; + if (runtime->rate) { + long t = runtime->period_size * 2 / runtime->rate; + wait_time = max(t, wait_time); } + wait_time = msecs_to_jiffies(wait_time * 1000); } for (;;) { @@ -1867,7 +1945,10 @@ static int wait_for_avail(struct snd_pcm_substream *substream, * This check must happen after been added to the waitqueue * and having current state be INTERRUPTIBLE. */ - avail = snd_pcm_avail(substream); + if (is_playback) + avail = snd_pcm_playback_avail(runtime); + else + avail = snd_pcm_capture_avail(runtime); if (avail >= runtime->twake) break; snd_pcm_stream_unlock_irq(substream); @@ -1912,147 +1993,129 @@ static int wait_for_avail(struct snd_pcm_substream *substream, return err; } -typedef int (*pcm_transfer_f)(struct snd_pcm_substream *substream, - int channel, unsigned long hwoff, - void *buf, unsigned long bytes); - -typedef int (*pcm_copy_f)(struct snd_pcm_substream *, snd_pcm_uframes_t, void *, - snd_pcm_uframes_t, snd_pcm_uframes_t, pcm_transfer_f); - -/* calculate the target DMA-buffer position to be written/read */ -static void *get_dma_ptr(struct snd_pcm_runtime *runtime, - int channel, unsigned long hwoff) -{ - return runtime->dma_area + hwoff + - channel * (runtime->dma_bytes / runtime->channels); -} - -/* default copy_user ops for write; used for both interleaved and non- modes */ -static int default_write_copy(struct snd_pcm_substream *substream, - int channel, unsigned long hwoff, - void *buf, unsigned long bytes) -{ - if (copy_from_user(get_dma_ptr(substream->runtime, channel, hwoff), - (void __user *)buf, bytes)) - return -EFAULT; - return 0; -} - -/* default copy_kernel ops for write */ -static int default_write_copy_kernel(struct snd_pcm_substream *substream, - int channel, unsigned long hwoff, - void *buf, unsigned long bytes) -{ - memcpy(get_dma_ptr(substream->runtime, channel, hwoff), buf, bytes); - return 0; -} - -/* fill silence instead of copy data; called as a transfer helper - * from __snd_pcm_lib_write() or directly from noninterleaved_copy() when - * a NULL buffer is passed - */ -static int fill_silence(struct snd_pcm_substream *substream, int channel, - unsigned long hwoff, void *buf, unsigned long bytes) +static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream, + unsigned int hwoff, + unsigned long data, unsigned int off, + snd_pcm_uframes_t frames) { struct snd_pcm_runtime *runtime = substream->runtime; - - if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) - return 0; - if (substream->ops->fill_silence) - return substream->ops->fill_silence(substream, channel, - hwoff, bytes); - - snd_pcm_format_set_silence(runtime->format, - get_dma_ptr(runtime, channel, hwoff), - bytes_to_samples(runtime, bytes)); - return 0; -} - -/* default copy_user ops for read; used for both interleaved and non- modes */ -static int default_read_copy(struct snd_pcm_substream *substream, - int channel, unsigned long hwoff, - void *buf, unsigned long bytes) -{ - if (copy_to_user((void __user *)buf, - get_dma_ptr(substream->runtime, channel, hwoff), - bytes)) - return -EFAULT; - return 0; -} - -/* default copy_kernel ops for read */ -static int default_read_copy_kernel(struct snd_pcm_substream *substream, - int channel, unsigned long hwoff, - void *buf, unsigned long bytes) -{ - memcpy(buf, get_dma_ptr(substream->runtime, channel, hwoff), bytes); + int err; + char __user *buf = (char __user *) data + frames_to_bytes(runtime, off); + if (substream->ops->copy) { + if ((err = substream->ops->copy(substream, -1, hwoff, buf, frames)) < 0) + return err; + } else { + char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff); + if (copy_from_user(hwbuf, buf, frames_to_bytes(runtime, frames))) + return -EFAULT; + } return 0; } + +typedef int (*transfer_f)(struct snd_pcm_substream *substream, unsigned int hwoff, + unsigned long data, unsigned int off, + snd_pcm_uframes_t size); -/* call transfer function with the converted pointers and sizes; - * for interleaved mode, it's one shot for all samples - */ -static int interleaved_copy(struct snd_pcm_substream *substream, - snd_pcm_uframes_t hwoff, void *data, - snd_pcm_uframes_t off, - snd_pcm_uframes_t frames, - pcm_transfer_f transfer) +static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, + unsigned long data, + snd_pcm_uframes_t size, + int nonblock, + transfer_f transfer) { struct snd_pcm_runtime *runtime = substream->runtime; + snd_pcm_uframes_t xfer = 0; + snd_pcm_uframes_t offset = 0; + snd_pcm_uframes_t avail; + int err = 0; - /* convert to bytes */ - hwoff = frames_to_bytes(runtime, hwoff); - off = frames_to_bytes(runtime, off); - frames = frames_to_bytes(runtime, frames); - return transfer(substream, 0, hwoff, data + off, frames); -} + if (size == 0) + return 0; -/* call transfer function with the converted pointers and sizes for each - * non-interleaved channel; when buffer is NULL, silencing instead of copying - */ -static int noninterleaved_copy(struct snd_pcm_substream *substream, - snd_pcm_uframes_t hwoff, void *data, - snd_pcm_uframes_t off, - snd_pcm_uframes_t frames, - pcm_transfer_f transfer) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - int channels = runtime->channels; - void **bufs = data; - int c, err; + snd_pcm_stream_lock_irq(substream); + switch (runtime->status->state) { + case SNDRV_PCM_STATE_PREPARED: + case SNDRV_PCM_STATE_RUNNING: + case SNDRV_PCM_STATE_PAUSED: + break; + case SNDRV_PCM_STATE_XRUN: + err = -EPIPE; + goto _end_unlock; + case SNDRV_PCM_STATE_SUSPENDED: + err = -ESTRPIPE; + goto _end_unlock; + default: + err = -EBADFD; + goto _end_unlock; + } - /* convert to bytes; note that it's not frames_to_bytes() here. - * in non-interleaved mode, we copy for each channel, thus - * each copy is n_samples bytes x channels = whole frames. - */ - off = samples_to_bytes(runtime, off); - frames = samples_to_bytes(runtime, frames); - hwoff = samples_to_bytes(runtime, hwoff); - for (c = 0; c < channels; ++c, ++bufs) { - if (!data || !*bufs) - err = fill_silence(substream, c, hwoff, NULL, frames); - else - err = transfer(substream, c, hwoff, *bufs + off, - frames); + runtime->twake = runtime->control->avail_min ? : 1; + if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) + snd_pcm_update_hw_ptr(substream); + avail = snd_pcm_playback_avail(runtime); + while (size > 0) { + snd_pcm_uframes_t frames, appl_ptr, appl_ofs; + snd_pcm_uframes_t cont; + if (!avail) { + if (nonblock) { + err = -EAGAIN; + goto _end_unlock; + } + runtime->twake = min_t(snd_pcm_uframes_t, size, + runtime->control->avail_min ? : 1); + err = wait_for_avail(substream, &avail); + if (err < 0) + goto _end_unlock; + } + frames = size > avail ? avail : size; + cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size; + if (frames > cont) + frames = cont; + if (snd_BUG_ON(!frames)) { + runtime->twake = 0; + snd_pcm_stream_unlock_irq(substream); + return -EINVAL; + } + appl_ptr = runtime->control->appl_ptr; + appl_ofs = appl_ptr % runtime->buffer_size; + snd_pcm_stream_unlock_irq(substream); + err = transfer(substream, appl_ofs, data, offset, frames); + snd_pcm_stream_lock_irq(substream); if (err < 0) - return err; - } - return 0; -} + goto _end_unlock; + switch (runtime->status->state) { + case SNDRV_PCM_STATE_XRUN: + err = -EPIPE; + goto _end_unlock; + case SNDRV_PCM_STATE_SUSPENDED: + err = -ESTRPIPE; + goto _end_unlock; + default: + break; + } + appl_ptr += frames; + if (appl_ptr >= runtime->boundary) + appl_ptr -= runtime->boundary; + runtime->control->appl_ptr = appl_ptr; + if (substream->ops->ack) + substream->ops->ack(substream); -/* fill silence on the given buffer position; - * called from snd_pcm_playback_silence() - */ -static int fill_silence_frames(struct snd_pcm_substream *substream, - snd_pcm_uframes_t off, snd_pcm_uframes_t frames) -{ - if (substream->runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED || - substream->runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) - return interleaved_copy(substream, off, NULL, 0, frames, - fill_silence); - else - return noninterleaved_copy(substream, off, NULL, 0, frames, - fill_silence); + offset += frames; + size -= frames; + xfer += frames; + avail -= frames; + if (runtime->status->state == SNDRV_PCM_STATE_PREPARED && + snd_pcm_playback_hw_avail(runtime) >= (snd_pcm_sframes_t)runtime->start_threshold) { + err = snd_pcm_start(substream); + if (err < 0) + goto _end_unlock; + } + } + _end_unlock: + runtime->twake = 0; + if (xfer > 0 && err >= 0) + snd_pcm_update_state(substream, runtime); + snd_pcm_stream_unlock_irq(substream); + return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; } /* sanity-check for read/write methods */ @@ -2062,141 +2125,164 @@ static int pcm_sanity_check(struct snd_pcm_substream *substream) if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; runtime = substream->runtime; - if (snd_BUG_ON(!substream->ops->copy_user && !runtime->dma_area)) + if (snd_BUG_ON(!substream->ops->copy && !runtime->dma_area)) return -EINVAL; if (runtime->status->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; return 0; } -static int pcm_accessible_state(struct snd_pcm_runtime *runtime) +snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, const void __user *buf, snd_pcm_uframes_t size) { - switch (runtime->status->state) { - case SNDRV_PCM_STATE_PREPARED: - case SNDRV_PCM_STATE_RUNNING: - case SNDRV_PCM_STATE_PAUSED: - return 0; - case SNDRV_PCM_STATE_XRUN: - return -EPIPE; - case SNDRV_PCM_STATE_SUSPENDED: - return -ESTRPIPE; - default: - return -EBADFD; - } + struct snd_pcm_runtime *runtime; + int nonblock; + int err; + + err = pcm_sanity_check(substream); + if (err < 0) + return err; + runtime = substream->runtime; + nonblock = !!(substream->f_flags & O_NONBLOCK); + + if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED && + runtime->channels > 1) + return -EINVAL; + return snd_pcm_lib_write1(substream, (unsigned long)buf, size, nonblock, + snd_pcm_lib_write_transfer); } -/* update to the given appl_ptr and call ack callback if needed; - * when an error is returned, take back to the original value - */ -int pcm_lib_apply_appl_ptr(struct snd_pcm_substream *substream, - snd_pcm_uframes_t appl_ptr) +EXPORT_SYMBOL(snd_pcm_lib_write); + +static int snd_pcm_lib_writev_transfer(struct snd_pcm_substream *substream, + unsigned int hwoff, + unsigned long data, unsigned int off, + snd_pcm_uframes_t frames) { struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_uframes_t old_appl_ptr = runtime->control->appl_ptr; - int ret; - - if (old_appl_ptr == appl_ptr) - return 0; - - runtime->control->appl_ptr = appl_ptr; - if (substream->ops->ack) { - ret = substream->ops->ack(substream); - if (ret < 0) { - runtime->control->appl_ptr = old_appl_ptr; - return ret; + int err; + void __user **bufs = (void __user **)data; + int channels = runtime->channels; + int c; + if (substream->ops->copy) { + if (snd_BUG_ON(!substream->ops->silence)) + return -EINVAL; + for (c = 0; c < channels; ++c, ++bufs) { + if (*bufs == NULL) { + if ((err = substream->ops->silence(substream, c, hwoff, frames)) < 0) + return err; + } else { + char __user *buf = *bufs + samples_to_bytes(runtime, off); + if ((err = substream->ops->copy(substream, c, hwoff, buf, frames)) < 0) + return err; + } + } + } else { + /* default transfer behaviour */ + size_t dma_csize = runtime->dma_bytes / channels; + for (c = 0; c < channels; ++c, ++bufs) { + char *hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, hwoff); + if (*bufs == NULL) { + snd_pcm_format_set_silence(runtime->format, hwbuf, frames); + } else { + char __user *buf = *bufs + samples_to_bytes(runtime, off); + if (copy_from_user(hwbuf, buf, samples_to_bytes(runtime, frames))) + return -EFAULT; + } } } - - trace_applptr(substream, old_appl_ptr, appl_ptr); - return 0; } - -/* the common loop for read/write data */ -snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, - void *data, bool interleaved, - snd_pcm_uframes_t size, bool in_kernel) + +snd_pcm_sframes_t snd_pcm_lib_writev(struct snd_pcm_substream *substream, + void __user **bufs, + snd_pcm_uframes_t frames) { - struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_uframes_t xfer = 0; - snd_pcm_uframes_t offset = 0; - snd_pcm_uframes_t avail; - pcm_copy_f writer; - pcm_transfer_f transfer; - bool nonblock; - bool is_playback; + struct snd_pcm_runtime *runtime; + int nonblock; int err; err = pcm_sanity_check(substream); if (err < 0) return err; + runtime = substream->runtime; + nonblock = !!(substream->f_flags & O_NONBLOCK); - is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; - if (interleaved) { - if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED && - runtime->channels > 1) - return -EINVAL; - writer = interleaved_copy; - } else { - if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) - return -EINVAL; - writer = noninterleaved_copy; - } + if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) + return -EINVAL; + return snd_pcm_lib_write1(substream, (unsigned long)bufs, frames, + nonblock, snd_pcm_lib_writev_transfer); +} - if (!data) { - if (is_playback) - transfer = fill_silence; - else - return -EINVAL; - } else if (in_kernel) { - if (substream->ops->copy_kernel) - transfer = substream->ops->copy_kernel; - else - transfer = is_playback ? - default_write_copy_kernel : default_read_copy_kernel; +EXPORT_SYMBOL(snd_pcm_lib_writev); + +static int snd_pcm_lib_read_transfer(struct snd_pcm_substream *substream, + unsigned int hwoff, + unsigned long data, unsigned int off, + snd_pcm_uframes_t frames) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + int err; + char __user *buf = (char __user *) data + frames_to_bytes(runtime, off); + if (substream->ops->copy) { + if ((err = substream->ops->copy(substream, -1, hwoff, buf, frames)) < 0) + return err; } else { - if (substream->ops->copy_user) - transfer = (pcm_transfer_f)substream->ops->copy_user; - else - transfer = is_playback ? - default_write_copy : default_read_copy; + char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff); + if (copy_to_user(buf, hwbuf, frames_to_bytes(runtime, frames))) + return -EFAULT; } + return 0; +} + +static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, + unsigned long data, + snd_pcm_uframes_t size, + int nonblock, + transfer_f transfer) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + snd_pcm_uframes_t xfer = 0; + snd_pcm_uframes_t offset = 0; + snd_pcm_uframes_t avail; + int err = 0; if (size == 0) return 0; - nonblock = !!(substream->f_flags & O_NONBLOCK); - snd_pcm_stream_lock_irq(substream); - err = pcm_accessible_state(runtime); - if (err < 0) - goto _end_unlock; - - runtime->twake = runtime->control->avail_min ? : 1; - if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) - snd_pcm_update_hw_ptr(substream); - - if (!is_playback && - runtime->status->state == SNDRV_PCM_STATE_PREPARED) { + switch (runtime->status->state) { + case SNDRV_PCM_STATE_PREPARED: if (size >= runtime->start_threshold) { err = snd_pcm_start(substream); if (err < 0) goto _end_unlock; - } else { - /* nothing to do */ - err = 0; - goto _end_unlock; } + break; + case SNDRV_PCM_STATE_DRAINING: + case SNDRV_PCM_STATE_RUNNING: + case SNDRV_PCM_STATE_PAUSED: + break; + case SNDRV_PCM_STATE_XRUN: + err = -EPIPE; + goto _end_unlock; + case SNDRV_PCM_STATE_SUSPENDED: + err = -ESTRPIPE; + goto _end_unlock; + default: + err = -EBADFD; + goto _end_unlock; } - avail = snd_pcm_avail(substream); - + runtime->twake = runtime->control->avail_min ? : 1; + if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) + snd_pcm_update_hw_ptr(substream); + avail = snd_pcm_capture_avail(runtime); while (size > 0) { snd_pcm_uframes_t frames, appl_ptr, appl_ofs; snd_pcm_uframes_t cont; if (!avail) { - if (!is_playback && - runtime->status->state == SNDRV_PCM_STATE_DRAINING) { + if (runtime->status->state == + SNDRV_PCM_STATE_DRAINING) { snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); goto _end_unlock; } @@ -2224,32 +2310,31 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, return -EINVAL; } snd_pcm_stream_unlock_irq(substream); - err = writer(substream, appl_ofs, data, offset, frames, - transfer); + err = transfer(substream, appl_ofs, data, offset, frames); snd_pcm_stream_lock_irq(substream); if (err < 0) goto _end_unlock; - err = pcm_accessible_state(runtime); - if (err < 0) + switch (runtime->status->state) { + case SNDRV_PCM_STATE_XRUN: + err = -EPIPE; goto _end_unlock; + case SNDRV_PCM_STATE_SUSPENDED: + err = -ESTRPIPE; + goto _end_unlock; + default: + break; + } appl_ptr += frames; if (appl_ptr >= runtime->boundary) appl_ptr -= runtime->boundary; - err = pcm_lib_apply_appl_ptr(substream, appl_ptr); - if (err < 0) - goto _end_unlock; + runtime->control->appl_ptr = appl_ptr; + if (substream->ops->ack) + substream->ops->ack(substream); offset += frames; size -= frames; xfer += frames; avail -= frames; - if (is_playback && - runtime->status->state == SNDRV_PCM_STATE_PREPARED && - snd_pcm_playback_hw_avail(runtime) >= (snd_pcm_sframes_t)runtime->start_threshold) { - err = snd_pcm_start(substream); - if (err < 0) - goto _end_unlock; - } } _end_unlock: runtime->twake = 0; @@ -2258,7 +2343,83 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, snd_pcm_stream_unlock_irq(substream); return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; } -EXPORT_SYMBOL(__snd_pcm_lib_xfer); + +snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, void __user *buf, snd_pcm_uframes_t size) +{ + struct snd_pcm_runtime *runtime; + int nonblock; + int err; + + err = pcm_sanity_check(substream); + if (err < 0) + return err; + runtime = substream->runtime; + nonblock = !!(substream->f_flags & O_NONBLOCK); + if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED) + return -EINVAL; + return snd_pcm_lib_read1(substream, (unsigned long)buf, size, nonblock, snd_pcm_lib_read_transfer); +} + +EXPORT_SYMBOL(snd_pcm_lib_read); + +static int snd_pcm_lib_readv_transfer(struct snd_pcm_substream *substream, + unsigned int hwoff, + unsigned long data, unsigned int off, + snd_pcm_uframes_t frames) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + int err; + void __user **bufs = (void __user **)data; + int channels = runtime->channels; + int c; + if (substream->ops->copy) { + for (c = 0; c < channels; ++c, ++bufs) { + char __user *buf; + if (*bufs == NULL) + continue; + buf = *bufs + samples_to_bytes(runtime, off); + if ((err = substream->ops->copy(substream, c, hwoff, buf, frames)) < 0) + return err; + } + } else { + snd_pcm_uframes_t dma_csize = runtime->dma_bytes / channels; + for (c = 0; c < channels; ++c, ++bufs) { + char *hwbuf; + char __user *buf; + if (*bufs == NULL) + continue; + + hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, hwoff); + buf = *bufs + samples_to_bytes(runtime, off); + if (copy_to_user(buf, hwbuf, samples_to_bytes(runtime, frames))) + return -EFAULT; + } + } + return 0; +} + +snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream, + void __user **bufs, + snd_pcm_uframes_t frames) +{ + struct snd_pcm_runtime *runtime; + int nonblock; + int err; + + err = pcm_sanity_check(substream); + if (err < 0) + return err; + runtime = substream->runtime; + if (runtime->status->state == SNDRV_PCM_STATE_OPEN) + return -EBADFD; + + nonblock = !!(substream->f_flags & O_NONBLOCK); + if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) + return -EINVAL; + return snd_pcm_lib_read1(substream, (unsigned long)bufs, frames, nonblock, snd_pcm_lib_readv_transfer); +} + +EXPORT_SYMBOL(snd_pcm_lib_readv); /* * standard channel mapping helpers diff --git a/sound/core/pcm_local.h b/sound/core/pcm_local.h deleted file mode 100644 index c515612969a4..000000000000 --- a/sound/core/pcm_local.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * pcm_local.h - a local header file for snd-pcm module. - * - * Copyright (c) Takashi Sakamoto <o-takashi@sakamocchi.jp> - * - * Licensed under the terms of the GNU General Public License, version 2. - */ - -#ifndef __SOUND_CORE_PCM_LOCAL_H -#define __SOUND_CORE_PCM_LOCAL_H - -extern const struct snd_pcm_hw_constraint_list snd_pcm_known_rates; - -void snd_interval_mul(const struct snd_interval *a, - const struct snd_interval *b, struct snd_interval *c); -void snd_interval_div(const struct snd_interval *a, - const struct snd_interval *b, struct snd_interval *c); -void snd_interval_muldivk(const struct snd_interval *a, - const struct snd_interval *b, - unsigned int k, struct snd_interval *c); -void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k, - const struct snd_interval *b, struct snd_interval *c); - -int snd_pcm_hw_constraints_init(struct snd_pcm_substream *substream); -int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream); - -int snd_pcm_hw_constraint_mask(struct snd_pcm_runtime *runtime, - snd_pcm_hw_param_t var, u_int32_t mask); - -int pcm_lib_apply_appl_ptr(struct snd_pcm_substream *substream, - snd_pcm_uframes_t appl_ptr); -int snd_pcm_update_state(struct snd_pcm_substream *substream, - struct snd_pcm_runtime *runtime); -int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream); - -void snd_pcm_playback_silence(struct snd_pcm_substream *substream, - snd_pcm_uframes_t new_hw_ptr); - -static inline snd_pcm_uframes_t -snd_pcm_avail(struct snd_pcm_substream *substream) -{ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - return snd_pcm_playback_avail(substream->runtime); - else - return snd_pcm_capture_avail(substream->runtime); -} - -static inline snd_pcm_uframes_t -snd_pcm_hw_avail(struct snd_pcm_substream *substream) -{ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - return snd_pcm_playback_hw_avail(substream->runtime); - else - return snd_pcm_capture_hw_avail(substream->runtime); -} - -#ifdef CONFIG_SND_PCM_TIMER -void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream); -void snd_pcm_timer_init(struct snd_pcm_substream *substream); -void snd_pcm_timer_done(struct snd_pcm_substream *substream); -#else -static inline void -snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream) {} -static inline void snd_pcm_timer_init(struct snd_pcm_substream *substream) {} -static inline void snd_pcm_timer_done(struct snd_pcm_substream *substream) {} -#endif - -void __snd_pcm_xrun(struct snd_pcm_substream *substream); - -#endif /* __SOUND_CORE_PCM_LOCAL_H */ diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index ae33e456708c..b45f6aa32264 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -120,6 +120,7 @@ int snd_pcm_lib_preallocate_free_for_all(struct snd_pcm *pcm) snd_pcm_lib_preallocate_free(substream); return 0; } + EXPORT_SYMBOL(snd_pcm_lib_preallocate_free_for_all); #ifdef CONFIG_SND_VERBOSE_PROCFS @@ -262,6 +263,7 @@ int snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream, substream->dma_buffer.dev.dev = data; return snd_pcm_lib_preallocate_pages1(substream, size, max); } + EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages); /** @@ -290,6 +292,7 @@ int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm, return err; return 0; } + EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all); #ifdef CONFIG_SND_DMA_SGBUF @@ -311,6 +314,7 @@ struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigne return NULL; return sgbuf->page_table[idx]; } + EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page); #endif /* CONFIG_SND_DMA_SGBUF */ @@ -366,6 +370,7 @@ int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size) runtime->dma_bytes = size; return 1; /* area was changed */ } + EXPORT_SYMBOL(snd_pcm_lib_malloc_pages); /** @@ -393,6 +398,7 @@ int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream) snd_pcm_set_runtime_buffer(substream, NULL); return 0; } + EXPORT_SYMBOL(snd_pcm_lib_free_pages); int _snd_pcm_lib_alloc_vmalloc_buffer(struct snd_pcm_substream *substream, diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c index c4eb561d2008..53dc37357bca 100644 --- a/sound/core/pcm_misc.c +++ b/sound/core/pcm_misc.c @@ -23,9 +23,6 @@ #include <linux/export.h> #include <sound/core.h> #include <sound/pcm.h> - -#include "pcm_local.h" - #define SND_PCM_FORMAT_UNKNOWN (-1) /* NOTE: "signed" prefix must be given below since the default char is @@ -163,30 +160,13 @@ static struct pcm_format_data pcm_formats[(INT)SNDRV_PCM_FORMAT_LAST+1] = { .width = 32, .phys = 32, .le = 0, .signd = 0, .silence = { 0x69, 0x69, 0x69, 0x69 }, }, - /* FIXME: the following two formats are not defined properly yet */ + /* FIXME: the following three formats are not defined properly yet */ [SNDRV_PCM_FORMAT_MPEG] = { .le = -1, .signd = -1, }, [SNDRV_PCM_FORMAT_GSM] = { .le = -1, .signd = -1, }, - [SNDRV_PCM_FORMAT_S20_LE] = { - .width = 20, .phys = 32, .le = 1, .signd = 1, - .silence = {}, - }, - [SNDRV_PCM_FORMAT_S20_BE] = { - .width = 20, .phys = 32, .le = 0, .signd = 1, - .silence = {}, - }, - [SNDRV_PCM_FORMAT_U20_LE] = { - .width = 20, .phys = 32, .le = 1, .signd = 0, - .silence = { 0x00, 0x00, 0x08, 0x00 }, - }, - [SNDRV_PCM_FORMAT_U20_BE] = { - .width = 20, .phys = 32, .le = 0, .signd = 0, - .silence = { 0x00, 0x08, 0x00, 0x00 }, - }, - /* FIXME: the following format is not defined properly yet */ [SNDRV_PCM_FORMAT_SPECIAL] = { .le = -1, .signd = -1, }, @@ -265,6 +245,7 @@ int snd_pcm_format_signed(snd_pcm_format_t format) return -EINVAL; return val; } + EXPORT_SYMBOL(snd_pcm_format_signed); /** @@ -283,6 +264,7 @@ int snd_pcm_format_unsigned(snd_pcm_format_t format) return val; return !val; } + EXPORT_SYMBOL(snd_pcm_format_unsigned); /** @@ -295,6 +277,7 @@ int snd_pcm_format_linear(snd_pcm_format_t format) { return snd_pcm_format_signed(format) >= 0; } + EXPORT_SYMBOL(snd_pcm_format_linear); /** @@ -313,6 +296,7 @@ int snd_pcm_format_little_endian(snd_pcm_format_t format) return -EINVAL; return val; } + EXPORT_SYMBOL(snd_pcm_format_little_endian); /** @@ -331,6 +315,7 @@ int snd_pcm_format_big_endian(snd_pcm_format_t format) return val; return !val; } + EXPORT_SYMBOL(snd_pcm_format_big_endian); /** @@ -349,6 +334,7 @@ int snd_pcm_format_width(snd_pcm_format_t format) return -EINVAL; return val; } + EXPORT_SYMBOL(snd_pcm_format_width); /** @@ -367,6 +353,7 @@ int snd_pcm_format_physical_width(snd_pcm_format_t format) return -EINVAL; return val; } + EXPORT_SYMBOL(snd_pcm_format_physical_width); /** @@ -384,6 +371,7 @@ ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples) return -EINVAL; return samples * phys_width / 8; } + EXPORT_SYMBOL(snd_pcm_format_size); /** @@ -400,6 +388,7 @@ const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format) return NULL; return pcm_formats[(INT)format].silence; } + EXPORT_SYMBOL(snd_pcm_format_silence_64); /** @@ -470,6 +459,7 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int #endif return 0; } + EXPORT_SYMBOL(snd_pcm_format_set_silence); /** @@ -498,6 +488,7 @@ int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime) } return 0; } + EXPORT_SYMBOL(snd_pcm_limit_hw_rates); /** diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 234963c5bd8b..5c58d1cfe959 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -38,18 +38,6 @@ #include <linux/uio.h> #include <linux/delay.h> -#include "pcm_local.h" - -#ifdef CONFIG_SND_DEBUG -#define CREATE_TRACE_POINTS -#include "pcm_param_trace.h" -#else -#define trace_hw_mask_param_enabled() 0 -#define trace_hw_interval_param_enabled() 0 -#define trace_hw_mask_param(substream, type, index, prev, curr) -#define trace_hw_interval_param(substream, type, index, prev, curr) -#endif - /* * Compatibility */ @@ -100,57 +88,6 @@ static inline void down_write_nonfifo(struct rw_semaphore *lock) msleep(1); } -#define PCM_LOCK_DEFAULT 0 -#define PCM_LOCK_IRQ 1 -#define PCM_LOCK_IRQSAVE 2 - -static unsigned long __snd_pcm_stream_lock_mode(struct snd_pcm_substream *substream, - unsigned int mode) -{ - unsigned long flags = 0; - if (substream->pcm->nonatomic) { - down_read_nested(&snd_pcm_link_rwsem, SINGLE_DEPTH_NESTING); - mutex_lock(&substream->self_group.mutex); - } else { - switch (mode) { - case PCM_LOCK_DEFAULT: - read_lock(&snd_pcm_link_rwlock); - break; - case PCM_LOCK_IRQ: - read_lock_irq(&snd_pcm_link_rwlock); - break; - case PCM_LOCK_IRQSAVE: - read_lock_irqsave(&snd_pcm_link_rwlock, flags); - break; - } - spin_lock(&substream->self_group.lock); - } - return flags; -} - -static void __snd_pcm_stream_unlock_mode(struct snd_pcm_substream *substream, - unsigned int mode, unsigned long flags) -{ - if (substream->pcm->nonatomic) { - mutex_unlock(&substream->self_group.mutex); - up_read(&snd_pcm_link_rwsem); - } else { - spin_unlock(&substream->self_group.lock); - - switch (mode) { - case PCM_LOCK_DEFAULT: - read_unlock(&snd_pcm_link_rwlock); - break; - case PCM_LOCK_IRQ: - read_unlock_irq(&snd_pcm_link_rwlock); - break; - case PCM_LOCK_IRQSAVE: - read_unlock_irqrestore(&snd_pcm_link_rwlock, flags); - break; - } - } -} - /** * snd_pcm_stream_lock - Lock the PCM stream * @substream: PCM substream @@ -161,7 +98,13 @@ static void __snd_pcm_stream_unlock_mode(struct snd_pcm_substream *substream, */ void snd_pcm_stream_lock(struct snd_pcm_substream *substream) { - __snd_pcm_stream_lock_mode(substream, PCM_LOCK_DEFAULT); + if (substream->pcm->nonatomic) { + down_read_nested(&snd_pcm_link_rwsem, SINGLE_DEPTH_NESTING); + mutex_lock(&substream->self_group.mutex); + } else { + read_lock(&snd_pcm_link_rwlock); + spin_lock(&substream->self_group.lock); + } } EXPORT_SYMBOL_GPL(snd_pcm_stream_lock); @@ -173,7 +116,13 @@ EXPORT_SYMBOL_GPL(snd_pcm_stream_lock); */ void snd_pcm_stream_unlock(struct snd_pcm_substream *substream) { - __snd_pcm_stream_unlock_mode(substream, PCM_LOCK_DEFAULT, 0); + if (substream->pcm->nonatomic) { + mutex_unlock(&substream->self_group.mutex); + up_read(&snd_pcm_link_rwsem); + } else { + spin_unlock(&substream->self_group.lock); + read_unlock(&snd_pcm_link_rwlock); + } } EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock); @@ -187,7 +136,9 @@ EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock); */ void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream) { - __snd_pcm_stream_lock_mode(substream, PCM_LOCK_IRQ); + if (!substream->pcm->nonatomic) + local_irq_disable(); + snd_pcm_stream_lock(substream); } EXPORT_SYMBOL_GPL(snd_pcm_stream_lock_irq); @@ -199,13 +150,19 @@ EXPORT_SYMBOL_GPL(snd_pcm_stream_lock_irq); */ void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream) { - __snd_pcm_stream_unlock_mode(substream, PCM_LOCK_IRQ, 0); + snd_pcm_stream_unlock(substream); + if (!substream->pcm->nonatomic) + local_irq_enable(); } EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irq); unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream) { - return __snd_pcm_stream_lock_mode(substream, PCM_LOCK_IRQSAVE); + unsigned long flags = 0; + if (!substream->pcm->nonatomic) + local_irq_save(flags); + snd_pcm_stream_lock(substream); + return flags; } EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave); @@ -219,12 +176,29 @@ EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave); void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream, unsigned long flags) { - __snd_pcm_stream_unlock_mode(substream, PCM_LOCK_IRQSAVE, flags); + snd_pcm_stream_unlock(substream); + if (!substream->pcm->nonatomic) + local_irq_restore(flags); } EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irqrestore); +static inline mm_segment_t snd_enter_user(void) +{ + mm_segment_t fs = get_fs(); + set_fs(get_ds()); + return fs; +} + +static inline void snd_leave_user(mm_segment_t fs) +{ + set_fs(fs); +} + + + int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info) { + struct snd_pcm_runtime *runtime; struct snd_pcm *pcm = substream->pcm; struct snd_pcm_str *pstr = substream->pstr; @@ -240,7 +214,12 @@ int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info) info->subdevices_count = pstr->substream_count; info->subdevices_avail = pstr->substream_count - pstr->substream_opened; strlcpy(info->subname, substream->name, sizeof(info->subname)); - + runtime = substream->runtime; + /* AB: FIXME!!! This is definitely nonsense */ + if (runtime) { + info->sync = runtime->sync; + substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_INFO, info); + } return 0; } @@ -266,8 +245,10 @@ static bool hw_support_mmap(struct snd_pcm_substream *substream) { if (!(substream->runtime->hw.info & SNDRV_PCM_INFO_MMAP)) return false; - /* architecture supports dma_mmap_coherent()? */ -#if defined(CONFIG_ARCH_NO_COHERENT_DMA_MMAP) || !defined(CONFIG_HAS_DMA) + /* check architectures that return -EINVAL from dma_mmap_coherent() */ + /* FIXME: this should be some global flag */ +#if defined(CONFIG_C6X) || defined(CONFIG_FRV) || defined(CONFIG_MN10300) ||\ + defined(CONFIG_PARISC) || defined(CONFIG_XTENSA) if (!substream->ops->mmap && substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV) return false; @@ -275,273 +256,205 @@ static bool hw_support_mmap(struct snd_pcm_substream *substream) return true; } -static int constrain_mask_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +#undef RULES_DEBUG + +#ifdef RULES_DEBUG +#define HW_PARAM(v) [SNDRV_PCM_HW_PARAM_##v] = #v +static const char * const snd_pcm_hw_param_names[] = { + HW_PARAM(ACCESS), + HW_PARAM(FORMAT), + HW_PARAM(SUBFORMAT), + HW_PARAM(SAMPLE_BITS), + HW_PARAM(FRAME_BITS), + HW_PARAM(CHANNELS), + HW_PARAM(RATE), + HW_PARAM(PERIOD_TIME), + HW_PARAM(PERIOD_SIZE), + HW_PARAM(PERIOD_BYTES), + HW_PARAM(PERIODS), + HW_PARAM(BUFFER_TIME), + HW_PARAM(BUFFER_SIZE), + HW_PARAM(BUFFER_BYTES), + HW_PARAM(TICK_TIME), +}; +#endif + +int snd_pcm_hw_refine(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) { - struct snd_pcm_hw_constraints *constrs = - &substream->runtime->hw_constraints; - struct snd_mask *m; unsigned int k; - struct snd_mask old_mask; - int changed; + struct snd_pcm_hardware *hw; + struct snd_interval *i = NULL; + struct snd_mask *m = NULL; + struct snd_pcm_hw_constraints *constrs = &substream->runtime->hw_constraints; + unsigned int rstamps[constrs->rules_num]; + unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1]; + unsigned int stamp = 2; + int changed, again; + + params->info = 0; + params->fifo_size = 0; + if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_SAMPLE_BITS)) + params->msbits = 0; + if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_RATE)) { + params->rate_num = 0; + params->rate_den = 0; + } for (k = SNDRV_PCM_HW_PARAM_FIRST_MASK; k <= SNDRV_PCM_HW_PARAM_LAST_MASK; k++) { m = hw_param_mask(params, k); if (snd_mask_empty(m)) return -EINVAL; - - /* This parameter is not requested to change by a caller. */ if (!(params->rmask & (1 << k))) continue; - - if (trace_hw_mask_param_enabled()) - old_mask = *m; - +#ifdef RULES_DEBUG + pr_debug("%s = ", snd_pcm_hw_param_names[k]); + pr_cont("%04x%04x%04x%04x -> ", m->bits[3], m->bits[2], m->bits[1], m->bits[0]); +#endif changed = snd_mask_refine(m, constrs_mask(constrs, k)); +#ifdef RULES_DEBUG + pr_cont("%04x%04x%04x%04x\n", m->bits[3], m->bits[2], m->bits[1], m->bits[0]); +#endif + if (changed) + params->cmask |= 1 << k; if (changed < 0) return changed; - if (changed == 0) - continue; - - /* Set corresponding flag so that the caller gets it. */ - trace_hw_mask_param(substream, k, 0, &old_mask, m); - params->cmask |= 1 << k; } - return 0; -} - -static int constrain_interval_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_pcm_hw_constraints *constrs = - &substream->runtime->hw_constraints; - struct snd_interval *i; - unsigned int k; - struct snd_interval old_interval; - int changed; - for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) { i = hw_param_interval(params, k); if (snd_interval_empty(i)) return -EINVAL; - - /* This parameter is not requested to change by a caller. */ if (!(params->rmask & (1 << k))) continue; - - if (trace_hw_interval_param_enabled()) - old_interval = *i; - +#ifdef RULES_DEBUG + pr_debug("%s = ", snd_pcm_hw_param_names[k]); + if (i->empty) + pr_cont("empty"); + else + pr_cont("%c%u %u%c", + i->openmin ? '(' : '[', i->min, + i->max, i->openmax ? ')' : ']'); + pr_cont(" -> "); +#endif changed = snd_interval_refine(i, constrs_interval(constrs, k)); +#ifdef RULES_DEBUG + if (i->empty) + pr_cont("empty\n"); + else + pr_cont("%c%u %u%c\n", + i->openmin ? '(' : '[', i->min, + i->max, i->openmax ? ')' : ']'); +#endif + if (changed) + params->cmask |= 1 << k; if (changed < 0) return changed; - if (changed == 0) - continue; - - /* Set corresponding flag so that the caller gets it. */ - trace_hw_interval_param(substream, k, 0, &old_interval, i); - params->cmask |= 1 << k; } - return 0; -} - -static int constrain_params_by_rules(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_pcm_hw_constraints *constrs = - &substream->runtime->hw_constraints; - unsigned int k; - unsigned int *rstamps; - unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1]; - unsigned int stamp; - struct snd_pcm_hw_rule *r; - unsigned int d; - struct snd_mask old_mask; - struct snd_interval old_interval; - bool again; - int changed, err = 0; - - /* - * Each application of rule has own sequence number. - * - * Each member of 'rstamps' array represents the sequence number of - * recent application of corresponding rule. - */ - rstamps = kcalloc(constrs->rules_num, sizeof(unsigned int), GFP_KERNEL); - if (!rstamps) - return -ENOMEM; - - /* - * Each member of 'vstamps' array represents the sequence number of - * recent application of rule in which corresponding parameters were - * changed. - * - * In initial state, elements corresponding to parameters requested by - * a caller is 1. For unrequested parameters, corresponding members - * have 0 so that the parameters are never changed anymore. - */ - for (k = 0; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) + for (k = 0; k < constrs->rules_num; k++) + rstamps[k] = 0; + for (k = 0; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0; - - /* Due to the above design, actual sequence number starts at 2. */ - stamp = 2; -retry: - /* Apply all rules in order. */ - again = false; - for (k = 0; k < constrs->rules_num; k++) { - r = &constrs->rules[k]; - - /* - * Check condition bits of this rule. When the rule has - * some condition bits, parameter without the bits is - * never processed. SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP - * is an example of the condition bits. - */ - if (r->cond && !(r->cond & params->flags)) - continue; - - /* - * The 'deps' array includes maximum three dependencies - * to SNDRV_PCM_HW_PARAM_XXXs for this rule. The fourth - * member of this array is a sentinel and should be - * negative value. - * - * This rule should be processed in this time when dependent - * parameters were changed at former applications of the other - * rules. - */ - for (d = 0; r->deps[d] >= 0; d++) { - if (vstamps[r->deps[d]] > rstamps[k]) - break; - } - if (r->deps[d] < 0) - continue; - - if (trace_hw_mask_param_enabled()) { - if (hw_is_mask(r->var)) - old_mask = *hw_param_mask(params, r->var); - } - if (trace_hw_interval_param_enabled()) { - if (hw_is_interval(r->var)) - old_interval = *hw_param_interval(params, r->var); - } - - changed = r->func(params, r); - if (changed < 0) { - err = changed; - goto out; - } - - /* - * When the parameter is changed, notify it to the caller - * by corresponding returned bit, then preparing for next - * iteration. - */ - if (changed && r->var >= 0) { - if (hw_is_mask(r->var)) { - trace_hw_mask_param(substream, r->var, - k + 1, &old_mask, - hw_param_mask(params, r->var)); + do { + again = 0; + for (k = 0; k < constrs->rules_num; k++) { + struct snd_pcm_hw_rule *r = &constrs->rules[k]; + unsigned int d; + int doit = 0; + if (r->cond && !(r->cond & params->flags)) + continue; + for (d = 0; r->deps[d] >= 0; d++) { + if (vstamps[r->deps[d]] > rstamps[k]) { + doit = 1; + break; + } } - if (hw_is_interval(r->var)) { - trace_hw_interval_param(substream, r->var, - k + 1, &old_interval, - hw_param_interval(params, r->var)); + if (!doit) + continue; +#ifdef RULES_DEBUG + pr_debug("Rule %d [%p]: ", k, r->func); + if (r->var >= 0) { + pr_cont("%s = ", snd_pcm_hw_param_names[r->var]); + if (hw_is_mask(r->var)) { + m = hw_param_mask(params, r->var); + pr_cont("%x", *m->bits); + } else { + i = hw_param_interval(params, r->var); + if (i->empty) + pr_cont("empty"); + else + pr_cont("%c%u %u%c", + i->openmin ? '(' : '[', i->min, + i->max, i->openmax ? ')' : ']'); + } } - - params->cmask |= (1 << r->var); - vstamps[r->var] = stamp; - again = true; +#endif + changed = r->func(params, r); +#ifdef RULES_DEBUG + if (r->var >= 0) { + pr_cont(" -> "); + if (hw_is_mask(r->var)) + pr_cont("%x", *m->bits); + else { + if (i->empty) + pr_cont("empty"); + else + pr_cont("%c%u %u%c", + i->openmin ? '(' : '[', i->min, + i->max, i->openmax ? ')' : ']'); + } + } + pr_cont("\n"); +#endif + rstamps[k] = stamp; + if (changed && r->var >= 0) { + params->cmask |= (1 << r->var); + vstamps[r->var] = stamp; + again = 1; + } + if (changed < 0) + return changed; + stamp++; } - - rstamps[k] = stamp++; - } - - /* Iterate to evaluate all rules till no parameters are changed. */ - if (again) - goto retry; - - out: - kfree(rstamps); - return err; -} - -static int fixup_unreferenced_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - const struct snd_interval *i; - const struct snd_mask *m; - int err; - + } while (again); if (!params->msbits) { - i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); + i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); if (snd_interval_single(i)) params->msbits = snd_interval_value(i); } if (!params->rate_den) { - i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE); + i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); if (snd_interval_single(i)) { params->rate_num = snd_interval_value(i); params->rate_den = 1; } } - if (!params->fifo_size) { - m = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT); - i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS); - if (snd_mask_single(m) && snd_interval_single(i)) { - err = substream->ops->ioctl(substream, - SNDRV_PCM_IOCTL1_FIFO_SIZE, params); - if (err < 0) - return err; - } - } - + hw = &substream->runtime->hw; if (!params->info) { - params->info = substream->runtime->hw.info; - params->info &= ~(SNDRV_PCM_INFO_FIFO_IN_FRAMES | - SNDRV_PCM_INFO_DRAIN_TRIGGER); + params->info = hw->info & ~(SNDRV_PCM_INFO_FIFO_IN_FRAMES | + SNDRV_PCM_INFO_DRAIN_TRIGGER); if (!hw_support_mmap(substream)) params->info &= ~(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID); } - - return 0; -} - -int snd_pcm_hw_refine(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - int err; - - params->info = 0; - params->fifo_size = 0; - if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_SAMPLE_BITS)) - params->msbits = 0; - if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_RATE)) { - params->rate_num = 0; - params->rate_den = 0; + if (!params->fifo_size) { + m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + if (snd_mask_min(m) == snd_mask_max(m) && + snd_interval_min(i) == snd_interval_max(i)) { + changed = substream->ops->ioctl(substream, + SNDRV_PCM_IOCTL1_FIFO_SIZE, params); + if (changed < 0) + return changed; + } } - - err = constrain_mask_params(substream, params); - if (err < 0) - return err; - - err = constrain_interval_params(substream, params); - if (err < 0) - return err; - - err = constrain_params_by_rules(substream, params); - if (err < 0) - return err; - params->rmask = 0; - return 0; } + EXPORT_SYMBOL(snd_pcm_hw_refine); static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream, @@ -555,16 +468,11 @@ static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream, return PTR_ERR(params); err = snd_pcm_hw_refine(substream, params); - if (err < 0) - goto end; - - err = fixup_unreferenced_params(substream, params); - if (err < 0) - goto end; + if (copy_to_user(_params, params, sizeof(*params))) { + if (!err) + err = -EFAULT; + } - if (copy_to_user(_params, params, sizeof(*params))) - err = -EFAULT; -end: kfree(params); return err; } @@ -602,70 +510,6 @@ static inline void snd_pcm_timer_notify(struct snd_pcm_substream *substream, #endif } -/** - * snd_pcm_hw_param_choose - choose a configuration defined by @params - * @pcm: PCM instance - * @params: the hw_params instance - * - * Choose one configuration from configuration space defined by @params. - * The configuration chosen is that obtained fixing in this order: - * first access, first format, first subformat, min channels, - * min rate, min period time, max buffer size, min tick time - * - * Return: Zero if successful, or a negative error code on failure. - */ -static int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm, - struct snd_pcm_hw_params *params) -{ - static const int vars[] = { - SNDRV_PCM_HW_PARAM_ACCESS, - SNDRV_PCM_HW_PARAM_FORMAT, - SNDRV_PCM_HW_PARAM_SUBFORMAT, - SNDRV_PCM_HW_PARAM_CHANNELS, - SNDRV_PCM_HW_PARAM_RATE, - SNDRV_PCM_HW_PARAM_PERIOD_TIME, - SNDRV_PCM_HW_PARAM_BUFFER_SIZE, - SNDRV_PCM_HW_PARAM_TICK_TIME, - -1 - }; - const int *v; - struct snd_mask old_mask; - struct snd_interval old_interval; - int changed; - - for (v = vars; *v != -1; v++) { - /* Keep old parameter to trace. */ - if (trace_hw_mask_param_enabled()) { - if (hw_is_mask(*v)) - old_mask = *hw_param_mask(params, *v); - } - if (trace_hw_interval_param_enabled()) { - if (hw_is_interval(*v)) - old_interval = *hw_param_interval(params, *v); - } - if (*v != SNDRV_PCM_HW_PARAM_BUFFER_SIZE) - changed = snd_pcm_hw_param_first(pcm, params, *v, NULL); - else - changed = snd_pcm_hw_param_last(pcm, params, *v, NULL); - if (changed < 0) - return changed; - if (changed == 0) - continue; - - /* Trace the changed parameter. */ - if (hw_is_mask(*v)) { - trace_hw_mask_param(pcm, *v, 0, &old_mask, - hw_param_mask(params, *v)); - } - if (hw_is_interval(*v)) { - trace_hw_interval_param(pcm, *v, 0, &old_interval, - hw_param_interval(params, *v)); - } - } - - return 0; -} - static int snd_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -703,10 +547,6 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, if (err < 0) goto _error; - err = fixup_unreferenced_params(substream, params); - if (err < 0) - goto _error; - if (substream->ops->hw_params != NULL) { err = substream->ops->hw_params(substream, params); if (err < 0) @@ -782,12 +622,11 @@ static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream, return PTR_ERR(params); err = snd_pcm_hw_params(substream, params); - if (err < 0) - goto end; + if (copy_to_user(_params, params, sizeof(*params))) { + if (!err) + err = -EFAULT; + } - if (copy_to_user(_params, params, sizeof(*params))) - err = -EFAULT; -end: kfree(params); return err; } @@ -887,18 +726,6 @@ static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream, return err; } -static inline snd_pcm_uframes_t -snd_pcm_calc_delay(struct snd_pcm_substream *substream) -{ - snd_pcm_uframes_t delay; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - delay = snd_pcm_playback_hw_avail(substream->runtime); - else - delay = snd_pcm_capture_avail(substream->runtime); - return delay + substream->runtime->delay; -} - int snd_pcm_status(struct snd_pcm_substream *substream, struct snd_pcm_status *status) { @@ -950,9 +777,21 @@ int snd_pcm_status(struct snd_pcm_substream *substream, _tstamp_end: status->appl_ptr = runtime->control->appl_ptr; status->hw_ptr = runtime->status->hw_ptr; - status->avail = snd_pcm_avail(substream); - status->delay = snd_pcm_running(substream) ? - snd_pcm_calc_delay(substream) : 0; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + status->avail = snd_pcm_playback_avail(runtime); + if (runtime->status->state == SNDRV_PCM_STATE_RUNNING || + runtime->status->state == SNDRV_PCM_STATE_DRAINING) { + status->delay = runtime->buffer_size - status->avail; + status->delay += runtime->delay; + } else + status->delay = 0; + } else { + status->avail = snd_pcm_capture_avail(runtime); + if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) + status->delay = status->avail + runtime->delay; + else + status->delay = 0; + } status->avail_max = runtime->avail_max; status->overrange = runtime->overrange; runtime->avail_max = 0; @@ -1243,7 +1082,6 @@ static const struct action_ops snd_pcm_action_start = { * @substream: the PCM substream instance * * Return: Zero if successful, or a negative error code. - * The stream lock must be acquired before calling this function. */ int snd_pcm_start(struct snd_pcm_substream *substream) { @@ -1251,13 +1089,6 @@ int snd_pcm_start(struct snd_pcm_substream *substream) SNDRV_PCM_STATE_RUNNING); } -/* take the stream lock and start the streams */ -static int snd_pcm_start_lock_irq(struct snd_pcm_substream *substream) -{ - return snd_pcm_action_lock_irq(&snd_pcm_action_start, substream, - SNDRV_PCM_STATE_RUNNING); -} - /* * stop callbacks */ @@ -1309,6 +1140,7 @@ int snd_pcm_stop(struct snd_pcm_substream *substream, snd_pcm_state_t state) { return snd_pcm_action(&snd_pcm_action_stop, substream, state); } + EXPORT_SYMBOL(snd_pcm_stop); /** @@ -1338,12 +1170,13 @@ int snd_pcm_drain_done(struct snd_pcm_substream *substream) int snd_pcm_stop_xrun(struct snd_pcm_substream *substream) { unsigned long flags; + int ret = 0; snd_pcm_stream_lock_irqsave(substream, flags); - if (substream->runtime && snd_pcm_running(substream)) - __snd_pcm_xrun(substream); + if (snd_pcm_running(substream)) + ret = snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); snd_pcm_stream_unlock_irqrestore(substream, flags); - return 0; + return ret; } EXPORT_SYMBOL_GPL(snd_pcm_stop_xrun); @@ -1482,6 +1315,7 @@ int snd_pcm_suspend(struct snd_pcm_substream *substream) snd_pcm_stream_unlock_irqrestore(substream, flags); return err; } + EXPORT_SYMBOL(snd_pcm_suspend); /** @@ -1513,6 +1347,7 @@ int snd_pcm_suspend_all(struct snd_pcm *pcm) } return 0; } + EXPORT_SYMBOL(snd_pcm_suspend_all); /* resume */ @@ -1563,7 +1398,14 @@ static const struct action_ops snd_pcm_action_resume = { static int snd_pcm_resume(struct snd_pcm_substream *substream) { - return snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, 0); + struct snd_card *card = substream->pcm->card; + int res; + + snd_power_lock(card); + if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0) + res = snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, 0); + snd_power_unlock(card); + return res; } #else @@ -1582,22 +1424,31 @@ static int snd_pcm_resume(struct snd_pcm_substream *substream) */ static int snd_pcm_xrun(struct snd_pcm_substream *substream) { + struct snd_card *card = substream->pcm->card; struct snd_pcm_runtime *runtime = substream->runtime; int result; + snd_power_lock(card); + if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { + result = snd_power_wait(card, SNDRV_CTL_POWER_D0); + if (result < 0) + goto _unlock; + } + snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_XRUN: result = 0; /* already there */ break; case SNDRV_PCM_STATE_RUNNING: - __snd_pcm_xrun(substream); - result = 0; + result = snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); break; default: result = -EBADFD; } snd_pcm_stream_unlock_irq(substream); + _unlock: + snd_power_unlock(card); return result; } @@ -1701,6 +1552,8 @@ static const struct action_ops snd_pcm_action_prepare = { static int snd_pcm_prepare(struct snd_pcm_substream *substream, struct file *file) { + int res; + struct snd_card *card = substream->pcm->card; int f_flags; if (file) @@ -1708,19 +1561,12 @@ static int snd_pcm_prepare(struct snd_pcm_substream *substream, else f_flags = substream->f_flags; - snd_pcm_stream_lock_irq(substream); - switch (substream->runtime->status->state) { - case SNDRV_PCM_STATE_PAUSED: - snd_pcm_pause(substream, 0); - /* fallthru */ - case SNDRV_PCM_STATE_SUSPENDED: - snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); - break; - } - snd_pcm_stream_unlock_irq(substream); - - return snd_pcm_action_nonatomic(&snd_pcm_action_prepare, - substream, f_flags); + snd_power_lock(card); + if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0) + res = snd_pcm_action_nonatomic(&snd_pcm_action_prepare, + substream, f_flags); + snd_power_unlock(card); + return res; } /* @@ -1817,6 +1663,15 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, if (runtime->status->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; + snd_power_lock(card); + if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { + result = snd_power_wait(card, SNDRV_CTL_POWER_D0); + if (result < 0) { + snd_power_unlock(card); + return result; + } + } + if (file) { if (file->f_flags & O_NONBLOCK) nonblock = 1; @@ -1863,6 +1718,7 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, add_wait_queue(&to_check->sleep, &wait); snd_pcm_stream_unlock_irq(substream); up_read(&snd_pcm_link_rwsem); + snd_power_unlock(card); if (runtime->no_period_wakeup) tout = MAX_SCHEDULE_TIMEOUT; else { @@ -1874,6 +1730,7 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, tout = msecs_to_jiffies(tout * 1000); } tout = schedule_timeout_interruptible(tout); + snd_power_lock(card); down_read(&snd_pcm_link_rwsem); snd_pcm_stream_lock_irq(substream); remove_wait_queue(&to_check->sleep, &wait); @@ -1897,6 +1754,7 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, unlock: snd_pcm_stream_unlock_irq(substream); up_read(&snd_pcm_link_rwsem); + snd_power_unlock(card); return result; } @@ -1916,7 +1774,8 @@ static int snd_pcm_drop(struct snd_pcm_substream *substream) runtime = substream->runtime; if (runtime->status->state == SNDRV_PCM_STATE_OPEN || - runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED) + runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED || + runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) return -EBADFD; snd_pcm_stream_lock_irq(substream); @@ -2082,8 +1941,7 @@ static int snd_pcm_hw_rule_format(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { unsigned int k; - const struct snd_interval *i = - hw_param_interval_c(params, rule->deps[0]); + struct snd_interval *i = hw_param_interval(params, rule->deps[0]); struct snd_mask m; struct snd_mask *mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); snd_mask_any(&m); @@ -2129,10 +1987,8 @@ static int snd_pcm_hw_rule_sample_bits(struct snd_pcm_hw_params *params, #error "Change this table" #endif -static const unsigned int rates[] = { - 5512, 8000, 11025, 16000, 22050, 32000, 44100, - 48000, 64000, 88200, 96000, 176400, 192000 -}; +static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, + 48000, 64000, 88200, 96000, 176400, 192000 }; const struct snd_pcm_hw_constraint_list snd_pcm_known_rates = { .count = ARRAY_SIZE(rates), @@ -2396,6 +2252,7 @@ void snd_pcm_release_substream(struct snd_pcm_substream *substream) } snd_pcm_detach_substream(substream); } + EXPORT_SYMBOL(snd_pcm_release_substream); int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, @@ -2437,6 +2294,7 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, snd_pcm_release_substream(substream); return err; } + EXPORT_SYMBOL(snd_pcm_open_substream); static int snd_pcm_open_file(struct file *file, @@ -2596,6 +2454,30 @@ static int do_pcm_hwsync(struct snd_pcm_substream *substream) } } +/* update to the given appl_ptr and call ack callback if needed; + * when an error is returned, take back to the original value + */ +static int apply_appl_ptr(struct snd_pcm_substream *substream, + snd_pcm_uframes_t appl_ptr) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + snd_pcm_uframes_t old_appl_ptr = runtime->control->appl_ptr; + int ret; + + if (old_appl_ptr == appl_ptr) + return 0; + + runtime->control->appl_ptr = appl_ptr; + if (substream->ops->ack) { + ret = substream->ops->ack(substream); + if (ret < 0) { + runtime->control->appl_ptr = old_appl_ptr; + return ret; + } + } + return 0; +} + /* increase the appl_ptr; returns the processed frames or a negative error */ static snd_pcm_sframes_t forward_appl_ptr(struct snd_pcm_substream *substream, snd_pcm_uframes_t frames, @@ -2612,7 +2494,7 @@ static snd_pcm_sframes_t forward_appl_ptr(struct snd_pcm_substream *substream, appl_ptr = runtime->control->appl_ptr + frames; if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary) appl_ptr -= runtime->boundary; - ret = pcm_lib_apply_appl_ptr(substream, appl_ptr); + ret = apply_appl_ptr(substream, appl_ptr); return ret < 0 ? ret : frames; } @@ -2632,7 +2514,7 @@ static snd_pcm_sframes_t rewind_appl_ptr(struct snd_pcm_substream *substream, appl_ptr = runtime->control->appl_ptr - frames; if (appl_ptr < 0) appl_ptr += runtime->boundary; - ret = pcm_lib_apply_appl_ptr(substream, appl_ptr); + ret = apply_appl_ptr(substream, appl_ptr); /* NOTE: we return zero for errors because PulseAudio gets depressed * upon receiving an error from rewind ioctl and stops processing * any longer. Returning zero means that no rewind is done, so @@ -2641,9 +2523,10 @@ static snd_pcm_sframes_t rewind_appl_ptr(struct snd_pcm_substream *substream, return ret < 0 ? 0 : frames; } -static snd_pcm_sframes_t snd_pcm_rewind(struct snd_pcm_substream *substream, - snd_pcm_uframes_t frames) +static snd_pcm_sframes_t snd_pcm_playback_rewind(struct snd_pcm_substream *substream, + snd_pcm_uframes_t frames) { + struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_sframes_t ret; if (frames == 0) @@ -2653,14 +2536,51 @@ static snd_pcm_sframes_t snd_pcm_rewind(struct snd_pcm_substream *substream, ret = do_pcm_hwsync(substream); if (!ret) ret = rewind_appl_ptr(substream, frames, - snd_pcm_hw_avail(substream)); + snd_pcm_playback_hw_avail(runtime)); snd_pcm_stream_unlock_irq(substream); return ret; } -static snd_pcm_sframes_t snd_pcm_forward(struct snd_pcm_substream *substream, - snd_pcm_uframes_t frames) +static snd_pcm_sframes_t snd_pcm_capture_rewind(struct snd_pcm_substream *substream, + snd_pcm_uframes_t frames) { + struct snd_pcm_runtime *runtime = substream->runtime; + snd_pcm_sframes_t ret; + + if (frames == 0) + return 0; + + snd_pcm_stream_lock_irq(substream); + ret = do_pcm_hwsync(substream); + if (!ret) + ret = rewind_appl_ptr(substream, frames, + snd_pcm_capture_hw_avail(runtime)); + snd_pcm_stream_unlock_irq(substream); + return ret; +} + +static snd_pcm_sframes_t snd_pcm_playback_forward(struct snd_pcm_substream *substream, + snd_pcm_uframes_t frames) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + snd_pcm_sframes_t ret; + + if (frames == 0) + return 0; + + snd_pcm_stream_lock_irq(substream); + ret = do_pcm_hwsync(substream); + if (!ret) + ret = forward_appl_ptr(substream, frames, + snd_pcm_playback_avail(runtime)); + snd_pcm_stream_unlock_irq(substream); + return ret; +} + +static snd_pcm_sframes_t snd_pcm_capture_forward(struct snd_pcm_substream *substream, + snd_pcm_uframes_t frames) +{ + struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_sframes_t ret; if (frames == 0) @@ -2670,7 +2590,7 @@ static snd_pcm_sframes_t snd_pcm_forward(struct snd_pcm_substream *substream, ret = do_pcm_hwsync(substream); if (!ret) ret = forward_appl_ptr(substream, frames, - snd_pcm_avail(substream)); + snd_pcm_capture_avail(runtime)); snd_pcm_stream_unlock_irq(substream); return ret; } @@ -2686,18 +2606,25 @@ static int snd_pcm_hwsync(struct snd_pcm_substream *substream) } static int snd_pcm_delay(struct snd_pcm_substream *substream, - snd_pcm_sframes_t *delay) + snd_pcm_sframes_t __user *res) { + struct snd_pcm_runtime *runtime = substream->runtime; int err; snd_pcm_sframes_t n = 0; snd_pcm_stream_lock_irq(substream); err = do_pcm_hwsync(substream); - if (!err) - n = snd_pcm_calc_delay(substream); + if (!err) { + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + n = snd_pcm_playback_hw_avail(runtime); + else + n = snd_pcm_capture_avail(runtime); + n += runtime->delay; + } snd_pcm_stream_unlock_irq(substream); if (!err) - *delay = n; + if (put_user(n, res)) + err = -EFAULT; return err; } @@ -2724,8 +2651,7 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream, } snd_pcm_stream_lock_irq(substream); if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) { - err = pcm_lib_apply_appl_ptr(substream, - sync_ptr.c.control.appl_ptr); + err = apply_appl_ptr(substream, sync_ptr.c.control.appl_ptr); if (err < 0) { snd_pcm_stream_unlock_irq(substream); return err; @@ -2760,101 +2686,11 @@ static int snd_pcm_tstamp(struct snd_pcm_substream *substream, int __user *_arg) runtime->tstamp_type = arg; return 0; } - -static int snd_pcm_xferi_frames_ioctl(struct snd_pcm_substream *substream, - struct snd_xferi __user *_xferi) -{ - struct snd_xferi xferi; - struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_sframes_t result; - - if (runtime->status->state == SNDRV_PCM_STATE_OPEN) - return -EBADFD; - if (put_user(0, &_xferi->result)) - return -EFAULT; - if (copy_from_user(&xferi, _xferi, sizeof(xferi))) - return -EFAULT; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - result = snd_pcm_lib_write(substream, xferi.buf, xferi.frames); - else - result = snd_pcm_lib_read(substream, xferi.buf, xferi.frames); - __put_user(result, &_xferi->result); - return result < 0 ? result : 0; -} - -static int snd_pcm_xfern_frames_ioctl(struct snd_pcm_substream *substream, - struct snd_xfern __user *_xfern) -{ - struct snd_xfern xfern; - struct snd_pcm_runtime *runtime = substream->runtime; - void *bufs; - snd_pcm_sframes_t result; - - if (runtime->status->state == SNDRV_PCM_STATE_OPEN) - return -EBADFD; - if (runtime->channels > 128) - return -EINVAL; - if (put_user(0, &_xfern->result)) - return -EFAULT; - if (copy_from_user(&xfern, _xfern, sizeof(xfern))) - return -EFAULT; - - bufs = memdup_user(xfern.bufs, sizeof(void *) * runtime->channels); - if (IS_ERR(bufs)) - return PTR_ERR(bufs); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - result = snd_pcm_lib_writev(substream, bufs, xfern.frames); - else - result = snd_pcm_lib_readv(substream, bufs, xfern.frames); - kfree(bufs); - __put_user(result, &_xfern->result); - return result < 0 ? result : 0; -} - -static int snd_pcm_rewind_ioctl(struct snd_pcm_substream *substream, - snd_pcm_uframes_t __user *_frames) -{ - snd_pcm_uframes_t frames; - snd_pcm_sframes_t result; - - if (get_user(frames, _frames)) - return -EFAULT; - if (put_user(0, _frames)) - return -EFAULT; - result = snd_pcm_rewind(substream, frames); - __put_user(result, _frames); - return result < 0 ? result : 0; -} - -static int snd_pcm_forward_ioctl(struct snd_pcm_substream *substream, - snd_pcm_uframes_t __user *_frames) -{ - snd_pcm_uframes_t frames; - snd_pcm_sframes_t result; - - if (get_user(frames, _frames)) - return -EFAULT; - if (put_user(0, _frames)) - return -EFAULT; - result = snd_pcm_forward(substream, frames); - __put_user(result, _frames); - return result < 0 ? result : 0; -} - -static int snd_pcm_common_ioctl(struct file *file, + +static int snd_pcm_common_ioctl1(struct file *file, struct snd_pcm_substream *substream, unsigned int cmd, void __user *arg) { - struct snd_pcm_file *pcm_file = file->private_data; - int res; - - if (PCM_RUNTIME_CHECK(substream)) - return -ENXIO; - - res = snd_power_wait(substream->pcm->card, SNDRV_CTL_POWER_D0); - if (res < 0) - return res; - switch (cmd) { case SNDRV_PCM_IOCTL_PVERSION: return put_user(SNDRV_PCM_VERSION, (int __user *)arg) ? -EFAULT : 0; @@ -2864,11 +2700,6 @@ static int snd_pcm_common_ioctl(struct file *file, return 0; case SNDRV_PCM_IOCTL_TTSTAMP: return snd_pcm_tstamp(substream, arg); - case SNDRV_PCM_IOCTL_USER_PVERSION: - if (get_user(pcm_file->user_pversion, - (unsigned int __user *)arg)) - return -EFAULT; - return 0; case SNDRV_PCM_IOCTL_HW_REFINE: return snd_pcm_hw_refine_user(substream, arg); case SNDRV_PCM_IOCTL_HW_PARAMS: @@ -2888,7 +2719,7 @@ static int snd_pcm_common_ioctl(struct file *file, case SNDRV_PCM_IOCTL_RESET: return snd_pcm_reset(substream); case SNDRV_PCM_IOCTL_START: - return snd_pcm_start_lock_irq(substream); + return snd_pcm_action_lock_irq(&snd_pcm_action_start, substream, SNDRV_PCM_STATE_RUNNING); case SNDRV_PCM_IOCTL_LINK: return snd_pcm_link(substream, (int)(unsigned long) arg); case SNDRV_PCM_IOCTL_UNLINK: @@ -2900,18 +2731,7 @@ static int snd_pcm_common_ioctl(struct file *file, case SNDRV_PCM_IOCTL_HWSYNC: return snd_pcm_hwsync(substream); case SNDRV_PCM_IOCTL_DELAY: - { - snd_pcm_sframes_t delay; - snd_pcm_sframes_t __user *res = arg; - int err; - - err = snd_pcm_delay(substream, &delay); - if (err) - return err; - if (put_user(delay, res)) - return -EFAULT; - return 0; - } + return snd_pcm_delay(substream, arg); case SNDRV_PCM_IOCTL_SYNC_PTR: return snd_pcm_sync_ptr(substream, arg); #ifdef CONFIG_SND_SUPPORT_OLD_API @@ -2925,26 +2745,180 @@ static int snd_pcm_common_ioctl(struct file *file, case SNDRV_PCM_IOCTL_DROP: return snd_pcm_drop(substream); case SNDRV_PCM_IOCTL_PAUSE: - return snd_pcm_action_lock_irq(&snd_pcm_action_pause, - substream, - (int)(unsigned long)arg); + { + int res; + snd_pcm_stream_lock_irq(substream); + res = snd_pcm_pause(substream, (int)(unsigned long)arg); + snd_pcm_stream_unlock_irq(substream); + return res; + } + } + pcm_dbg(substream->pcm, "unknown ioctl = 0x%x\n", cmd); + return -ENOTTY; +} + +static int snd_pcm_playback_ioctl1(struct file *file, + struct snd_pcm_substream *substream, + unsigned int cmd, void __user *arg) +{ + if (snd_BUG_ON(!substream)) + return -ENXIO; + if (snd_BUG_ON(substream->stream != SNDRV_PCM_STREAM_PLAYBACK)) + return -EINVAL; + switch (cmd) { case SNDRV_PCM_IOCTL_WRITEI_FRAMES: - case SNDRV_PCM_IOCTL_READI_FRAMES: - return snd_pcm_xferi_frames_ioctl(substream, arg); + { + struct snd_xferi xferi; + struct snd_xferi __user *_xferi = arg; + struct snd_pcm_runtime *runtime = substream->runtime; + snd_pcm_sframes_t result; + if (runtime->status->state == SNDRV_PCM_STATE_OPEN) + return -EBADFD; + if (put_user(0, &_xferi->result)) + return -EFAULT; + if (copy_from_user(&xferi, _xferi, sizeof(xferi))) + return -EFAULT; + result = snd_pcm_lib_write(substream, xferi.buf, xferi.frames); + __put_user(result, &_xferi->result); + return result < 0 ? result : 0; + } case SNDRV_PCM_IOCTL_WRITEN_FRAMES: + { + struct snd_xfern xfern; + struct snd_xfern __user *_xfern = arg; + struct snd_pcm_runtime *runtime = substream->runtime; + void __user **bufs; + snd_pcm_sframes_t result; + if (runtime->status->state == SNDRV_PCM_STATE_OPEN) + return -EBADFD; + if (runtime->channels > 128) + return -EINVAL; + if (put_user(0, &_xfern->result)) + return -EFAULT; + if (copy_from_user(&xfern, _xfern, sizeof(xfern))) + return -EFAULT; + + bufs = memdup_user(xfern.bufs, + sizeof(void *) * runtime->channels); + if (IS_ERR(bufs)) + return PTR_ERR(bufs); + result = snd_pcm_lib_writev(substream, bufs, xfern.frames); + kfree(bufs); + __put_user(result, &_xfern->result); + return result < 0 ? result : 0; + } + case SNDRV_PCM_IOCTL_REWIND: + { + snd_pcm_uframes_t frames; + snd_pcm_uframes_t __user *_frames = arg; + snd_pcm_sframes_t result; + if (get_user(frames, _frames)) + return -EFAULT; + if (put_user(0, _frames)) + return -EFAULT; + result = snd_pcm_playback_rewind(substream, frames); + __put_user(result, _frames); + return result < 0 ? result : 0; + } + case SNDRV_PCM_IOCTL_FORWARD: + { + snd_pcm_uframes_t frames; + snd_pcm_uframes_t __user *_frames = arg; + snd_pcm_sframes_t result; + if (get_user(frames, _frames)) + return -EFAULT; + if (put_user(0, _frames)) + return -EFAULT; + result = snd_pcm_playback_forward(substream, frames); + __put_user(result, _frames); + return result < 0 ? result : 0; + } + } + return snd_pcm_common_ioctl1(file, substream, cmd, arg); +} + +static int snd_pcm_capture_ioctl1(struct file *file, + struct snd_pcm_substream *substream, + unsigned int cmd, void __user *arg) +{ + if (snd_BUG_ON(!substream)) + return -ENXIO; + if (snd_BUG_ON(substream->stream != SNDRV_PCM_STREAM_CAPTURE)) + return -EINVAL; + switch (cmd) { + case SNDRV_PCM_IOCTL_READI_FRAMES: + { + struct snd_xferi xferi; + struct snd_xferi __user *_xferi = arg; + struct snd_pcm_runtime *runtime = substream->runtime; + snd_pcm_sframes_t result; + if (runtime->status->state == SNDRV_PCM_STATE_OPEN) + return -EBADFD; + if (put_user(0, &_xferi->result)) + return -EFAULT; + if (copy_from_user(&xferi, _xferi, sizeof(xferi))) + return -EFAULT; + result = snd_pcm_lib_read(substream, xferi.buf, xferi.frames); + __put_user(result, &_xferi->result); + return result < 0 ? result : 0; + } case SNDRV_PCM_IOCTL_READN_FRAMES: - return snd_pcm_xfern_frames_ioctl(substream, arg); + { + struct snd_xfern xfern; + struct snd_xfern __user *_xfern = arg; + struct snd_pcm_runtime *runtime = substream->runtime; + void *bufs; + snd_pcm_sframes_t result; + if (runtime->status->state == SNDRV_PCM_STATE_OPEN) + return -EBADFD; + if (runtime->channels > 128) + return -EINVAL; + if (put_user(0, &_xfern->result)) + return -EFAULT; + if (copy_from_user(&xfern, _xfern, sizeof(xfern))) + return -EFAULT; + + bufs = memdup_user(xfern.bufs, + sizeof(void *) * runtime->channels); + if (IS_ERR(bufs)) + return PTR_ERR(bufs); + result = snd_pcm_lib_readv(substream, bufs, xfern.frames); + kfree(bufs); + __put_user(result, &_xfern->result); + return result < 0 ? result : 0; + } case SNDRV_PCM_IOCTL_REWIND: - return snd_pcm_rewind_ioctl(substream, arg); + { + snd_pcm_uframes_t frames; + snd_pcm_uframes_t __user *_frames = arg; + snd_pcm_sframes_t result; + if (get_user(frames, _frames)) + return -EFAULT; + if (put_user(0, _frames)) + return -EFAULT; + result = snd_pcm_capture_rewind(substream, frames); + __put_user(result, _frames); + return result < 0 ? result : 0; + } case SNDRV_PCM_IOCTL_FORWARD: - return snd_pcm_forward_ioctl(substream, arg); + { + snd_pcm_uframes_t frames; + snd_pcm_uframes_t __user *_frames = arg; + snd_pcm_sframes_t result; + if (get_user(frames, _frames)) + return -EFAULT; + if (put_user(0, _frames)) + return -EFAULT; + result = snd_pcm_capture_forward(substream, frames); + __put_user(result, _frames); + return result < 0 ? result : 0; } - pcm_dbg(substream->pcm, "unknown ioctl = 0x%x\n", cmd); - return -ENOTTY; + } + return snd_pcm_common_ioctl1(file, substream, cmd, arg); } -static long snd_pcm_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) +static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) { struct snd_pcm_file *pcm_file; @@ -2953,53 +2927,48 @@ static long snd_pcm_ioctl(struct file *file, unsigned int cmd, if (((cmd >> 8) & 0xff) != 'A') return -ENOTTY; - return snd_pcm_common_ioctl(file, pcm_file->substream, cmd, - (void __user *)arg); + return snd_pcm_playback_ioctl1(file, pcm_file->substream, cmd, + (void __user *)arg); +} + +static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct snd_pcm_file *pcm_file; + + pcm_file = file->private_data; + + if (((cmd >> 8) & 0xff) != 'A') + return -ENOTTY; + + return snd_pcm_capture_ioctl1(file, pcm_file->substream, cmd, + (void __user *)arg); } -/** - * snd_pcm_kernel_ioctl - Execute PCM ioctl in the kernel-space - * @substream: PCM substream - * @cmd: IOCTL cmd - * @arg: IOCTL argument - * - * The function is provided primarily for OSS layer and USB gadget drivers, - * and it allows only the limited set of ioctls (hw_params, sw_params, - * prepare, start, drain, drop, forward). - */ int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg) { - snd_pcm_uframes_t *frames = arg; - snd_pcm_sframes_t result; + mm_segment_t fs; + int result; - switch (cmd) { - case SNDRV_PCM_IOCTL_FORWARD: - { - /* provided only for OSS; capture-only and no value returned */ - if (substream->stream != SNDRV_PCM_STREAM_CAPTURE) - return -EINVAL; - result = snd_pcm_forward(substream, *frames); - return result < 0 ? result : 0; - } - case SNDRV_PCM_IOCTL_HW_PARAMS: - return snd_pcm_hw_params(substream, arg); - case SNDRV_PCM_IOCTL_SW_PARAMS: - return snd_pcm_sw_params(substream, arg); - case SNDRV_PCM_IOCTL_PREPARE: - return snd_pcm_prepare(substream, NULL); - case SNDRV_PCM_IOCTL_START: - return snd_pcm_start_lock_irq(substream); - case SNDRV_PCM_IOCTL_DRAIN: - return snd_pcm_drain(substream, NULL); - case SNDRV_PCM_IOCTL_DROP: - return snd_pcm_drop(substream); - case SNDRV_PCM_IOCTL_DELAY: - return snd_pcm_delay(substream, frames); + fs = snd_enter_user(); + switch (substream->stream) { + case SNDRV_PCM_STREAM_PLAYBACK: + result = snd_pcm_playback_ioctl1(NULL, substream, cmd, + (void __user *)arg); + break; + case SNDRV_PCM_STREAM_CAPTURE: + result = snd_pcm_capture_ioctl1(NULL, substream, cmd, + (void __user *)arg); + break; default: - return -EINVAL; + result = -EINVAL; + break; } + snd_leave_user(fs); + return result; } + EXPORT_SYMBOL(snd_pcm_kernel_ioctl); static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count, @@ -3121,46 +3090,82 @@ static ssize_t snd_pcm_writev(struct kiocb *iocb, struct iov_iter *from) return result; } -static unsigned int snd_pcm_poll(struct file *file, poll_table *wait) +static unsigned int snd_pcm_playback_poll(struct file *file, poll_table * wait) { struct snd_pcm_file *pcm_file; struct snd_pcm_substream *substream; struct snd_pcm_runtime *runtime; - unsigned int mask, ok; + unsigned int mask; snd_pcm_uframes_t avail; pcm_file = file->private_data; substream = pcm_file->substream; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - ok = POLLOUT | POLLWRNORM; - else - ok = POLLIN | POLLRDNORM; if (PCM_RUNTIME_CHECK(substream)) - return ok | POLLERR; + return POLLOUT | POLLWRNORM | POLLERR; + runtime = substream->runtime; + poll_wait(file, &runtime->sleep, wait); + + snd_pcm_stream_lock_irq(substream); + avail = snd_pcm_playback_avail(runtime); + switch (runtime->status->state) { + case SNDRV_PCM_STATE_RUNNING: + case SNDRV_PCM_STATE_PREPARED: + case SNDRV_PCM_STATE_PAUSED: + if (avail >= runtime->control->avail_min) { + mask = POLLOUT | POLLWRNORM; + break; + } + /* Fall through */ + case SNDRV_PCM_STATE_DRAINING: + mask = 0; + break; + default: + mask = POLLOUT | POLLWRNORM | POLLERR; + break; + } + snd_pcm_stream_unlock_irq(substream); + return mask; +} + +static unsigned int snd_pcm_capture_poll(struct file *file, poll_table * wait) +{ + struct snd_pcm_file *pcm_file; + struct snd_pcm_substream *substream; + struct snd_pcm_runtime *runtime; + unsigned int mask; + snd_pcm_uframes_t avail; + + pcm_file = file->private_data; + + substream = pcm_file->substream; + if (PCM_RUNTIME_CHECK(substream)) + return POLLIN | POLLRDNORM | POLLERR; runtime = substream->runtime; + poll_wait(file, &runtime->sleep, wait); - mask = 0; snd_pcm_stream_lock_irq(substream); - avail = snd_pcm_avail(substream); + avail = snd_pcm_capture_avail(runtime); switch (runtime->status->state) { case SNDRV_PCM_STATE_RUNNING: case SNDRV_PCM_STATE_PREPARED: case SNDRV_PCM_STATE_PAUSED: - if (avail >= runtime->control->avail_min) - mask = ok; + if (avail >= runtime->control->avail_min) { + mask = POLLIN | POLLRDNORM; + break; + } + mask = 0; break; case SNDRV_PCM_STATE_DRAINING: - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { - mask = ok; - if (!avail) - mask |= POLLERR; + if (avail > 0) { + mask = POLLIN | POLLRDNORM; + break; } - break; + /* Fall through */ default: - mask = ok | POLLERR; + mask = POLLIN | POLLRDNORM | POLLERR; break; } snd_pcm_stream_unlock_irq(substream); @@ -3247,41 +3252,10 @@ static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; return 0; } - -static bool pcm_status_mmap_allowed(struct snd_pcm_file *pcm_file) -{ - if (pcm_file->no_compat_mmap) - return false; - /* See pcm_control_mmap_allowed() below. - * Since older alsa-lib requires both status and control mmaps to be - * coupled, we have to disable the status mmap for old alsa-lib, too. - */ - if (pcm_file->user_pversion < SNDRV_PROTOCOL_VERSION(2, 0, 14) && - (pcm_file->substream->runtime->hw.info & SNDRV_PCM_INFO_SYNC_APPLPTR)) - return false; - return true; -} - -static bool pcm_control_mmap_allowed(struct snd_pcm_file *pcm_file) -{ - if (pcm_file->no_compat_mmap) - return false; - /* Disallow the control mmap when SYNC_APPLPTR flag is set; - * it enforces the user-space to fall back to snd_pcm_sync_ptr(), - * thus it effectively assures the manual update of appl_ptr. - */ - if (pcm_file->substream->runtime->hw.info & SNDRV_PCM_INFO_SYNC_APPLPTR) - return false; - return true; -} - #else /* ! coherent mmap */ /* * don't support mmap for status and control records. */ -#define pcm_status_mmap_allowed(pcm_file) false -#define pcm_control_mmap_allowed(pcm_file) false - static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file *file, struct vm_area_struct *area) { @@ -3366,7 +3340,7 @@ int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream, } #endif /* CONFIG_GENERIC_ALLOCATOR */ #ifndef CONFIG_X86 /* for avoiding warnings arch/x86/mm/pat.c */ - if (IS_ENABLED(CONFIG_HAS_DMA) && !substream->ops->page && + if (!substream->ops->page && substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV) return dma_mmap_coherent(substream->dma_buffer.dev.dev, area, @@ -3396,11 +3370,12 @@ EXPORT_SYMBOL_GPL(snd_pcm_lib_default_mmap); int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, struct vm_area_struct *area) { - struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_pcm_runtime *runtime = substream->runtime;; area->vm_page_prot = pgprot_noncached(area->vm_page_prot); return vm_iomap_memory(area, runtime->dma_addr, runtime->dma_bytes); } + EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem); #endif /* SNDRV_PCM_INFO_MMAP */ @@ -3449,6 +3424,7 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, atomic_inc(&substream->mmap_count); return err; } + EXPORT_SYMBOL(snd_pcm_mmap_data); static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area) @@ -3465,11 +3441,11 @@ static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area) offset = area->vm_pgoff << PAGE_SHIFT; switch (offset) { case SNDRV_PCM_MMAP_OFFSET_STATUS: - if (!pcm_status_mmap_allowed(pcm_file)) + if (pcm_file->no_compat_mmap) return -ENXIO; return snd_pcm_mmap_status(substream, file, area); case SNDRV_PCM_MMAP_OFFSET_CONTROL: - if (!pcm_control_mmap_allowed(pcm_file)) + if (pcm_file->no_compat_mmap) return -ENXIO; return snd_pcm_mmap_control(substream, file, area); default: @@ -3565,17 +3541,12 @@ static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream, } snd_pcm_hw_convert_from_old_params(params, oparams); err = snd_pcm_hw_refine(substream, params); - if (err < 0) - goto out_old; - - err = fixup_unreferenced_params(substream, params); - if (err < 0) - goto out_old; - snd_pcm_hw_convert_to_old_params(oparams, params); - if (copy_to_user(_oparams, oparams, sizeof(*oparams))) - err = -EFAULT; -out_old: + if (copy_to_user(_oparams, oparams, sizeof(*oparams))) { + if (!err) + err = -EFAULT; + } + kfree(oparams); out: kfree(params); @@ -3598,16 +3569,14 @@ static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream, err = PTR_ERR(oparams); goto out; } - snd_pcm_hw_convert_from_old_params(params, oparams); err = snd_pcm_hw_params(substream, params); - if (err < 0) - goto out_old; - snd_pcm_hw_convert_to_old_params(oparams, params); - if (copy_to_user(_oparams, oparams, sizeof(*oparams))) - err = -EFAULT; -out_old: + if (copy_to_user(_oparams, oparams, sizeof(*oparams))) { + if (!err) + err = -EFAULT; + } + kfree(oparams); out: kfree(params); @@ -3652,8 +3621,8 @@ const struct file_operations snd_pcm_f_ops[2] = { .open = snd_pcm_playback_open, .release = snd_pcm_release, .llseek = no_llseek, - .poll = snd_pcm_poll, - .unlocked_ioctl = snd_pcm_ioctl, + .poll = snd_pcm_playback_poll, + .unlocked_ioctl = snd_pcm_playback_ioctl, .compat_ioctl = snd_pcm_ioctl_compat, .mmap = snd_pcm_mmap, .fasync = snd_pcm_fasync, @@ -3666,8 +3635,8 @@ const struct file_operations snd_pcm_f_ops[2] = { .open = snd_pcm_capture_open, .release = snd_pcm_release, .llseek = no_llseek, - .poll = snd_pcm_poll, - .unlocked_ioctl = snd_pcm_ioctl, + .poll = snd_pcm_capture_poll, + .unlocked_ioctl = snd_pcm_capture_ioctl, .compat_ioctl = snd_pcm_ioctl_compat, .mmap = snd_pcm_mmap, .fasync = snd_pcm_fasync, diff --git a/sound/core/pcm_param_trace.h b/sound/core/pcm_param_trace.h deleted file mode 100644 index 86c8d658a25c..000000000000 --- a/sound/core/pcm_param_trace.h +++ /dev/null @@ -1,142 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM snd_pcm - -#if !defined(_PCM_PARAMS_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) -#define _PCM_PARAMS_TRACE_H - -#include <linux/tracepoint.h> - -#define HW_PARAM_ENTRY(param) {SNDRV_PCM_HW_PARAM_##param, #param} -#define hw_param_labels \ - HW_PARAM_ENTRY(ACCESS), \ - HW_PARAM_ENTRY(FORMAT), \ - HW_PARAM_ENTRY(SUBFORMAT), \ - HW_PARAM_ENTRY(SAMPLE_BITS), \ - HW_PARAM_ENTRY(FRAME_BITS), \ - HW_PARAM_ENTRY(CHANNELS), \ - HW_PARAM_ENTRY(RATE), \ - HW_PARAM_ENTRY(PERIOD_TIME), \ - HW_PARAM_ENTRY(PERIOD_SIZE), \ - HW_PARAM_ENTRY(PERIOD_BYTES), \ - HW_PARAM_ENTRY(PERIODS), \ - HW_PARAM_ENTRY(BUFFER_TIME), \ - HW_PARAM_ENTRY(BUFFER_SIZE), \ - HW_PARAM_ENTRY(BUFFER_BYTES), \ - HW_PARAM_ENTRY(TICK_TIME) - -TRACE_EVENT(hw_mask_param, - TP_PROTO(struct snd_pcm_substream *substream, snd_pcm_hw_param_t type, int index, const struct snd_mask *prev, const struct snd_mask *curr), - TP_ARGS(substream, type, index, prev, curr), - TP_STRUCT__entry( - __field(int, card) - __field(int, device) - __field(int, subdevice) - __field(int, direction) - __field(snd_pcm_hw_param_t, type) - __field(int, index) - __field(int, total) - __array(__u32, prev_bits, 8) - __array(__u32, curr_bits, 8) - ), - TP_fast_assign( - __entry->card = substream->pcm->card->number; - __entry->device = substream->pcm->device; - __entry->subdevice = substream->number; - __entry->direction = substream->stream; - __entry->type = type; - __entry->index = index; - __entry->total = substream->runtime->hw_constraints.rules_num; - memcpy(__entry->prev_bits, prev->bits, sizeof(__u32) * 8); - memcpy(__entry->curr_bits, curr->bits, sizeof(__u32) * 8); - ), - TP_printk("pcmC%dD%d%s:%d %03d/%03d %s %08x%08x%08x%08x %08x%08x%08x%08x", - __entry->card, - __entry->device, - __entry->direction ? "c" : "p", - __entry->subdevice, - __entry->index, - __entry->total, - __print_symbolic(__entry->type, hw_param_labels), - __entry->prev_bits[3], __entry->prev_bits[2], - __entry->prev_bits[1], __entry->prev_bits[0], - __entry->curr_bits[3], __entry->curr_bits[2], - __entry->curr_bits[1], __entry->curr_bits[0] - ) -); - -TRACE_EVENT(hw_interval_param, - TP_PROTO(struct snd_pcm_substream *substream, snd_pcm_hw_param_t type, int index, const struct snd_interval *prev, const struct snd_interval *curr), - TP_ARGS(substream, type, index, prev, curr), - TP_STRUCT__entry( - __field(int, card) - __field(int, device) - __field(int, subdevice) - __field(int, direction) - __field(snd_pcm_hw_param_t, type) - __field(int, index) - __field(int, total) - __field(unsigned int, prev_min) - __field(unsigned int, prev_max) - __field(unsigned int, prev_openmin) - __field(unsigned int, prev_openmax) - __field(unsigned int, prev_integer) - __field(unsigned int, prev_empty) - __field(unsigned int, curr_min) - __field(unsigned int, curr_max) - __field(unsigned int, curr_openmin) - __field(unsigned int, curr_openmax) - __field(unsigned int, curr_integer) - __field(unsigned int, curr_empty) - ), - TP_fast_assign( - __entry->card = substream->pcm->card->number; - __entry->device = substream->pcm->device; - __entry->subdevice = substream->number; - __entry->direction = substream->stream; - __entry->type = type; - __entry->index = index; - __entry->total = substream->runtime->hw_constraints.rules_num; - __entry->prev_min = prev->min; - __entry->prev_max = prev->max; - __entry->prev_openmin = prev->openmin; - __entry->prev_openmax = prev->openmax; - __entry->prev_integer = prev->integer; - __entry->prev_empty = prev->empty; - __entry->curr_min = curr->min; - __entry->curr_max = curr->max; - __entry->curr_openmin = curr->openmin; - __entry->curr_openmax = curr->openmax; - __entry->curr_integer = curr->integer; - __entry->curr_empty = curr->empty; - ), - TP_printk("pcmC%dD%d%s:%d %03d/%03d %s %d %d %s%u %u%s %d %d %s%u %u%s", - __entry->card, - __entry->device, - __entry->direction ? "c" : "p", - __entry->subdevice, - __entry->index, - __entry->total, - __print_symbolic(__entry->type, hw_param_labels), - __entry->prev_empty, - __entry->prev_integer, - __entry->prev_openmin ? "(" : "[", - __entry->prev_min, - __entry->prev_max, - __entry->prev_openmax ? ")" : "]", - __entry->curr_empty, - __entry->curr_integer, - __entry->curr_openmin ? "(" : "[", - __entry->curr_min, - __entry->curr_max, - __entry->curr_openmax ? ")" : "]" - ) -); - -#endif /* _PCM_PARAMS_TRACE_H */ - -/* This part must be outside protection */ -#undef TRACE_INCLUDE_PATH -#define TRACE_INCLUDE_PATH . -#undef TRACE_INCLUDE_FILE -#define TRACE_INCLUDE_FILE pcm_param_trace -#include <trace/define_trace.h> diff --git a/sound/core/pcm_timer.c b/sound/core/pcm_timer.c index 11389f13de73..20ecd8f18080 100644 --- a/sound/core/pcm_timer.c +++ b/sound/core/pcm_timer.c @@ -25,8 +25,6 @@ #include <sound/pcm.h> #include <sound/timer.h> -#include "pcm_local.h" - /* * Timer functions */ @@ -35,8 +33,8 @@ void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream) { unsigned long rate, mult, fsize, l, post; struct snd_pcm_runtime *runtime = substream->runtime; - - mult = 1000000000; + + mult = 1000000000; rate = runtime->rate; if (snd_BUG_ON(!rate)) return; @@ -67,7 +65,7 @@ void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream) static unsigned long snd_pcm_timer_resolution(struct snd_timer * timer) { struct snd_pcm_substream *substream; - + substream = timer->private_data; return substream->runtime ? substream->runtime->timer_resolution : 0; } @@ -75,7 +73,7 @@ static unsigned long snd_pcm_timer_resolution(struct snd_timer * timer) static int snd_pcm_timer_start(struct snd_timer * timer) { struct snd_pcm_substream *substream; - + substream = snd_timer_chip(timer); substream->timer_running = 1; return 0; @@ -84,7 +82,7 @@ static int snd_pcm_timer_start(struct snd_timer * timer) static int snd_pcm_timer_stop(struct snd_timer * timer) { struct snd_pcm_substream *substream; - + substream = snd_timer_chip(timer); substream->timer_running = 0; return 0; @@ -114,7 +112,7 @@ void snd_pcm_timer_init(struct snd_pcm_substream *substream) { struct snd_timer_id tid; struct snd_timer *timer; - + tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE; tid.dev_class = SNDRV_TIMER_CLASS_PCM; tid.card = substream->pcm->card->number; diff --git a/sound/core/pcm_trace.h b/sound/core/pcm_trace.h index 3ddec1b8ae46..b63b654da5ff 100644 --- a/sound/core/pcm_trace.h +++ b/sound/core/pcm_trace.h @@ -34,9 +34,9 @@ TRACE_EVENT(hwptr, __entry->old_hw_ptr = (substream)->runtime->status->hw_ptr; __entry->hw_ptr_base = (substream)->runtime->hw_ptr_base; ), - TP_printk("pcmC%dD%d%s/sub%d: %s: pos=%lu, old=%lu, base=%lu, period=%lu, buf=%lu", + TP_printk("pcmC%dD%d%c/sub%d: %s: pos=%lu, old=%lu, base=%lu, period=%lu, buf=%lu", __entry->card, __entry->device, - __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? "p" : "c", + __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c', __entry->number, __entry->in_interrupt ? "IRQ" : "POS", (unsigned long)__entry->pos, @@ -69,9 +69,9 @@ TRACE_EVENT(xrun, __entry->old_hw_ptr = (substream)->runtime->status->hw_ptr; __entry->hw_ptr_base = (substream)->runtime->hw_ptr_base; ), - TP_printk("pcmC%dD%d%s/sub%d: XRUN: old=%lu, base=%lu, period=%lu, buf=%lu", + TP_printk("pcmC%dD%d%c/sub%d: XRUN: old=%lu, base=%lu, period=%lu, buf=%lu", __entry->card, __entry->device, - __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? "p" : "c", + __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c', __entry->number, (unsigned long)__entry->old_hw_ptr, (unsigned long)__entry->hw_ptr_base, @@ -96,50 +96,12 @@ TRACE_EVENT(hw_ptr_error, __entry->stream = (substream)->stream; __entry->reason = (why); ), - TP_printk("pcmC%dD%d%s/sub%d: ERROR: %s", + TP_printk("pcmC%dD%d%c/sub%d: ERROR: %s", __entry->card, __entry->device, - __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? "p" : "c", + __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c', __entry->number, __entry->reason) ); -TRACE_EVENT(applptr, - TP_PROTO(struct snd_pcm_substream *substream, snd_pcm_uframes_t prev, snd_pcm_uframes_t curr), - TP_ARGS(substream, prev, curr), - TP_STRUCT__entry( - __field( unsigned int, card ) - __field( unsigned int, device ) - __field( unsigned int, number ) - __field( unsigned int, stream ) - __field( snd_pcm_uframes_t, prev ) - __field( snd_pcm_uframes_t, curr ) - __field( snd_pcm_uframes_t, avail ) - __field( snd_pcm_uframes_t, period_size ) - __field( snd_pcm_uframes_t, buffer_size ) - ), - TP_fast_assign( - __entry->card = (substream)->pcm->card->number; - __entry->device = (substream)->pcm->device; - __entry->number = (substream)->number; - __entry->stream = (substream)->stream; - __entry->prev = (prev); - __entry->curr = (curr); - __entry->avail = (substream)->stream ? snd_pcm_capture_avail(substream->runtime) : snd_pcm_playback_avail(substream->runtime); - __entry->period_size = (substream)->runtime->period_size; - __entry->buffer_size = (substream)->runtime->buffer_size; - ), - TP_printk("pcmC%dD%d%s/sub%d: prev=%lu, curr=%lu, avail=%lu, period=%lu, buf=%lu", - __entry->card, - __entry->device, - __entry->stream ? "c" : "p", - __entry->number, - __entry->prev, - __entry->curr, - __entry->avail, - __entry->period_size, - __entry->buffer_size - ) -); - #endif /* _PCM_TRACE_H */ /* This part must be outside protection */ diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index e8197bbd12b8..ac39b3f591f4 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -29,7 +29,6 @@ #include <linux/mutex.h> #include <linux/module.h> #include <linux/delay.h> -#include <linux/mm.h> #include <sound/rawmidi.h> #include <sound/info.h> #include <sound/control.h> @@ -89,7 +88,6 @@ static inline unsigned short snd_rawmidi_file_flags(struct file *file) static inline int snd_rawmidi_ready(struct snd_rawmidi_substream *substream) { struct snd_rawmidi_runtime *runtime = substream->runtime; - return runtime->avail >= runtime->avail_min; } @@ -97,7 +95,6 @@ static inline int snd_rawmidi_ready_append(struct snd_rawmidi_substream *substre size_t count) { struct snd_rawmidi_runtime *runtime = substream->runtime; - return runtime->avail >= runtime->avail_min && (!substream->append || runtime->avail >= count); } @@ -106,7 +103,6 @@ static void snd_rawmidi_input_event_work(struct work_struct *work) { struct snd_rawmidi_runtime *runtime = container_of(work, struct snd_rawmidi_runtime, event_work); - if (runtime->event) runtime->event(runtime->substream); } @@ -115,8 +111,7 @@ static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream) { struct snd_rawmidi_runtime *runtime; - runtime = kzalloc(sizeof(*runtime), GFP_KERNEL); - if (!runtime) + if ((runtime = kzalloc(sizeof(*runtime), GFP_KERNEL)) == NULL) return -ENOMEM; runtime->substream = substream; spin_lock_init(&runtime->lock); @@ -129,8 +124,7 @@ static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream) runtime->avail = 0; else runtime->avail = runtime->buffer_size; - runtime->buffer = kvzalloc(runtime->buffer_size, GFP_KERNEL); - if (!runtime->buffer) { + if ((runtime->buffer = kmalloc(runtime->buffer_size, GFP_KERNEL)) == NULL) { kfree(runtime); return -ENOMEM; } @@ -143,13 +137,13 @@ static int snd_rawmidi_runtime_free(struct snd_rawmidi_substream *substream) { struct snd_rawmidi_runtime *runtime = substream->runtime; - kvfree(runtime->buffer); + kfree(runtime->buffer); kfree(runtime); substream->runtime = NULL; return 0; } -static inline void snd_rawmidi_output_trigger(struct snd_rawmidi_substream *substream, int up) +static inline void snd_rawmidi_output_trigger(struct snd_rawmidi_substream *substream,int up) { if (!substream->opened) return; @@ -165,28 +159,17 @@ static void snd_rawmidi_input_trigger(struct snd_rawmidi_substream *substream, i cancel_work_sync(&substream->runtime->event_work); } -static void __reset_runtime_ptrs(struct snd_rawmidi_runtime *runtime, - bool is_input) -{ - runtime->drain = 0; - runtime->appl_ptr = runtime->hw_ptr = 0; - runtime->avail = is_input ? 0 : runtime->buffer_size; -} - -static void reset_runtime_ptrs(struct snd_rawmidi_runtime *runtime, - bool is_input) +int snd_rawmidi_drop_output(struct snd_rawmidi_substream *substream) { unsigned long flags; + struct snd_rawmidi_runtime *runtime = substream->runtime; + snd_rawmidi_output_trigger(substream, 0); + runtime->drain = 0; spin_lock_irqsave(&runtime->lock, flags); - __reset_runtime_ptrs(runtime, is_input); + runtime->appl_ptr = runtime->hw_ptr = 0; + runtime->avail = runtime->buffer_size; spin_unlock_irqrestore(&runtime->lock, flags); -} - -int snd_rawmidi_drop_output(struct snd_rawmidi_substream *substream) -{ - snd_rawmidi_output_trigger(substream, 0); - reset_runtime_ptrs(substream->runtime, false); return 0; } EXPORT_SYMBOL(snd_rawmidi_drop_output); @@ -225,8 +208,15 @@ EXPORT_SYMBOL(snd_rawmidi_drain_output); int snd_rawmidi_drain_input(struct snd_rawmidi_substream *substream) { + unsigned long flags; + struct snd_rawmidi_runtime *runtime = substream->runtime; + snd_rawmidi_input_trigger(substream, 0); - reset_runtime_ptrs(substream->runtime, true); + runtime->drain = 0; + spin_lock_irqsave(&runtime->lock, flags); + runtime->appl_ptr = runtime->hw_ptr = 0; + runtime->avail = 0; + spin_unlock_irqrestore(&runtime->lock, flags); return 0; } EXPORT_SYMBOL(snd_rawmidi_drain_input); @@ -340,23 +330,25 @@ static int rawmidi_open_priv(struct snd_rawmidi *rmidi, int subdevice, int mode, /* called from sound/core/seq/seq_midi.c */ int snd_rawmidi_kernel_open(struct snd_card *card, int device, int subdevice, - int mode, struct snd_rawmidi_file *rfile) + int mode, struct snd_rawmidi_file * rfile) { struct snd_rawmidi *rmidi; - int err = 0; + int err; if (snd_BUG_ON(!rfile)) return -EINVAL; mutex_lock(®ister_mutex); rmidi = snd_rawmidi_search(card, device); - if (!rmidi) - err = -ENODEV; - else if (!try_module_get(rmidi->card->module)) - err = -ENXIO; + if (rmidi == NULL) { + mutex_unlock(®ister_mutex); + return -ENODEV; + } + if (!try_module_get(rmidi->card->module)) { + mutex_unlock(®ister_mutex); + return -ENXIO; + } mutex_unlock(®ister_mutex); - if (err < 0) - return err; mutex_lock(&rmidi->open_mutex); err = rawmidi_open_priv(rmidi, subdevice, mode, rfile); @@ -378,7 +370,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) struct snd_rawmidi_file *rawmidi_file = NULL; wait_queue_entry_t wait; - if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK)) + if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK)) return -EINVAL; /* invalid combination */ err = nonseekable_open(inode, file); @@ -528,7 +520,7 @@ int snd_rawmidi_kernel_release(struct snd_rawmidi_file *rfile) if (snd_BUG_ON(!rfile)) return -ENXIO; - + rmidi = rfile->rmidi; rawmidi_release_priv(rfile); module_put(rmidi->card->module); @@ -556,7 +548,7 @@ static int snd_rawmidi_info(struct snd_rawmidi_substream *substream, struct snd_rawmidi_info *info) { struct snd_rawmidi *rmidi; - + if (substream == NULL) return -ENODEV; rmidi = substream->rmidi; @@ -576,13 +568,11 @@ static int snd_rawmidi_info(struct snd_rawmidi_substream *substream, } static int snd_rawmidi_info_user(struct snd_rawmidi_substream *substream, - struct snd_rawmidi_info __user *_info) + struct snd_rawmidi_info __user * _info) { struct snd_rawmidi_info info; int err; - - err = snd_rawmidi_info(substream, &info); - if (err < 0) + if ((err = snd_rawmidi_info(substream, &info)) < 0) return err; if (copy_to_user(_info, &info, sizeof(struct snd_rawmidi_info))) return -EFAULT; @@ -629,68 +619,85 @@ static int snd_rawmidi_info_select_user(struct snd_card *card, { int err; struct snd_rawmidi_info info; - if (get_user(info.device, &_info->device)) return -EFAULT; if (get_user(info.stream, &_info->stream)) return -EFAULT; if (get_user(info.subdevice, &_info->subdevice)) return -EFAULT; - err = snd_rawmidi_info_select(card, &info); - if (err < 0) + if ((err = snd_rawmidi_info_select(card, &info)) < 0) return err; if (copy_to_user(_info, &info, sizeof(struct snd_rawmidi_info))) return -EFAULT; return 0; } -static int resize_runtime_buffer(struct snd_rawmidi_runtime *runtime, - struct snd_rawmidi_params *params, - bool is_input) +int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream, + struct snd_rawmidi_params * params) { char *newbuf, *oldbuf; - - if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L) + struct snd_rawmidi_runtime *runtime = substream->runtime; + + if (substream->append && substream->use_count > 1) + return -EBUSY; + snd_rawmidi_drain_output(substream); + if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L) { return -EINVAL; - if (params->avail_min < 1 || params->avail_min > params->buffer_size) + } + if (params->avail_min < 1 || params->avail_min > params->buffer_size) { return -EINVAL; + } if (params->buffer_size != runtime->buffer_size) { - newbuf = kvzalloc(params->buffer_size, GFP_KERNEL); + newbuf = kmalloc(params->buffer_size, GFP_KERNEL); if (!newbuf) return -ENOMEM; spin_lock_irq(&runtime->lock); oldbuf = runtime->buffer; runtime->buffer = newbuf; runtime->buffer_size = params->buffer_size; - __reset_runtime_ptrs(runtime, is_input); + runtime->avail = runtime->buffer_size; + runtime->appl_ptr = runtime->hw_ptr = 0; spin_unlock_irq(&runtime->lock); - kvfree(oldbuf); + kfree(oldbuf); } runtime->avail_min = params->avail_min; - return 0; -} - -int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream, - struct snd_rawmidi_params *params) -{ - if (substream->append && substream->use_count > 1) - return -EBUSY; - snd_rawmidi_drain_output(substream); substream->active_sensing = !params->no_active_sensing; - return resize_runtime_buffer(substream->runtime, params, false); + return 0; } EXPORT_SYMBOL(snd_rawmidi_output_params); int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream, - struct snd_rawmidi_params *params) + struct snd_rawmidi_params * params) { + char *newbuf, *oldbuf; + struct snd_rawmidi_runtime *runtime = substream->runtime; + snd_rawmidi_drain_input(substream); - return resize_runtime_buffer(substream->runtime, params, true); + if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L) { + return -EINVAL; + } + if (params->avail_min < 1 || params->avail_min > params->buffer_size) { + return -EINVAL; + } + if (params->buffer_size != runtime->buffer_size) { + newbuf = kmalloc(params->buffer_size, GFP_KERNEL); + if (!newbuf) + return -ENOMEM; + spin_lock_irq(&runtime->lock); + oldbuf = runtime->buffer; + runtime->buffer = newbuf; + runtime->buffer_size = params->buffer_size; + runtime->appl_ptr = runtime->hw_ptr = 0; + spin_unlock_irq(&runtime->lock); + kfree(oldbuf); + } + runtime->avail_min = params->avail_min; + return 0; } EXPORT_SYMBOL(snd_rawmidi_input_params); static int snd_rawmidi_output_status(struct snd_rawmidi_substream *substream, - struct snd_rawmidi_status *status) + struct snd_rawmidi_status * status) { struct snd_rawmidi_runtime *runtime = substream->runtime; @@ -703,7 +710,7 @@ static int snd_rawmidi_output_status(struct snd_rawmidi_substream *substream, } static int snd_rawmidi_input_status(struct snd_rawmidi_substream *substream, - struct snd_rawmidi_status *status) + struct snd_rawmidi_status * status) { struct snd_rawmidi_runtime *runtime = substream->runtime; @@ -732,7 +739,6 @@ static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long { int stream; struct snd_rawmidi_info __user *info = argp; - if (get_user(stream, &info->stream)) return -EFAULT; switch (stream) { @@ -747,7 +753,6 @@ static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long case SNDRV_RAWMIDI_IOCTL_PARAMS: { struct snd_rawmidi_params params; - if (copy_from_user(¶ms, argp, sizeof(struct snd_rawmidi_params))) return -EFAULT; switch (params.stream) { @@ -767,7 +772,6 @@ static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long { int err = 0; struct snd_rawmidi_status status; - if (copy_from_user(&status, argp, sizeof(struct snd_rawmidi_status))) return -EFAULT; switch (status.stream) { @@ -793,7 +797,6 @@ static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long case SNDRV_RAWMIDI_IOCTL_DROP: { int val; - if (get_user(val, (int __user *) argp)) return -EFAULT; switch (val) { @@ -808,7 +811,6 @@ static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long case SNDRV_RAWMIDI_IOCTL_DRAIN: { int val; - if (get_user(val, (int __user *) argp)) return -EFAULT; switch (val) { @@ -842,7 +844,7 @@ static int snd_rawmidi_control_ioctl(struct snd_card *card, case SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE: { int device; - + if (get_user(device, (int __user *)argp)) return -EFAULT; if (device >= SNDRV_RAWMIDI_DEVICES) /* next device is -1 */ @@ -864,7 +866,7 @@ static int snd_rawmidi_control_ioctl(struct snd_card *card, case SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE: { int val; - + if (get_user(val, (int __user *)argp)) return -EFAULT; control->preferred_subdevice[SND_CTL_SUBDEV_RAWMIDI] = val; @@ -1018,7 +1020,6 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun spin_lock_irq(&runtime->lock); while (!snd_rawmidi_ready(substream)) { wait_queue_entry_t wait; - if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) { spin_unlock_irq(&runtime->lock); return result > 0 ? result : -EAGAIN; @@ -1071,7 +1072,7 @@ int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream) spin_lock_irqsave(&runtime->lock, flags); result = runtime->avail >= runtime->buffer_size; spin_unlock_irqrestore(&runtime->lock, flags); - return result; + return result; } EXPORT_SYMBOL(snd_rawmidi_transmit_empty); @@ -1209,7 +1210,7 @@ EXPORT_SYMBOL(snd_rawmidi_transmit_ack); * @substream: the rawmidi substream * @buffer: the buffer pointer * @count: the data size to transfer - * + * * Copies data from the buffer to the device and advances the pointer. * * Return: The copied size if successful, or a negative error code on failure. @@ -1236,28 +1237,6 @@ int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream, } EXPORT_SYMBOL(snd_rawmidi_transmit); -/** - * snd_rawmidi_proceed - Discard the all pending bytes and proceed - * @substream: rawmidi substream - * - * Return: the number of discarded bytes - */ -int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream) -{ - struct snd_rawmidi_runtime *runtime = substream->runtime; - unsigned long flags; - int count = 0; - - spin_lock_irqsave(&runtime->lock, flags); - if (runtime->avail < runtime->buffer_size) { - count = runtime->buffer_size - runtime->avail; - __snd_rawmidi_transmit_ack(substream, count); - } - spin_unlock_irqrestore(&runtime->lock, flags); - return count; -} -EXPORT_SYMBOL(snd_rawmidi_proceed); - static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, const unsigned char __user *userbuf, const unsigned char *kernelbuf, @@ -1345,7 +1324,6 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, spin_lock_irq(&runtime->lock); while (!snd_rawmidi_ready_append(substream, count)) { wait_queue_entry_t wait; - if (file->f_flags & O_NONBLOCK) { spin_unlock_irq(&runtime->lock); return result > 0 ? result : -EAGAIN; @@ -1379,7 +1357,6 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, while (runtime->avail != runtime->buffer_size) { wait_queue_entry_t wait; unsigned int last_avail = runtime->avail; - init_waitqueue_entry(&wait, current); add_wait_queue(&runtime->sleep, &wait); set_current_state(TASK_INTERRUPTIBLE); @@ -1397,7 +1374,7 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, return result; } -static unsigned int snd_rawmidi_poll(struct file *file, poll_table *wait) +static unsigned int snd_rawmidi_poll(struct file *file, poll_table * wait) { struct snd_rawmidi_file *rfile; struct snd_rawmidi_runtime *runtime; @@ -1434,6 +1411,7 @@ static unsigned int snd_rawmidi_poll(struct file *file, poll_table *wait) #endif /* + */ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, @@ -1501,7 +1479,8 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, * Register functions */ -static const struct file_operations snd_rawmidi_f_ops = { +static const struct file_operations snd_rawmidi_f_ops = +{ .owner = THIS_MODULE, .read = snd_rawmidi_read, .write = snd_rawmidi_write, @@ -1556,7 +1535,7 @@ static void release_rawmidi_device(struct device *dev) */ int snd_rawmidi_new(struct snd_card *card, char *id, int device, int output_count, int input_count, - struct snd_rawmidi **rrawmidi) + struct snd_rawmidi ** rrawmidi) { struct snd_rawmidi *rmidi; int err; @@ -1587,29 +1566,27 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device, rmidi->dev.release = release_rawmidi_device; dev_set_name(&rmidi->dev, "midiC%iD%i", card->number, device); - err = snd_rawmidi_alloc_substreams(rmidi, - &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT], - SNDRV_RAWMIDI_STREAM_INPUT, - input_count); - if (err < 0) - goto error; - err = snd_rawmidi_alloc_substreams(rmidi, - &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT], - SNDRV_RAWMIDI_STREAM_OUTPUT, - output_count); - if (err < 0) - goto error; - err = snd_device_new(card, SNDRV_DEV_RAWMIDI, rmidi, &ops); - if (err < 0) - goto error; - + if ((err = snd_rawmidi_alloc_substreams(rmidi, + &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT], + SNDRV_RAWMIDI_STREAM_INPUT, + input_count)) < 0) { + snd_rawmidi_free(rmidi); + return err; + } + if ((err = snd_rawmidi_alloc_substreams(rmidi, + &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT], + SNDRV_RAWMIDI_STREAM_OUTPUT, + output_count)) < 0) { + snd_rawmidi_free(rmidi); + return err; + } + if ((err = snd_device_new(card, SNDRV_DEV_RAWMIDI, rmidi, &ops)) < 0) { + snd_rawmidi_free(rmidi); + return err; + } if (rrawmidi) *rrawmidi = rmidi; return 0; - - error: - snd_rawmidi_free(rmidi); - return err; } EXPORT_SYMBOL(snd_rawmidi_new); @@ -1647,15 +1624,13 @@ static int snd_rawmidi_free(struct snd_rawmidi *rmidi) static int snd_rawmidi_dev_free(struct snd_device *device) { struct snd_rawmidi *rmidi = device->device_data; - return snd_rawmidi_free(rmidi); } -#if IS_ENABLED(CONFIG_SND_SEQUENCER) +#if IS_REACHABLE(CONFIG_SND_SEQUENCER) static void snd_rawmidi_dev_seq_free(struct snd_seq_device *device) { struct snd_rawmidi *rmidi = device->private_data; - rmidi->seq_dev = NULL; } #endif @@ -1669,27 +1644,30 @@ static int snd_rawmidi_dev_register(struct snd_device *device) if (rmidi->device >= SNDRV_RAWMIDI_DEVICES) return -ENOMEM; - err = 0; mutex_lock(®ister_mutex); - if (snd_rawmidi_search(rmidi->card, rmidi->device)) - err = -EBUSY; - else - list_add_tail(&rmidi->list, &snd_rawmidi_devices); + if (snd_rawmidi_search(rmidi->card, rmidi->device)) { + mutex_unlock(®ister_mutex); + return -EBUSY; + } + list_add_tail(&rmidi->list, &snd_rawmidi_devices); mutex_unlock(®ister_mutex); - if (err < 0) - return err; - err = snd_register_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device, &snd_rawmidi_f_ops, rmidi, &rmidi->dev); if (err < 0) { rmidi_err(rmidi, "unable to register\n"); - goto error; + mutex_lock(®ister_mutex); + list_del(&rmidi->list); + mutex_unlock(®ister_mutex); + return err; } - if (rmidi->ops && rmidi->ops->dev_register) { - err = rmidi->ops->dev_register(rmidi); - if (err < 0) - goto error_unregister; + if (rmidi->ops && rmidi->ops->dev_register && + (err = rmidi->ops->dev_register(rmidi)) < 0) { + snd_unregister_device(&rmidi->dev); + mutex_lock(®ister_mutex); + list_del(&rmidi->list); + mutex_unlock(®ister_mutex); + return err; } #ifdef CONFIG_SND_OSSEMUL rmidi->ossreg = 0; @@ -1730,7 +1708,7 @@ static int snd_rawmidi_dev_register(struct snd_device *device) } } rmidi->proc_entry = entry; -#if IS_ENABLED(CONFIG_SND_SEQUENCER) +#if IS_REACHABLE(CONFIG_SND_SEQUENCER) if (!rmidi->ops || !rmidi->ops->dev_register) { /* own registration mechanism */ if (snd_seq_device_new(rmidi->card, rmidi->device, SNDRV_SEQ_DEV_ID_MIDISYNTH, 0, &rmidi->seq_dev) >= 0) { rmidi->seq_dev->private_data = rmidi; @@ -1741,14 +1719,6 @@ static int snd_rawmidi_dev_register(struct snd_device *device) } #endif return 0; - - error_unregister: - snd_unregister_device(&rmidi->dev); - error: - mutex_lock(®ister_mutex); - list_del(&rmidi->list); - mutex_unlock(®ister_mutex); - return err; } static int snd_rawmidi_dev_disconnect(struct snd_device *device) @@ -1762,7 +1732,6 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device) list_del_init(&rmidi->list); for (dir = 0; dir < 2; dir++) { struct snd_rawmidi_substream *s; - list_for_each_entry(s, &rmidi->streams[dir].substreams, list) { if (s->runtime) wake_up(&s->runtime->sleep); @@ -1800,7 +1769,7 @@ void snd_rawmidi_set_ops(struct snd_rawmidi *rmidi, int stream, const struct snd_rawmidi_ops *ops) { struct snd_rawmidi_substream *substream; - + list_for_each_entry(substream, &rmidi->streams[stream].substreams, list) substream->ops = ops; } diff --git a/sound/core/seq/Kconfig b/sound/core/seq/Kconfig index 45c1336c6597..b851fd890a89 100644 --- a/sound/core/seq/Kconfig +++ b/sound/core/seq/Kconfig @@ -1,62 +1,16 @@ -config SND_SEQUENCER - tristate "Sequencer support" - select SND_TIMER - select SND_SEQ_DEVICE - help - Say Y or M to enable MIDI sequencer and router support. This - feature allows routing and enqueueing of MIDI events. Events - can be processed at a given time. +# define SND_XXX_SEQ to min(SND_SEQUENCER,SND_XXX) - Many programs require this feature, so you should enable it - unless you know what you're doing. +config SND_RAWMIDI_SEQ + def_tristate SND_SEQUENCER && SND_RAWMIDI -if SND_SEQUENCER +config SND_OPL3_LIB_SEQ + def_tristate SND_SEQUENCER && SND_OPL3_LIB -config SND_SEQ_DUMMY - tristate "Sequencer dummy client" - help - Say Y here to enable the dummy sequencer client. This client - is a simple MIDI-through client: all normal input events are - redirected to the output port immediately. +config SND_OPL4_LIB_SEQ + def_tristate SND_SEQUENCER && SND_OPL4_LIB - You don't need this unless you want to connect many MIDI - devices or applications together. +config SND_SBAWE_SEQ + def_tristate SND_SEQUENCER && SND_SBAWE - To compile this driver as a module, choose M here: the module - will be called snd-seq-dummy. - -config SND_SEQUENCER_OSS - tristate "OSS Sequencer API" - depends on SND_OSSEMUL - select SND_SEQ_MIDI_EVENT - help - Say Y here to enable OSS sequencer emulation (both - /dev/sequencer and /dev/music interfaces). - - Many programs still use the OSS API, so say Y. - - To compile this driver as a module, choose M here: the module - will be called snd-seq-oss. - -config SND_SEQ_HRTIMER_DEFAULT - bool "Use HR-timer as default sequencer timer" - depends on SND_HRTIMER - default y - help - Say Y here to use the HR-timer backend as the default sequencer - timer. - -config SND_SEQ_MIDI_EVENT - tristate - -config SND_SEQ_MIDI - def_tristate SND_RAWMIDI - select SND_SEQ_MIDI_EVENT - -config SND_SEQ_MIDI_EMUL - tristate - -config SND_SEQ_VIRMIDI - tristate - -endif # SND_SEQUENCER +config SND_EMU10K1_SEQ + def_tristate SND_SEQUENCER && SND_EMU10K1 diff --git a/sound/core/seq/Makefile b/sound/core/seq/Makefile index 68fd367ac39c..b65fa5a1943b 100644 --- a/sound/core/seq/Makefile +++ b/sound/core/seq/Makefile @@ -3,6 +3,7 @@ # Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> # +snd-seq-device-objs := seq_device.o snd-seq-objs := seq.o seq_lock.o seq_clientmgr.o seq_memory.o seq_queue.o \ seq_fifo.o seq_prioq.o seq_timer.o \ seq_system.o seq_ports.o @@ -13,11 +14,17 @@ snd-seq-midi-event-objs := seq_midi_event.o snd-seq-dummy-objs := seq_dummy.o snd-seq-virmidi-objs := seq_virmidi.o -obj-$(CONFIG_SND_SEQUENCER) += snd-seq.o -obj-$(CONFIG_SND_SEQUENCER_OSS) += oss/ - +obj-$(CONFIG_SND_SEQUENCER) += snd-seq.o snd-seq-device.o +ifeq ($(CONFIG_SND_SEQUENCER_OSS),y) + obj-$(CONFIG_SND_SEQUENCER) += snd-seq-midi-event.o + obj-$(CONFIG_SND_SEQUENCER) += oss/ +endif obj-$(CONFIG_SND_SEQ_DUMMY) += snd-seq-dummy.o -obj-$(CONFIG_SND_SEQ_MIDI) += snd-seq-midi.o -obj-$(CONFIG_SND_SEQ_MIDI_EMUL) += snd-seq-midi-emul.o -obj-$(CONFIG_SND_SEQ_MIDI_EVENT) += snd-seq-midi-event.o -obj-$(CONFIG_SND_SEQ_VIRMIDI) += snd-seq-virmidi.o + +# Toplevel Module Dependency +obj-$(CONFIG_SND_VIRMIDI) += snd-seq-virmidi.o snd-seq-midi-event.o +obj-$(CONFIG_SND_RAWMIDI_SEQ) += snd-seq-midi.o snd-seq-midi-event.o +obj-$(CONFIG_SND_OPL3_LIB_SEQ) += snd-seq-midi-event.o snd-seq-midi-emul.o +obj-$(CONFIG_SND_OPL4_LIB_SEQ) += snd-seq-midi-event.o snd-seq-midi-emul.o +obj-$(CONFIG_SND_SBAWE_SEQ) += snd-seq-midi-emul.o snd-seq-virmidi.o +obj-$(CONFIG_SND_EMU10K1_SEQ) += snd-seq-midi-emul.o snd-seq-virmidi.o diff --git a/sound/core/seq/oss/Makefile b/sound/core/seq/oss/Makefile index 4ea4e3eea6b7..b38406b8463c 100644 --- a/sound/core/seq/oss/Makefile +++ b/sound/core/seq/oss/Makefile @@ -7,4 +7,4 @@ snd-seq-oss-objs := seq_oss.o seq_oss_init.o seq_oss_timer.o seq_oss_ioctl.o \ seq_oss_event.o seq_oss_rw.o seq_oss_synth.o \ seq_oss_midi.o seq_oss_readq.o seq_oss_writeq.o -obj-$(CONFIG_SND_SEQUENCER_OSS) += snd-seq-oss.o +obj-$(CONFIG_SND_SEQUENCER) += snd-seq-oss.o diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c index 0c87502d0867..8cdf489df80e 100644 --- a/sound/core/seq/oss/seq_oss.c +++ b/sound/core/seq/oss/seq_oss.c @@ -203,7 +203,7 @@ odev_poll(struct file *file, poll_table * wait) struct seq_oss_devinfo *dp; dp = file->private_data; if (snd_BUG_ON(!dp)) - return POLLERR; + return -ENXIO; return snd_seq_oss_poll(dp, file, wait); } diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c index 0d5f8b16d057..9debd1b8fd28 100644 --- a/sound/core/seq/oss/seq_oss_midi.c +++ b/sound/core/seq/oss/seq_oss_midi.c @@ -637,7 +637,7 @@ snd_seq_oss_midi_putc(struct seq_oss_devinfo *dp, int dev, unsigned char c, stru if ((mdev = get_mididev(dp, dev)) == NULL) return -ENODEV; - if (snd_midi_event_encode_byte(mdev->coder, c, ev)) { + if (snd_midi_event_encode_byte(mdev->coder, c, ev) > 0) { snd_seq_oss_fill_addr(dp, ev, mdev->client, mdev->port); snd_use_lock_free(&mdev->use_lock); return 0; diff --git a/sound/core/seq/oss/seq_oss_timer.c b/sound/core/seq/oss/seq_oss_timer.c index 0778d28421da..4f24ea9fad93 100644 --- a/sound/core/seq/oss/seq_oss_timer.c +++ b/sound/core/seq/oss/seq_oss_timer.c @@ -92,7 +92,7 @@ snd_seq_oss_process_timer_event(struct seq_oss_timer *rec, union evrec *ev) case TMR_WAIT_REL: parm += rec->cur_tick; rec->realtime = 0; - /* fall through */ + /* continue to next */ case TMR_WAIT_ABS: if (parm == 0) { rec->realtime = 1; diff --git a/sound/core/seq/seq.c b/sound/core/seq/seq.c index 7de98d71f2aa..639544b4fb04 100644 --- a/sound/core/seq/seq.c +++ b/sound/core/seq/seq.c @@ -84,32 +84,30 @@ static int __init alsa_seq_init(void) { int err; - err = client_init_data(); - if (err < 0) + if ((err = client_init_data()) < 0) + goto error; + + /* init memory, room for selected events */ + if ((err = snd_sequencer_memory_init()) < 0) + goto error; + + /* init event queues */ + if ((err = snd_seq_queues_init()) < 0) goto error; /* register sequencer device */ - err = snd_sequencer_device_init(); - if (err < 0) + if ((err = snd_sequencer_device_init()) < 0) goto error; /* register proc interface */ - err = snd_seq_info_init(); - if (err < 0) - goto error_device; + if ((err = snd_seq_info_init()) < 0) + goto error; /* register our internal client */ - err = snd_seq_system_client_init(); - if (err < 0) - goto error_info; + if ((err = snd_seq_system_client_init()) < 0) + goto error; snd_seq_autoload_init(); - return 0; - - error_info: - snd_seq_info_done(); - error_device: - snd_sequencer_device_done(); error: return err; } @@ -128,6 +126,9 @@ static void __exit alsa_seq_exit(void) /* unregister sequencer device */ snd_sequencer_device_done(); + /* release event memory */ + snd_sequencer_memory_done(); + snd_seq_autoload_exit(); } diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 1cfb1a6a5d2a..f8070a3b1d8a 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -311,9 +311,10 @@ static int snd_seq_open(struct inode *inode, struct file *file) if (err < 0) return err; - mutex_lock(®ister_mutex); + if (mutex_lock_interruptible(®ister_mutex)) + return -ERESTARTSYS; client = seq_create_client1(-1, SNDRV_SEQ_DEFAULT_EVENTS); - if (!client) { + if (client == NULL) { mutex_unlock(®ister_mutex); return -ENOMEM; /* failure code */ } @@ -802,10 +803,6 @@ static int snd_seq_deliver_event(struct snd_seq_client *client, struct snd_seq_e return -EMLINK; } - if (snd_seq_ev_is_variable(event) && - snd_BUG_ON(atomic && (event->data.ext.len & SNDRV_SEQ_EXT_USRPTR))) - return -EINVAL; - if (event->queue == SNDRV_SEQ_ADDRESS_SUBSCRIBERS || event->dest.client == SNDRV_SEQ_ADDRESS_SUBSCRIBERS) result = deliver_to_subscribers(client, event, atomic, hop); @@ -1100,7 +1097,7 @@ static unsigned int snd_seq_poll(struct file *file, poll_table * wait) /* check client structures are in place */ if (snd_BUG_ON(!client)) - return POLLERR; + return -ENXIO; if ((snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_INPUT) && client->data.user.fifo) { @@ -1678,6 +1675,7 @@ int snd_seq_set_queue_tempo(int client, struct snd_seq_queue_tempo *tempo) return -EPERM; return snd_seq_queue_timer_set_tempo(tempo->queue, client, tempo); } + EXPORT_SYMBOL(snd_seq_set_queue_tempo); static int snd_seq_ioctl_set_queue_tempo(struct snd_seq_client *client, @@ -1703,7 +1701,10 @@ static int snd_seq_ioctl_get_queue_timer(struct snd_seq_client *client, if (queue == NULL) return -EINVAL; - mutex_lock(&queue->timer_mutex); + if (mutex_lock_interruptible(&queue->timer_mutex)) { + queuefree(queue); + return -ERESTARTSYS; + } tmr = queue->timer; memset(timer, 0, sizeof(*timer)); timer->queue = queue->queue; @@ -1737,7 +1738,10 @@ static int snd_seq_ioctl_set_queue_timer(struct snd_seq_client *client, q = queueptr(timer->queue); if (q == NULL) return -ENXIO; - mutex_lock(&q->timer_mutex); + if (mutex_lock_interruptible(&q->timer_mutex)) { + queuefree(q); + return -ERESTARTSYS; + } tmr = q->timer; snd_seq_queue_timer_close(timer->queue); tmr->type = timer->type; @@ -2173,7 +2177,8 @@ int snd_seq_create_kernel_client(struct snd_card *card, int client_index, if (card == NULL && client_index >= SNDRV_SEQ_GLOBAL_CLIENTS) return -EINVAL; - mutex_lock(®ister_mutex); + if (mutex_lock_interruptible(®ister_mutex)) + return -ERESTARTSYS; if (card) { client_index += SNDRV_SEQ_GLOBAL_CLIENTS @@ -2207,6 +2212,7 @@ int snd_seq_create_kernel_client(struct snd_card *card, int client_index, /* return client number to caller */ return client->number; } + EXPORT_SYMBOL(snd_seq_create_kernel_client); /* exported to kernel modules */ @@ -2225,6 +2231,7 @@ int snd_seq_delete_kernel_client(int client) kfree(ptr); return 0; } + EXPORT_SYMBOL(snd_seq_delete_kernel_client); /* skeleton to enqueue event, called from snd_seq_kernel_client_enqueue @@ -2275,6 +2282,7 @@ int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event * ev, { return kernel_client_enqueue(client, ev, NULL, 0, atomic, hop); } + EXPORT_SYMBOL(snd_seq_kernel_client_enqueue); /* @@ -2288,6 +2296,7 @@ int snd_seq_kernel_client_enqueue_blocking(int client, struct snd_seq_event * ev { return kernel_client_enqueue(client, ev, file, 1, atomic, hop); } + EXPORT_SYMBOL(snd_seq_kernel_client_enqueue_blocking); /* @@ -2325,6 +2334,7 @@ int snd_seq_kernel_client_dispatch(int client, struct snd_seq_event * ev, snd_seq_client_unlock(cptr); return result; } + EXPORT_SYMBOL(snd_seq_kernel_client_dispatch); /** @@ -2357,6 +2367,7 @@ int snd_seq_kernel_client_ctl(int clientid, unsigned int cmd, void *arg) cmd, _IOC_TYPE(cmd), _IOC_NR(cmd)); return -ENOTTY; } + EXPORT_SYMBOL(snd_seq_kernel_client_ctl); /* exported (for OSS emulator) */ @@ -2374,6 +2385,7 @@ int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table return 1; return 0; } + EXPORT_SYMBOL(snd_seq_kernel_client_write_poll); /*---------------------------------------------------------------------------*/ @@ -2514,15 +2526,19 @@ int __init snd_sequencer_device_init(void) snd_device_initialize(&seq_dev, NULL); dev_set_name(&seq_dev, "seq"); - mutex_lock(®ister_mutex); + if (mutex_lock_interruptible(®ister_mutex)) + return -ERESTARTSYS; + err = snd_register_device(SNDRV_DEVICE_TYPE_SEQUENCER, NULL, 0, &snd_seq_f_ops, NULL, &seq_dev); - mutex_unlock(®ister_mutex); if (err < 0) { + mutex_unlock(®ister_mutex); put_device(&seq_dev); return err; } + mutex_unlock(®ister_mutex); + return 0; } @@ -2531,7 +2547,7 @@ int __init snd_sequencer_device_init(void) /* * unregister sequencer device */ -void snd_sequencer_device_done(void) +void __exit snd_sequencer_device_done(void) { snd_unregister_device(&seq_dev); put_device(&seq_dev); diff --git a/sound/core/seq_device.c b/sound/core/seq/seq_device.c index e40a2cba5002..e40a2cba5002 100644 --- a/sound/core/seq_device.c +++ b/sound/core/seq/seq_device.c diff --git a/sound/core/seq/seq_info.c b/sound/core/seq/seq_info.c index b27fedd435b6..97015447b9b3 100644 --- a/sound/core/seq/seq_info.c +++ b/sound/core/seq/seq_info.c @@ -50,7 +50,7 @@ create_info_entry(char *name, void (*read)(struct snd_info_entry *, return entry; } -void snd_seq_info_done(void) +static void free_info_entries(void) { snd_info_free_entry(queues_entry); snd_info_free_entry(clients_entry); @@ -70,6 +70,12 @@ int __init snd_seq_info_init(void) return 0; error: - snd_seq_info_done(); + free_info_entries(); return -ENOMEM; } + +int __exit snd_seq_info_done(void) +{ + free_info_entries(); + return 0; +} diff --git a/sound/core/seq/seq_info.h b/sound/core/seq/seq_info.h index 2cdf8f6e63f5..f8549f81a645 100644 --- a/sound/core/seq/seq_info.h +++ b/sound/core/seq/seq_info.h @@ -30,11 +30,11 @@ void snd_seq_info_queues_read(struct snd_info_entry *entry, struct snd_info_buff #ifdef CONFIG_SND_PROC_FS -int snd_seq_info_init(void); -void snd_seq_info_done(void); +int snd_seq_info_init( void ); +int snd_seq_info_done( void ); #else static inline int snd_seq_info_init(void) { return 0; } -static inline void snd_seq_info_done(void) {} +static inline int snd_seq_info_done(void) { return 0; } #endif #endif diff --git a/sound/core/seq/seq_lock.c b/sound/core/seq/seq_lock.c index cda64b489e42..ba5752ee9af3 100644 --- a/sound/core/seq/seq_lock.c +++ b/sound/core/seq/seq_lock.c @@ -38,4 +38,5 @@ void snd_use_lock_sync_helper(snd_use_lock_t *lockp, const char *file, int line) schedule_timeout_uninterruptible(1); } } + EXPORT_SYMBOL(snd_use_lock_sync_helper); diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c index a45133f9f460..5e07f1428deb 100644 --- a/sound/core/seq/seq_memory.c +++ b/sound/core/seq/seq_memory.c @@ -118,6 +118,7 @@ int snd_seq_dump_var_event(const struct snd_seq_event *event, } return 0; } + EXPORT_SYMBOL(snd_seq_dump_var_event); @@ -168,6 +169,7 @@ int snd_seq_expand_var_event(const struct snd_seq_event *event, int count, char &buf); return err < 0 ? err : newlen; } + EXPORT_SYMBOL(snd_seq_expand_var_event); /* @@ -503,6 +505,18 @@ int snd_seq_pool_delete(struct snd_seq_pool **ppool) return 0; } +/* initialize sequencer memory */ +int __init snd_sequencer_memory_init(void) +{ + return 0; +} + +/* release sequencer memory */ +void __exit snd_sequencer_memory_done(void) +{ +} + + /* exported to seq_clientmgr.c */ void snd_seq_info_pool(struct snd_info_buffer *buffer, struct snd_seq_pool *pool, char *space) diff --git a/sound/core/seq/seq_memory.h b/sound/core/seq/seq_memory.h index 1292fe91f02e..3abe306c394a 100644 --- a/sound/core/seq/seq_memory.h +++ b/sound/core/seq/seq_memory.h @@ -94,6 +94,12 @@ struct snd_seq_pool *snd_seq_pool_new(int poolsize); /* remove pool */ int snd_seq_pool_delete(struct snd_seq_pool **pool); +/* init memory */ +int snd_sequencer_memory_init(void); + +/* release event memory */ +void snd_sequencer_memory_done(void); + /* polling */ int snd_seq_pool_poll_wait(struct snd_seq_pool *pool, struct file *file, poll_table *wait); diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c index 9e0dabd3ce5f..5dd0ee258359 100644 --- a/sound/core/seq/seq_midi.c +++ b/sound/core/seq/seq_midi.c @@ -78,7 +78,7 @@ static void snd_midi_input_event(struct snd_rawmidi_substream *substream) struct seq_midisynth *msynth; struct snd_seq_event ev; char buf[16], *pbuf; - long res; + long res, count; if (substream == NULL) return; @@ -94,15 +94,19 @@ static void snd_midi_input_event(struct snd_rawmidi_substream *substream) if (msynth->parser == NULL) continue; pbuf = buf; - while (res-- > 0) { - if (!snd_midi_event_encode_byte(msynth->parser, - *pbuf++, &ev)) - continue; - ev.source.port = msynth->seq_port; - ev.dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS; - snd_seq_kernel_client_dispatch(msynth->seq_client, &ev, 1, 0); - /* clear event and reset header */ - memset(&ev, 0, sizeof(ev)); + while (res > 0) { + count = snd_midi_event_encode(msynth->parser, pbuf, res, &ev); + if (count < 0) + break; + pbuf += count; + res -= count; + if (ev.type != SNDRV_SEQ_EVENT_NONE) { + ev.source.port = msynth->seq_port; + ev.dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS; + snd_seq_kernel_client_dispatch(msynth->seq_client, &ev, 1, 0); + /* clear event and reset header */ + memset(&ev, 0, sizeof(ev)); + } } } } diff --git a/sound/core/seq/seq_midi_emul.c b/sound/core/seq/seq_midi_emul.c index ce780658bbcc..7ba937399ac7 100644 --- a/sound/core/seq/seq_midi_emul.c +++ b/sound/core/seq/seq_midi_emul.c @@ -236,7 +236,6 @@ snd_midi_process_event(struct snd_midi_op *ops, break; } } -EXPORT_SYMBOL(snd_midi_process_event); /* @@ -318,7 +317,7 @@ do_control(struct snd_midi_op *ops, void *drv, struct snd_midi_channel_set *chse break; case MIDI_CTL_MSB_DATA_ENTRY: chan->control[MIDI_CTL_LSB_DATA_ENTRY] = 0; - /* fall through */ + /* go through here */ case MIDI_CTL_LSB_DATA_ENTRY: if (chan->param_type == SNDRV_MIDI_PARAM_TYPE_REGISTERED) rpn(ops, drv, chan, chset); @@ -410,7 +409,6 @@ snd_midi_channel_set_clear(struct snd_midi_channel_set *chset) chan->drum_channel = 0; } } -EXPORT_SYMBOL(snd_midi_channel_set_clear); /* * Process a rpn message. @@ -703,7 +701,6 @@ struct snd_midi_channel_set *snd_midi_channel_alloc_set(int n) } return chset; } -EXPORT_SYMBOL(snd_midi_channel_alloc_set); /* * Reset the midi controllers on a particular channel to default values. @@ -727,4 +724,20 @@ void snd_midi_channel_free_set(struct snd_midi_channel_set *chset) kfree(chset->channels); kfree(chset); } + +static int __init alsa_seq_midi_emul_init(void) +{ + return 0; +} + +static void __exit alsa_seq_midi_emul_exit(void) +{ +} + +module_init(alsa_seq_midi_emul_init) +module_exit(alsa_seq_midi_emul_exit) + +EXPORT_SYMBOL(snd_midi_process_event); +EXPORT_SYMBOL(snd_midi_channel_set_clear); +EXPORT_SYMBOL(snd_midi_channel_alloc_set); EXPORT_SYMBOL(snd_midi_channel_free_set); diff --git a/sound/core/seq/seq_midi_event.c b/sound/core/seq/seq_midi_event.c index b11419537062..37db7ba492a6 100644 --- a/sound/core/seq/seq_midi_event.c +++ b/sound/core/seq/seq_midi_event.c @@ -134,7 +134,6 @@ int snd_midi_event_new(int bufsize, struct snd_midi_event **rdev) *rdev = dev; return 0; } -EXPORT_SYMBOL(snd_midi_event_new); void snd_midi_event_free(struct snd_midi_event *dev) { @@ -143,7 +142,6 @@ void snd_midi_event_free(struct snd_midi_event *dev) kfree(dev); } } -EXPORT_SYMBOL(snd_midi_event_free); /* * initialize record @@ -163,7 +161,6 @@ void snd_midi_event_reset_encode(struct snd_midi_event *dev) reset_encode(dev); spin_unlock_irqrestore(&dev->lock, flags); } -EXPORT_SYMBOL(snd_midi_event_reset_encode); void snd_midi_event_reset_decode(struct snd_midi_event *dev) { @@ -173,25 +170,83 @@ void snd_midi_event_reset_decode(struct snd_midi_event *dev) dev->lastcmd = 0xff; spin_unlock_irqrestore(&dev->lock, flags); } -EXPORT_SYMBOL(snd_midi_event_reset_decode); + +#if 0 +void snd_midi_event_init(struct snd_midi_event *dev) +{ + snd_midi_event_reset_encode(dev); + snd_midi_event_reset_decode(dev); +} +#endif /* 0 */ void snd_midi_event_no_status(struct snd_midi_event *dev, int on) { dev->nostat = on ? 1 : 0; } -EXPORT_SYMBOL(snd_midi_event_no_status); + +/* + * resize buffer + */ +#if 0 +int snd_midi_event_resize_buffer(struct snd_midi_event *dev, int bufsize) +{ + unsigned char *new_buf, *old_buf; + unsigned long flags; + + if (bufsize == dev->bufsize) + return 0; + new_buf = kmalloc(bufsize, GFP_KERNEL); + if (new_buf == NULL) + return -ENOMEM; + spin_lock_irqsave(&dev->lock, flags); + old_buf = dev->buf; + dev->buf = new_buf; + dev->bufsize = bufsize; + reset_encode(dev); + spin_unlock_irqrestore(&dev->lock, flags); + kfree(old_buf); + return 0; +} +#endif /* 0 */ + +/* + * read bytes and encode to sequencer event if finished + * return the size of encoded bytes + */ +long snd_midi_event_encode(struct snd_midi_event *dev, unsigned char *buf, long count, + struct snd_seq_event *ev) +{ + long result = 0; + int rc; + + ev->type = SNDRV_SEQ_EVENT_NONE; + + while (count-- > 0) { + rc = snd_midi_event_encode_byte(dev, *buf++, ev); + result++; + if (rc < 0) + return rc; + else if (rc > 0) + return result; + } + + return result; +} /* * read one byte and encode to sequencer event: - * return true if MIDI bytes are encoded to an event - * false data is not finished + * return 1 if MIDI bytes are encoded to an event + * 0 data is not finished + * negative for error */ -bool snd_midi_event_encode_byte(struct snd_midi_event *dev, unsigned char c, - struct snd_seq_event *ev) +int snd_midi_event_encode_byte(struct snd_midi_event *dev, int c, + struct snd_seq_event *ev) { - bool rc = false; + int rc = 0; unsigned long flags; + c &= 0xff; + if (c >= MIDI_CMD_COMMON_CLOCK) { /* real-time event */ ev->type = status_event[ST_SPECIAL + c - 0xf0].event; @@ -232,7 +287,7 @@ bool snd_midi_event_encode_byte(struct snd_midi_event *dev, unsigned char c, status_event[dev->type].encode(dev, ev); if (dev->type >= ST_SPECIAL) dev->type = ST_INVALID; - rc = true; + rc = 1; } else if (dev->type == ST_SYSEX) { if (c == MIDI_CMD_COMMON_SYSEX_END || dev->read >= dev->bufsize) { @@ -245,14 +300,13 @@ bool snd_midi_event_encode_byte(struct snd_midi_event *dev, unsigned char c, dev->read = 0; /* continue to parse */ else reset_encode(dev); /* all parsed */ - rc = true; + rc = 1; } } spin_unlock_irqrestore(&dev->lock, flags); return rc; } -EXPORT_SYMBOL(snd_midi_event_encode_byte); /* encode note event */ static void note_event(struct snd_midi_event *dev, struct snd_seq_event *ev) @@ -354,7 +408,6 @@ long snd_midi_event_decode(struct snd_midi_event *dev, unsigned char *buf, long return qlen; } } -EXPORT_SYMBOL(snd_midi_event_decode); /* decode note event */ @@ -470,3 +523,28 @@ static int extra_decode_xrpn(struct snd_midi_event *dev, unsigned char *buf, } return idx; } + +/* + * exports + */ + +EXPORT_SYMBOL(snd_midi_event_new); +EXPORT_SYMBOL(snd_midi_event_free); +EXPORT_SYMBOL(snd_midi_event_reset_encode); +EXPORT_SYMBOL(snd_midi_event_reset_decode); +EXPORT_SYMBOL(snd_midi_event_no_status); +EXPORT_SYMBOL(snd_midi_event_encode); +EXPORT_SYMBOL(snd_midi_event_encode_byte); +EXPORT_SYMBOL(snd_midi_event_decode); + +static int __init alsa_seq_midi_event_init(void) +{ + return 0; +} + +static void __exit alsa_seq_midi_event_exit(void) +{ +} + +module_init(alsa_seq_midi_event_init) +module_exit(alsa_seq_midi_event_exit) diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c index 24d90abfc64d..f04714d70bf7 100644 --- a/sound/core/seq/seq_ports.c +++ b/sound/core/seq/seq_ports.c @@ -669,7 +669,7 @@ int snd_seq_event_port_attach(int client, /* Set up the port */ memset(&portinfo, 0, sizeof(portinfo)); portinfo.addr.client = client; - strlcpy(portinfo.name, portname ? portname : "Unnamed port", + strlcpy(portinfo.name, portname ? portname : "Unamed port", sizeof(portinfo.name)); portinfo.capability = cap; @@ -688,6 +688,7 @@ int snd_seq_event_port_attach(int client, return ret; } + EXPORT_SYMBOL(snd_seq_event_port_attach); /* @@ -708,4 +709,5 @@ int snd_seq_event_port_detach(int client, int port) return err; } + EXPORT_SYMBOL(snd_seq_event_port_detach); diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c index 3b3ac96f1f5f..1a6dc4ff44a6 100644 --- a/sound/core/seq/seq_queue.c +++ b/sound/core/seq/seq_queue.c @@ -159,8 +159,18 @@ static void queue_delete(struct snd_seq_queue *q) /*----------------------------------------------------------------*/ +/* setup queues */ +int __init snd_seq_queues_init(void) +{ + /* + memset(queue_list, 0, sizeof(queue_list)); + num_queues = 0; + */ + return 0; +} + /* delete all existing queues */ -void snd_seq_queues_delete(void) +void __exit snd_seq_queues_delete(void) { int i; @@ -477,7 +487,9 @@ int snd_seq_queue_timer_set_tempo(int queueid, int client, return -EPERM; } - result = snd_seq_timer_set_tempo_ppq(q->timer, info->tempo, info->ppq); + result = snd_seq_timer_set_tempo(q->timer, info->tempo); + if (result >= 0) + result = snd_seq_timer_set_ppq(q->timer, info->ppq); if (result >= 0 && info->skew_base > 0) result = snd_seq_timer_set_skew(q->timer, info->skew_value, info->skew_base); diff --git a/sound/core/seq/seq_queue.h b/sound/core/seq/seq_queue.h index e006fc8e3a36..719093489a2c 100644 --- a/sound/core/seq/seq_queue.h +++ b/sound/core/seq/seq_queue.h @@ -63,6 +63,9 @@ struct snd_seq_queue { /* get the number of current queues */ int snd_seq_queue_get_cur_queues(void); +/* init queues structure */ +int snd_seq_queues_init(void); + /* delete queues */ void snd_seq_queues_delete(void); @@ -109,4 +112,28 @@ int snd_seq_queue_is_used(int queueid, int client); int snd_seq_control_queue(struct snd_seq_event *ev, int atomic, int hop); +/* + * 64bit division - for sync stuff.. + */ +#if defined(i386) || defined(i486) + +#define udiv_qrnnd(q, r, n1, n0, d) \ + __asm__ ("divl %4" \ + : "=a" ((u32)(q)), \ + "=d" ((u32)(r)) \ + : "0" ((u32)(n0)), \ + "1" ((u32)(n1)), \ + "rm" ((u32)(d))) + +#define u64_div(x,y,q) do {u32 __tmp; udiv_qrnnd(q, __tmp, (x)>>32, x, y);} while (0) +#define u64_mod(x,y,r) do {u32 __tmp; udiv_qrnnd(__tmp, q, (x)>>32, x, y);} while (0) +#define u64_divmod(x,y,q,r) udiv_qrnnd(q, r, (x)>>32, x, y) + +#else +#define u64_div(x,y,q) ((q) = (u32)((u64)(x) / (u64)(y))) +#define u64_mod(x,y,r) ((r) = (u32)((u64)(x) % (u64)(y))) +#define u64_divmod(x,y,q,r) (u64_div(x,y,q), u64_mod(x,y,r)) +#endif + + #endif diff --git a/sound/core/seq/seq_system.c b/sound/core/seq/seq_system.c index 0dc5d5a45ecc..8ce1d0b40dce 100644 --- a/sound/core/seq/seq_system.c +++ b/sound/core/seq/seq_system.c @@ -123,7 +123,6 @@ int __init snd_seq_system_client_init(void) { struct snd_seq_port_callback pcallbacks; struct snd_seq_port_info *port; - int err; port = kzalloc(sizeof(*port), GFP_KERNEL); if (!port) @@ -135,10 +134,6 @@ int __init snd_seq_system_client_init(void) /* register client */ sysclient = snd_seq_create_kernel_client(NULL, 0, "System"); - if (sysclient < 0) { - kfree(port); - return sysclient; - } /* register timer */ strcpy(port->name, "Timer"); @@ -149,10 +144,7 @@ int __init snd_seq_system_client_init(void) port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT; port->addr.client = sysclient; port->addr.port = SNDRV_SEQ_PORT_SYSTEM_TIMER; - err = snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT, - port); - if (err < 0) - goto error_port; + snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT, port); /* register announcement port */ strcpy(port->name, "Announce"); @@ -162,24 +154,16 @@ int __init snd_seq_system_client_init(void) port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT; port->addr.client = sysclient; port->addr.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE; - err = snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT, - port); - if (err < 0) - goto error_port; + snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT, port); announce_port = port->addr.port; kfree(port); return 0; - - error_port: - snd_seq_system_client_done(); - kfree(port); - return err; } /* unregister our internal client */ -void snd_seq_system_client_done(void) +void __exit snd_seq_system_client_done(void) { int oldsysclient = sysclient; diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c index f587d0e27476..b80985fbc334 100644 --- a/sound/core/seq/seq_timer.c +++ b/sound/core/seq/seq_timer.c @@ -191,15 +191,14 @@ int snd_seq_timer_set_tempo(struct snd_seq_timer * tmr, int tempo) return 0; } -/* set current tempo and ppq in a shot */ -int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq) +/* set current ppq */ +int snd_seq_timer_set_ppq(struct snd_seq_timer * tmr, int ppq) { - int changed; unsigned long flags; if (snd_BUG_ON(!tmr)) return -EINVAL; - if (tempo <= 0 || ppq <= 0) + if (ppq <= 0) return -EINVAL; spin_lock_irqsave(&tmr->lock, flags); if (tmr->running && (ppq != tmr->ppq)) { @@ -209,11 +208,9 @@ int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq) pr_debug("ALSA: seq: cannot change ppq of a running timer\n"); return -EBUSY; } - changed = (tempo != tmr->tempo) || (ppq != tmr->ppq); - tmr->tempo = tempo; + tmr->ppq = ppq; - if (changed) - snd_seq_timer_set_tick_resolution(tmr); + snd_seq_timer_set_tick_resolution(tmr); spin_unlock_irqrestore(&tmr->lock, flags); return 0; } @@ -371,7 +368,9 @@ static int initialize_timer(struct snd_seq_timer *tmr) tmr->ticks = 1; if (!(t->hw.flags & SNDRV_TIMER_HW_SLAVE)) { - unsigned long r = snd_timer_resolution(tmr->timeri); + unsigned long r = t->hw.resolution; + if (! r && t->hw.c_resolution) + r = t->hw.c_resolution(t); if (r) { tmr->ticks = (unsigned int)(1000000000uL / (r * freq)); if (! tmr->ticks) diff --git a/sound/core/seq/seq_timer.h b/sound/core/seq/seq_timer.h index 62f390671096..9506b661fe5b 100644 --- a/sound/core/seq/seq_timer.h +++ b/sound/core/seq/seq_timer.h @@ -131,7 +131,7 @@ int snd_seq_timer_stop(struct snd_seq_timer *tmr); int snd_seq_timer_start(struct snd_seq_timer *tmr); int snd_seq_timer_continue(struct snd_seq_timer *tmr); int snd_seq_timer_set_tempo(struct snd_seq_timer *tmr, int tempo); -int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq); +int snd_seq_timer_set_ppq(struct snd_seq_timer *tmr, int ppq); int snd_seq_timer_set_position_tick(struct snd_seq_timer *tmr, snd_seq_tick_time_t position); int snd_seq_timer_set_position_time(struct snd_seq_timer *tmr, snd_seq_real_time_t position); int snd_seq_timer_set_skew(struct snd_seq_timer *tmr, unsigned int skew, unsigned int base); diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index e5a40795914a..c45375ff9d5c 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -89,7 +89,7 @@ static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev, else down_read(&rdev->filelist_sem); list_for_each_entry(vmidi, &rdev->filelist, list) { - if (!READ_ONCE(vmidi->trigger)) + if (!vmidi->trigger) continue; if (ev->type == SNDRV_SEQ_EVENT_SYSEX) { if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE) @@ -110,6 +110,23 @@ static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev, } /* + * receive an event from the remote virmidi port + * + * for rawmidi inputs, you can call this function from the event + * handler of a remote port which is attached to the virmidi via + * SNDRV_VIRMIDI_SEQ_ATTACH. + */ +#if 0 +int snd_virmidi_receive(struct snd_rawmidi *rmidi, struct snd_seq_event *ev) +{ + struct snd_virmidi_dev *rdev; + + rdev = rmidi->private_data; + return snd_virmidi_dev_receive_event(rdev, ev, true); +} +#endif /* 0 */ + +/* * event handler of virmidi port */ static int snd_virmidi_event_input(struct snd_seq_event *ev, int direct, @@ -130,45 +147,10 @@ static void snd_virmidi_input_trigger(struct snd_rawmidi_substream *substream, i { struct snd_virmidi *vmidi = substream->runtime->private_data; - WRITE_ONCE(vmidi->trigger, !!up); -} - -/* process rawmidi bytes and send events; - * we need no lock here for vmidi->event since it's handled only in this work - */ -static void snd_vmidi_output_work(struct work_struct *work) -{ - struct snd_virmidi *vmidi; - struct snd_rawmidi_substream *substream; - unsigned char input; - int ret; - - vmidi = container_of(work, struct snd_virmidi, output_work); - substream = vmidi->substream; - - /* discard the outputs in dispatch mode unless subscribed */ - if (vmidi->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH && - !(vmidi->rdev->flags & SNDRV_VIRMIDI_SUBSCRIBE)) { - snd_rawmidi_proceed(substream); - return; - } - - while (READ_ONCE(vmidi->trigger)) { - if (snd_rawmidi_transmit(substream, &input, 1) != 1) - break; - if (!snd_midi_event_encode_byte(vmidi->parser, input, - &vmidi->event)) - continue; - if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) { - ret = snd_seq_kernel_client_dispatch(vmidi->client, - &vmidi->event, - false, 0); - vmidi->event.type = SNDRV_SEQ_EVENT_NONE; - if (ret < 0) - break; - } - /* rawmidi input might be huge, allow to have a break */ - cond_resched(); + if (up) { + vmidi->trigger = 1; + } else { + vmidi->trigger = 0; } } @@ -178,10 +160,62 @@ static void snd_vmidi_output_work(struct work_struct *work) static void snd_virmidi_output_trigger(struct snd_rawmidi_substream *substream, int up) { struct snd_virmidi *vmidi = substream->runtime->private_data; - - WRITE_ONCE(vmidi->trigger, !!up); - if (up) - queue_work(system_highpri_wq, &vmidi->output_work); + int count, res; + unsigned char buf[32], *pbuf; + unsigned long flags; + bool check_resched = !in_atomic(); + + if (up) { + vmidi->trigger = 1; + if (vmidi->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH && + !(vmidi->rdev->flags & SNDRV_VIRMIDI_SUBSCRIBE)) { + while (snd_rawmidi_transmit(substream, buf, + sizeof(buf)) > 0) { + /* ignored */ + } + return; + } + spin_lock_irqsave(&substream->runtime->lock, flags); + if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) { + if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, in_atomic(), 0) < 0) + goto out; + vmidi->event.type = SNDRV_SEQ_EVENT_NONE; + } + while (1) { + count = __snd_rawmidi_transmit_peek(substream, buf, sizeof(buf)); + if (count <= 0) + break; + pbuf = buf; + while (count > 0) { + res = snd_midi_event_encode(vmidi->parser, pbuf, count, &vmidi->event); + if (res < 0) { + snd_midi_event_reset_encode(vmidi->parser); + continue; + } + __snd_rawmidi_transmit_ack(substream, res); + pbuf += res; + count -= res; + if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) { + if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, in_atomic(), 0) < 0) + goto out; + vmidi->event.type = SNDRV_SEQ_EVENT_NONE; + } + } + if (!check_resched) + continue; + /* do temporary unlock & cond_resched() for avoiding + * CPU soft lockup, which may happen via a write from + * a huge rawmidi buffer + */ + spin_unlock_irqrestore(&substream->runtime->lock, flags); + cond_resched(); + spin_lock_irqsave(&substream->runtime->lock, flags); + } + out: + spin_unlock_irqrestore(&substream->runtime->lock, flags); + } else { + vmidi->trigger = 0; + } } /* @@ -236,7 +270,6 @@ static int snd_virmidi_output_open(struct snd_rawmidi_substream *substream) vmidi->port = rdev->port; snd_virmidi_init_event(vmidi, &vmidi->event); vmidi->rdev = rdev; - INIT_WORK(&vmidi->output_work, snd_vmidi_output_work); runtime->private_data = vmidi; return 0; } @@ -266,9 +299,6 @@ static int snd_virmidi_input_close(struct snd_rawmidi_substream *substream) static int snd_virmidi_output_close(struct snd_rawmidi_substream *substream) { struct snd_virmidi *vmidi = substream->runtime->private_data; - - WRITE_ONCE(vmidi->trigger, false); /* to be sure */ - cancel_work_sync(&vmidi->output_work); snd_midi_event_free(vmidi->parser); substream->runtime->private_data = NULL; kfree(vmidi); @@ -525,4 +555,21 @@ int snd_virmidi_new(struct snd_card *card, int device, struct snd_rawmidi **rrmi *rrmidi = rmidi; return 0; } + +/* + * ENTRY functions + */ + +static int __init alsa_virmidi_init(void) +{ + return 0; +} + +static void __exit alsa_virmidi_exit(void) +{ +} + +module_init(alsa_virmidi_init) +module_exit(alsa_virmidi_exit) + EXPORT_SYMBOL(snd_virmidi_new); diff --git a/sound/core/sound.c b/sound/core/sound.c index b30f027eb0fe..175f9e4e01c8 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -74,6 +74,7 @@ void snd_request_card(int card) return; request_module("snd-card-%i", card); } + EXPORT_SYMBOL(snd_request_card); static void snd_request_other(int minor) @@ -123,6 +124,7 @@ void *snd_lookup_minor_data(unsigned int minor, int type) mutex_unlock(&sound_mutex); return private_data; } + EXPORT_SYMBOL(snd_lookup_minor_data); #ifdef CONFIG_MODULES diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c index 0a5c66229a22..0ca9d72b2273 100644 --- a/sound/core/sound_oss.c +++ b/sound/core/sound_oss.c @@ -55,6 +55,7 @@ void *snd_lookup_oss_minor_data(unsigned int minor, int type) mutex_unlock(&sound_oss_mutex); return private_data; } + EXPORT_SYMBOL(snd_lookup_oss_minor_data); static int snd_oss_kernel_minor(int type, struct snd_card *card, int dev) @@ -158,6 +159,7 @@ int snd_register_oss_device(int type, struct snd_card *card, int dev, kfree(preg); return -EBUSY; } + EXPORT_SYMBOL(snd_register_oss_device); int snd_unregister_oss_device(int type, struct snd_card *card, int dev) @@ -198,6 +200,7 @@ int snd_unregister_oss_device(int type, struct snd_card *card, int dev) kfree(mptr); return 0; } + EXPORT_SYMBOL(snd_unregister_oss_device); /* diff --git a/sound/core/timer.c b/sound/core/timer.c index 50aad2bafdcc..a46a4089196d 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -345,7 +345,6 @@ int snd_timer_open(struct snd_timer_instance **ti, *ti = timeri; return err; } -EXPORT_SYMBOL(snd_timer_open); /* * close a timer instance @@ -409,7 +408,6 @@ static int snd_timer_close_locked(struct snd_timer_instance *timeri) return 0; } -EXPORT_SYMBOL(snd_timer_close); /* * close a timer instance @@ -427,35 +425,23 @@ int snd_timer_close(struct snd_timer_instance *timeri) return err; } -static unsigned long snd_timer_hw_resolution(struct snd_timer *timer) -{ - if (timer->hw.c_resolution) - return timer->hw.c_resolution(timer); - else - return timer->hw.resolution; -} - unsigned long snd_timer_resolution(struct snd_timer_instance *timeri) { struct snd_timer * timer; - unsigned long ret = 0; - unsigned long flags; if (timeri == NULL) return 0; - timer = timeri->timer; - if (timer) { - spin_lock_irqsave(&timer->lock, flags); - ret = snd_timer_hw_resolution(timer); - spin_unlock_irqrestore(&timer->lock, flags); + if ((timer = timeri->timer) != NULL) { + if (timer->hw.c_resolution) + return timer->hw.c_resolution(timer); + return timer->hw.resolution; } - return ret; + return 0; } -EXPORT_SYMBOL(snd_timer_resolution); static void snd_timer_notify1(struct snd_timer_instance *ti, int event) { - struct snd_timer *timer = ti->timer; + struct snd_timer *timer; unsigned long resolution = 0; struct snd_timer_instance *ts; struct timespec tstamp; @@ -467,14 +453,14 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event) if (snd_BUG_ON(event < SNDRV_TIMER_EVENT_START || event > SNDRV_TIMER_EVENT_PAUSE)) return; - if (timer && - (event == SNDRV_TIMER_EVENT_START || - event == SNDRV_TIMER_EVENT_CONTINUE)) - resolution = snd_timer_hw_resolution(timer); + if (event == SNDRV_TIMER_EVENT_START || + event == SNDRV_TIMER_EVENT_CONTINUE) + resolution = snd_timer_resolution(ti); if (ti->ccallback) ti->ccallback(ti, event, &tstamp, resolution); if (ti->flags & SNDRV_TIMER_IFLG_SLAVE) return; + timer = ti->timer; if (timer == NULL) return; if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE) @@ -643,7 +629,6 @@ int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks) else return snd_timer_start1(timeri, true, ticks); } -EXPORT_SYMBOL(snd_timer_start); /* * stop the timer instance. @@ -657,7 +642,6 @@ int snd_timer_stop(struct snd_timer_instance *timeri) else return snd_timer_stop1(timeri, true); } -EXPORT_SYMBOL(snd_timer_stop); /* * start again.. the tick is kept. @@ -673,7 +657,6 @@ int snd_timer_continue(struct snd_timer_instance *timeri) else return snd_timer_start1(timeri, false, 0); } -EXPORT_SYMBOL(snd_timer_continue); /* * pause.. remember the ticks left @@ -685,7 +668,6 @@ int snd_timer_pause(struct snd_timer_instance * timeri) else return snd_timer_stop1(timeri, false); } -EXPORT_SYMBOL(snd_timer_pause); /* * reschedule the timer @@ -781,7 +763,10 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) spin_lock_irqsave(&timer->lock, flags); /* remember the current resolution */ - resolution = snd_timer_hw_resolution(timer); + if (timer->hw.c_resolution) + resolution = timer->hw.c_resolution(timer); + else + resolution = timer->hw.resolution; /* loop for all active instances * Here we cannot use list_for_each_entry because the active_list of a @@ -864,7 +849,6 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) if (use_tasklet) tasklet_schedule(&timer->task_queue); } -EXPORT_SYMBOL(snd_timer_interrupt); /* @@ -883,11 +867,6 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid, if (snd_BUG_ON(!tid)) return -EINVAL; - if (tid->dev_class == SNDRV_TIMER_CLASS_CARD || - tid->dev_class == SNDRV_TIMER_CLASS_PCM) { - if (WARN_ON(!card)) - return -EINVAL; - } if (rtimer) *rtimer = NULL; timer = kzalloc(sizeof(*timer), GFP_KERNEL); @@ -921,7 +900,6 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid, *rtimer = timer; return 0; } -EXPORT_SYMBOL(snd_timer_new); static int snd_timer_free(struct snd_timer *timer) { @@ -1026,8 +1004,12 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstam spin_lock_irqsave(&timer->lock, flags); if (event == SNDRV_TIMER_EVENT_MSTART || event == SNDRV_TIMER_EVENT_MCONTINUE || - event == SNDRV_TIMER_EVENT_MRESUME) - resolution = snd_timer_hw_resolution(timer); + event == SNDRV_TIMER_EVENT_MRESUME) { + if (timer->hw.c_resolution) + resolution = timer->hw.c_resolution(timer); + else + resolution = timer->hw.resolution; + } list_for_each_entry(ti, &timer->active_list_head, active_list) { if (ti->ccallback) ti->ccallback(ti, event, tstamp, resolution); @@ -1037,7 +1019,6 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstam } spin_unlock_irqrestore(&timer->lock, flags); } -EXPORT_SYMBOL(snd_timer_notify); /* * exported functions for global timers @@ -1053,13 +1034,11 @@ int snd_timer_global_new(char *id, int device, struct snd_timer **rtimer) tid.subdevice = 0; return snd_timer_new(NULL, id, &tid, rtimer); } -EXPORT_SYMBOL(snd_timer_global_new); int snd_timer_global_free(struct snd_timer *timer) { return snd_timer_free(timer); } -EXPORT_SYMBOL(snd_timer_global_free); int snd_timer_global_register(struct snd_timer *timer) { @@ -1069,7 +1048,6 @@ int snd_timer_global_register(struct snd_timer *timer) dev.device_data = timer; return snd_timer_dev_register(&dev); } -EXPORT_SYMBOL(snd_timer_global_register); /* * System timer @@ -1077,17 +1055,15 @@ EXPORT_SYMBOL(snd_timer_global_register); struct snd_timer_system_private { struct timer_list tlist; - struct snd_timer *snd_timer; unsigned long last_expires; unsigned long last_jiffies; unsigned long correction; }; -static void snd_timer_s_function(struct timer_list *t) +static void snd_timer_s_function(unsigned long data) { - struct snd_timer_system_private *priv = from_timer(priv, t, - tlist); - struct snd_timer *timer = priv->snd_timer; + struct snd_timer *timer = (struct snd_timer *)data; + struct snd_timer_system_private *priv = timer->private_data; unsigned long jiff = jiffies; if (time_after(jiff, priv->last_expires)) priv->correction += (long)jiff - (long)priv->last_expires; @@ -1169,8 +1145,7 @@ static int snd_timer_register_system(void) snd_timer_free(timer); return -ENOMEM; } - priv->snd_timer = timer; - timer_setup(&priv->tlist, snd_timer_s_function, 0); + setup_timer(&priv->tlist, snd_timer_s_function, (unsigned long) timer); timer->private_data = priv; timer->private_free = snd_timer_free_system; return snd_timer_global_register(timer); @@ -1393,33 +1368,6 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri, wake_up(&tu->qchange_sleep); } -static int realloc_user_queue(struct snd_timer_user *tu, int size) -{ - struct snd_timer_read *queue = NULL; - struct snd_timer_tread *tqueue = NULL; - - if (tu->tread) { - tqueue = kcalloc(size, sizeof(*tqueue), GFP_KERNEL); - if (!tqueue) - return -ENOMEM; - } else { - queue = kcalloc(size, sizeof(*queue), GFP_KERNEL); - if (!queue) - return -ENOMEM; - } - - spin_lock_irq(&tu->qlock); - kfree(tu->queue); - kfree(tu->tqueue); - tu->queue_size = size; - tu->queue = queue; - tu->tqueue = tqueue; - tu->qhead = tu->qtail = tu->qused = 0; - spin_unlock_irq(&tu->qlock); - - return 0; -} - static int snd_timer_user_open(struct inode *inode, struct file *file) { struct snd_timer_user *tu; @@ -1436,7 +1384,10 @@ static int snd_timer_user_open(struct inode *inode, struct file *file) init_waitqueue_head(&tu->qchange_sleep); mutex_init(&tu->ioctl_lock); tu->ticks = 1; - if (realloc_user_queue(tu, 128) < 0) { + tu->queue_size = 128; + tu->queue = kmalloc(tu->queue_size * sizeof(struct snd_timer_read), + GFP_KERNEL); + if (tu->queue == NULL) { kfree(tu); return -ENOMEM; } @@ -1664,8 +1615,10 @@ static int snd_timer_user_gstatus(struct file *file, mutex_lock(®ister_mutex); t = snd_timer_find(&tid); if (t != NULL) { - spin_lock_irq(&t->lock); - gstatus.resolution = snd_timer_hw_resolution(t); + if (t->hw.c_resolution) + gstatus.resolution = t->hw.c_resolution(t); + else + gstatus.resolution = t->hw.resolution; if (t->hw.precise_resolution) { t->hw.precise_resolution(t, &gstatus.resolution_num, &gstatus.resolution_den); @@ -1673,7 +1626,6 @@ static int snd_timer_user_gstatus(struct file *file, gstatus.resolution_num = gstatus.resolution; gstatus.resolution_den = 1000000000uL; } - spin_unlock_irq(&t->lock); } else { err = -ENODEV; } @@ -1707,12 +1659,34 @@ static int snd_timer_user_tselect(struct file *file, if (err < 0) goto __err; - tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST; - tu->timeri->callback = tu->tread + tu->qhead = tu->qtail = tu->qused = 0; + kfree(tu->queue); + tu->queue = NULL; + kfree(tu->tqueue); + tu->tqueue = NULL; + if (tu->tread) { + tu->tqueue = kmalloc(tu->queue_size * sizeof(struct snd_timer_tread), + GFP_KERNEL); + if (tu->tqueue == NULL) + err = -ENOMEM; + } else { + tu->queue = kmalloc(tu->queue_size * sizeof(struct snd_timer_read), + GFP_KERNEL); + if (tu->queue == NULL) + err = -ENOMEM; + } + + if (err < 0) { + snd_timer_close(tu->timeri); + tu->timeri = NULL; + } else { + tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST; + tu->timeri->callback = tu->tread ? snd_timer_user_tinterrupt : snd_timer_user_interrupt; - tu->timeri->ccallback = snd_timer_user_ccallback; - tu->timeri->callback_data = (void *)tu; - tu->timeri->disconnect = snd_timer_user_disconnect; + tu->timeri->ccallback = snd_timer_user_ccallback; + tu->timeri->callback_data = (void *)tu; + tu->timeri->disconnect = snd_timer_user_disconnect; + } __err: return err; @@ -1754,6 +1728,8 @@ static int snd_timer_user_params(struct file *file, struct snd_timer_user *tu; struct snd_timer_params params; struct snd_timer *t; + struct snd_timer_read *tr; + struct snd_timer_tread *ttr; int err; tu = file->private_data; @@ -1816,11 +1792,24 @@ static int snd_timer_user_params(struct file *file, spin_unlock_irq(&t->lock); if (params.queue_size > 0 && (unsigned int)tu->queue_size != params.queue_size) { - err = realloc_user_queue(tu, params.queue_size); - if (err < 0) - goto _end; + if (tu->tread) { + ttr = kmalloc(params.queue_size * sizeof(*ttr), + GFP_KERNEL); + if (ttr) { + kfree(tu->tqueue); + tu->queue_size = params.queue_size; + tu->tqueue = ttr; + } + } else { + tr = kmalloc(params.queue_size * sizeof(*tr), + GFP_KERNEL); + if (tr) { + kfree(tu->queue); + tu->queue_size = params.queue_size; + tu->queue = tr; + } + } } - spin_lock_irq(&tu->qlock); tu->qhead = tu->qtail = tu->qused = 0; if (tu->timeri->flags & SNDRV_TIMER_IFLG_EARLY_EVENT) { if (tu->tread) { @@ -1841,7 +1830,6 @@ static int snd_timer_user_params(struct file *file, } tu->filter = params.filter; tu->ticks = params.ticks; - spin_unlock_irq(&tu->qlock); err = 0; _end: if (copy_to_user(_params, ¶ms, sizeof(params))) @@ -1944,19 +1932,13 @@ static long __snd_timer_user_ioctl(struct file *file, unsigned int cmd, return snd_timer_user_next_device(argp); case SNDRV_TIMER_IOCTL_TREAD: { - int xarg, old_tread; + int xarg; if (tu->timeri) /* too late */ return -EBUSY; if (get_user(xarg, p)) return -EFAULT; - old_tread = tu->tread; tu->tread = xarg ? 1 : 0; - if (tu->tread != old_tread && - realloc_user_queue(tu, tu->queue_size) < 0) { - tu->tread = old_tread; - return -ENOMEM; - } return 0; } case SNDRV_TIMER_IOCTL_GINFO: @@ -2089,12 +2071,10 @@ static unsigned int snd_timer_user_poll(struct file *file, poll_table * wait) poll_wait(file, &tu->qchange_sleep, wait); mask = 0; - spin_lock_irq(&tu->qlock); if (tu->qused) mask |= POLLIN | POLLRDNORM; if (tu->disconnected) mask |= POLLERR; - spin_unlock_irq(&tu->qlock); return mask; } @@ -2148,7 +2128,8 @@ static int __init alsa_timer_init(void) err = snd_timer_register_system(); if (err < 0) { pr_err("ALSA: unable to register system timer (%i)\n", err); - goto put_timer; + put_device(&timer_dev); + return err; } err = snd_register_device(SNDRV_DEVICE_TYPE_TIMER, NULL, 0, @@ -2156,15 +2137,12 @@ static int __init alsa_timer_init(void) if (err < 0) { pr_err("ALSA: unable to register timer device (%i)\n", err); snd_timer_free_all(); - goto put_timer; + put_device(&timer_dev); + return err; } snd_timer_proc_init(); return 0; - -put_timer: - put_device(&timer_dev); - return err; } static void __exit alsa_timer_exit(void) @@ -2180,3 +2158,17 @@ static void __exit alsa_timer_exit(void) module_init(alsa_timer_init) module_exit(alsa_timer_exit) + +EXPORT_SYMBOL(snd_timer_open); +EXPORT_SYMBOL(snd_timer_close); +EXPORT_SYMBOL(snd_timer_resolution); +EXPORT_SYMBOL(snd_timer_start); +EXPORT_SYMBOL(snd_timer_stop); +EXPORT_SYMBOL(snd_timer_continue); +EXPORT_SYMBOL(snd_timer_pause); +EXPORT_SYMBOL(snd_timer_new); +EXPORT_SYMBOL(snd_timer_notify); +EXPORT_SYMBOL(snd_timer_global_new); +EXPORT_SYMBOL(snd_timer_global_free); +EXPORT_SYMBOL(snd_timer_global_register); +EXPORT_SYMBOL(snd_timer_interrupt); diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c index 58fa3f94722a..b67de2bb06a2 100644 --- a/sound/core/vmaster.c +++ b/sound/core/vmaster.c @@ -63,7 +63,7 @@ static int slave_update(struct link_slave *slave) struct snd_ctl_elem_value *uctl; int err, ch; - uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); + uctl = kmalloc(sizeof(*uctl), GFP_KERNEL); if (!uctl) return -ENOMEM; uctl->id = slave->slave.id; @@ -421,15 +421,13 @@ struct snd_kcontrol *snd_ctl_make_virtual_master(char *name, kctl->private_free = master_free; /* additional (constant) TLV read */ - if (tlv) { - unsigned int type = tlv[SNDRV_CTL_TLVO_TYPE]; - if (type == SNDRV_CTL_TLVT_DB_SCALE || - type == SNDRV_CTL_TLVT_DB_MINMAX || - type == SNDRV_CTL_TLVT_DB_MINMAX_MUTE) { - kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; - memcpy(master->tlv, tlv, sizeof(master->tlv)); - kctl->tlv.p = master->tlv; - } + if (tlv && + (tlv[0] == SNDRV_CTL_TLVT_DB_SCALE || + tlv[0] == SNDRV_CTL_TLVT_DB_MINMAX || + tlv[0] == SNDRV_CTL_TLVT_DB_MINMAX_MUTE)) { + kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; + memcpy(master->tlv, tlv, sizeof(master->tlv)); + kctl->tlv.p = master->tlv; } return kctl; diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig index 7144cc36e8ae..8545da99b183 100644 --- a/sound/drivers/Kconfig +++ b/sound/drivers/Kconfig @@ -6,24 +6,11 @@ config SND_OPL3_LIB tristate select SND_TIMER select SND_HWDEP - select SND_SEQ_DEVICE if SND_SEQUENCER != n config SND_OPL4_LIB tristate select SND_TIMER select SND_HWDEP - select SND_SEQ_DEVICE if SND_SEQUENCER != n - -# select SEQ stuff to min(SND_SEQUENCER,SND_XXX) -config SND_OPL3_LIB_SEQ - def_tristate SND_SEQUENCER && SND_OPL3_LIB - select SND_SEQ_MIDI_EMUL - select SND_SEQ_MIDI_EVENT - -config SND_OPL4_LIB_SEQ - def_tristate SND_SEQUENCER && SND_OPL4_LIB - select SND_SEQ_MIDI_EMUL - select SND_SEQ_MIDI_EVENT config SND_VX_LIB tristate @@ -112,8 +99,6 @@ config SND_VIRMIDI depends on SND_SEQUENCER select SND_TIMER select SND_RAWMIDI - select SND_SEQ_VIRMIDI - select SND_SEQ_MIDI_EVENT help Say Y here to include the virtual MIDI driver. This driver allows to connect applications using raw MIDI devices to diff --git a/sound/drivers/opl3/opl3_lib.c b/sound/drivers/opl3/opl3_lib.c index d5e5b4657b4b..cd9e9f31720f 100644 --- a/sound/drivers/opl3/opl3_lib.c +++ b/sound/drivers/opl3/opl3_lib.c @@ -528,7 +528,7 @@ int snd_opl3_hwdep_new(struct snd_opl3 * opl3, opl3->hwdep = hw; opl3->seq_dev_num = seq_device; -#if IS_ENABLED(CONFIG_SND_SEQUENCER) +#if IS_REACHABLE(CONFIG_SND_SEQUENCER) if (snd_seq_device_new(card, seq_device, SNDRV_SEQ_DEV_ID_OPL3, sizeof(struct snd_opl3 *), &opl3->seq_dev) >= 0) { strcpy(opl3->seq_dev->name, hw->name); diff --git a/sound/drivers/opl3/opl3_seq.c b/sound/drivers/opl3/opl3_seq.c index d3e91be8b23a..fdae5d7f421f 100644 --- a/sound/drivers/opl3/opl3_seq.c +++ b/sound/drivers/opl3/opl3_seq.c @@ -252,7 +252,7 @@ static int snd_opl3_seq_probe(struct device *_dev) spin_lock_init(&opl3->sys_timer_lock); opl3->sys_timer_status = 0; -#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS) +#ifdef CONFIG_SND_SEQUENCER_OSS snd_opl3_init_seq_oss(opl3, name); #endif return 0; @@ -267,7 +267,7 @@ static int snd_opl3_seq_remove(struct device *_dev) if (opl3 == NULL) return -EINVAL; -#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS) +#ifdef CONFIG_SND_SEQUENCER_OSS snd_opl3_free_seq_oss(opl3); #endif if (opl3->seq_client >= 0) { diff --git a/sound/drivers/opl3/opl3_voice.h b/sound/drivers/opl3/opl3_voice.h index eaef435e0528..a371c075ac87 100644 --- a/sound/drivers/opl3/opl3_voice.h +++ b/sound/drivers/opl3/opl3_voice.h @@ -44,12 +44,9 @@ void snd_opl3_load_drums(struct snd_opl3 *opl3); void snd_opl3_drum_switch(struct snd_opl3 *opl3, int note, int on_off, int vel, struct snd_midi_channel *chan); /* Prototypes for opl3_oss.c */ -#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS) +#ifdef CONFIG_SND_SEQUENCER_OSS void snd_opl3_init_seq_oss(struct snd_opl3 *opl3, char *name); void snd_opl3_free_seq_oss(struct snd_opl3 *opl3); -#else -#define snd_opl3_init_seq_oss(opl3, name) /* NOP */ -#define snd_opl3_free_seq_oss(opl3) /* NOP */ #endif #endif diff --git a/sound/drivers/opl4/opl4_lib.c b/sound/drivers/opl4/opl4_lib.c index bc345d564f8d..89c7aa04b3bc 100644 --- a/sound/drivers/opl4/opl4_lib.c +++ b/sound/drivers/opl4/opl4_lib.c @@ -153,7 +153,7 @@ static int snd_opl4_detect(struct snd_opl4 *opl4) return 0; } -#if IS_ENABLED(CONFIG_SND_SEQUENCER) +#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) static void snd_opl4_seq_dev_free(struct snd_seq_device *seq_dev) { struct snd_opl4 *opl4 = seq_dev->private_data; @@ -249,7 +249,7 @@ int snd_opl4_create(struct snd_card *card, snd_opl4_create_mixer(opl4); snd_opl4_create_proc(opl4); -#if IS_ENABLED(CONFIG_SND_SEQUENCER) +#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) opl4->seq_client = -1; if (opl4->hardware < OPL3_HW_OPL4_ML) snd_opl4_create_seq_dev(opl4, seq_device); diff --git a/sound/drivers/opl4/opl4_local.h b/sound/drivers/opl4/opl4_local.h index a16b4677c1e9..9a41bdebce6b 100644 --- a/sound/drivers/opl4/opl4_local.h +++ b/sound/drivers/opl4/opl4_local.h @@ -184,7 +184,7 @@ struct snd_opl4 { #endif struct mutex access_mutex; -#if IS_ENABLED(CONFIG_SND_SEQUENCER) +#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE) int used; int seq_dev_num; diff --git a/sound/drivers/vx/vx_mixer.c b/sound/drivers/vx/vx_mixer.c index 98a41ac40b60..be9477e30739 100644 --- a/sound/drivers/vx/vx_mixer.c +++ b/sound/drivers/vx/vx_mixer.c @@ -455,7 +455,7 @@ static int vx_output_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ele return 0; } -static const struct snd_kcontrol_new vx_control_output_level = { +static struct snd_kcontrol_new vx_control_output_level = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ), @@ -514,7 +514,7 @@ static int vx_audio_src_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v return 0; } -static const struct snd_kcontrol_new vx_control_audio_src = { +static struct snd_kcontrol_new vx_control_audio_src = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capture Source", .info = vx_audio_src_info, @@ -558,7 +558,7 @@ static int vx_clock_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ return 0; } -static const struct snd_kcontrol_new vx_control_clock_mode = { +static struct snd_kcontrol_new vx_control_clock_mode = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Clock Mode", .info = vx_clock_mode_info, @@ -717,7 +717,7 @@ static int vx_monitor_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ static const DECLARE_TLV_DB_SCALE(db_scale_audio_gain, -10975, 25, 0); -static const struct snd_kcontrol_new vx_control_audio_gain = { +static struct snd_kcontrol_new vx_control_audio_gain = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ), @@ -727,14 +727,14 @@ static const struct snd_kcontrol_new vx_control_audio_gain = { .put = vx_audio_gain_put, .tlv = { .p = db_scale_audio_gain }, }; -static const struct snd_kcontrol_new vx_control_output_switch = { +static struct snd_kcontrol_new vx_control_output_switch = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Switch", .info = vx_audio_sw_info, .get = vx_audio_sw_get, .put = vx_audio_sw_put }; -static const struct snd_kcontrol_new vx_control_monitor_gain = { +static struct snd_kcontrol_new vx_control_monitor_gain = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Monitoring Volume", .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | @@ -744,7 +744,7 @@ static const struct snd_kcontrol_new vx_control_monitor_gain = { .put = vx_audio_monitor_put, .tlv = { .p = db_scale_audio_gain }, }; -static const struct snd_kcontrol_new vx_control_monitor_switch = { +static struct snd_kcontrol_new vx_control_monitor_switch = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Monitoring Switch", .info = vx_audio_sw_info, /* shared */ @@ -805,7 +805,7 @@ static int vx_iec958_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu return 0; } -static const struct snd_kcontrol_new vx_control_iec958_mask = { +static struct snd_kcontrol_new vx_control_iec958_mask = { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK), @@ -813,7 +813,7 @@ static const struct snd_kcontrol_new vx_control_iec958_mask = { .get = vx_iec958_mask_get, }; -static const struct snd_kcontrol_new vx_control_iec958 = { +static struct snd_kcontrol_new vx_control_iec958 = { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), .info = vx_iec958_info, @@ -878,7 +878,7 @@ static int vx_saturation_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ return 0; } -static const struct snd_kcontrol_new vx_control_vu_meter = { +static struct snd_kcontrol_new vx_control_vu_meter = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, /* name will be filled later */ @@ -886,7 +886,7 @@ static const struct snd_kcontrol_new vx_control_vu_meter = { .get = vx_vu_meter_get, }; -static const struct snd_kcontrol_new vx_control_peak_meter = { +static struct snd_kcontrol_new vx_control_peak_meter = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, /* name will be filled later */ @@ -894,7 +894,7 @@ static const struct snd_kcontrol_new vx_control_peak_meter = { .get = vx_peak_meter_get, }; -static const struct snd_kcontrol_new vx_control_saturation = { +static struct snd_kcontrol_new vx_control_saturation = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Input Saturation", .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, diff --git a/sound/firewire/bebob/bebob_maudio.c b/sound/firewire/bebob/bebob_maudio.c index d3fb5022a65a..6dbf047d4f75 100644 --- a/sound/firewire/bebob/bebob_maudio.c +++ b/sound/firewire/bebob/bebob_maudio.c @@ -396,7 +396,7 @@ static int special_clk_ctl_put(struct snd_kcontrol *kctl, return err; } -static const struct snd_kcontrol_new special_clk_ctl = { +static struct snd_kcontrol_new special_clk_ctl = { .name = "Clock Source", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, @@ -429,7 +429,7 @@ static int special_sync_ctl_get(struct snd_kcontrol *kctl, return 0; } -static const struct snd_kcontrol_new special_sync_ctl = { +static struct snd_kcontrol_new special_sync_ctl = { .name = "Sync Status", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = SNDRV_CTL_ELEM_ACCESS_READ, @@ -521,7 +521,7 @@ end: mutex_unlock(&bebob->mutex); return err; } -static const struct snd_kcontrol_new special_dig_in_iface_ctl = { +static struct snd_kcontrol_new special_dig_in_iface_ctl = { .name = "Digital Input Interface", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, @@ -577,7 +577,7 @@ static int special_dig_out_iface_ctl_set(struct snd_kcontrol *kctl, mutex_unlock(&bebob->mutex); return err; } -static const struct snd_kcontrol_new special_dig_out_iface_ctl = { +static struct snd_kcontrol_new special_dig_out_iface_ctl = { .name = "Digital Output Interface", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index b7a75b0a382a..37adcc6cbe6b 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -377,7 +377,6 @@ config SND_SBAWE select SND_OPL3_LIB select SND_MPU401_UART select SND_SB16_DSP - select SND_SEQ_DEVICE if SND_SEQUENCER != n help Say Y here to include support for Sound Blaster AWE soundcards (including the Plug and Play version). @@ -385,12 +384,6 @@ config SND_SBAWE To compile this driver as a module, choose M here: the module will be called snd-sbawe. -# select SEQ stuff to min(SND_SEQUENCER,SND_XXX) -config SND_SBAWE_SEQ - def_tristate SND_SEQUENCER && SND_SBAWE - select SND_SEQ_MIDI_EMUL - select SND_SEQ_VIRMIDI - config SND_SB16_CSP bool "Sound Blaster 16/AWE CSP support" depends on (SND_SB16 || SND_SBAWE) && (BROKEN || !PPC) diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c index d56973b770c7..ec180708f160 100644 --- a/sound/isa/sb/emu8000.c +++ b/sound/isa/sb/emu8000.c @@ -1138,7 +1138,7 @@ snd_emu8000_new(struct snd_card *card, int index, long port, int seq_ports, snd_emu8000_free(hw); return err; } -#if IS_ENABLED(CONFIG_SND_SEQUENCER) +#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) if (snd_seq_device_new(card, index, SNDRV_SEQ_DEV_ID_EMU8000, sizeof(struct snd_emu8000*), &awe) >= 0) { strcpy(awe->name, "EMU-8000"); diff --git a/sound/isa/sb/emu8000_callback.c b/sound/isa/sb/emu8000_callback.c index d28d712f99f4..72a9ac5efb40 100644 --- a/sound/isa/sb/emu8000_callback.c +++ b/sound/isa/sb/emu8000_callback.c @@ -36,7 +36,7 @@ static void reset_voice(struct snd_emux *emu, int ch); static void terminate_voice(struct snd_emux_voice *vp); static void sysex(struct snd_emux *emu, char *buf, int len, int parsed, struct snd_midi_channel_set *chset); -#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS) +#ifdef CONFIG_SND_SEQUENCER_OSS static int oss_ioctl(struct snd_emux *emu, int cmd, int p1, int p2); #endif static int load_fx(struct snd_emux *emu, int type, int mode, @@ -76,7 +76,7 @@ static struct snd_emux_operators emu8000_ops = { .sample_reset = snd_emu8000_sample_reset, .load_fx = load_fx, .sysex = sysex, -#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS) +#ifdef CONFIG_SND_SEQUENCER_OSS .oss_ioctl = oss_ioctl, #endif }; @@ -477,7 +477,7 @@ sysex(struct snd_emux *emu, char *buf, int len, int parsed, struct snd_midi_chan } -#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS) +#ifdef CONFIG_SND_SEQUENCER_OSS /* * OSS ioctl callback */ diff --git a/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c index 917a93d696c3..3b2e4f405ff2 100644 --- a/sound/isa/sb/sb16.c +++ b/sound/isa/sb/sb16.c @@ -62,7 +62,7 @@ MODULE_SUPPORTED_DEVICE("{{Creative Labs,SB AWE 32}," #define SNDRV_DEBUG_IRQ #endif -#if defined(SNDRV_SBAWE) && IS_ENABLED(CONFIG_SND_SEQUENCER) +#if defined(SNDRV_SBAWE) && (defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))) #define SNDRV_SBAWE_EMU8000 #endif diff --git a/sound/mips/hal2.c b/sound/mips/hal2.c index 6505deb8c06b..684dc4ddef41 100644 --- a/sound/mips/hal2.c +++ b/sound/mips/hal2.c @@ -264,7 +264,7 @@ static int hal2_gain_put(struct snd_kcontrol *kcontrol, return old != new; } -static const struct snd_kcontrol_new hal2_ctrl_headphone = { +static struct snd_kcontrol_new hal2_ctrl_headphone = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Headphone Playback Volume", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, @@ -274,7 +274,7 @@ static const struct snd_kcontrol_new hal2_ctrl_headphone = { .put = hal2_gain_put, }; -static const struct snd_kcontrol_new hal2_ctrl_mic = { +static struct snd_kcontrol_new hal2_ctrl_mic = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Mic Capture Volume", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, diff --git a/sound/mips/sgio2audio.c b/sound/mips/sgio2audio.c index 0ebc1c3727df..f07aa3993f83 100644 --- a/sound/mips/sgio2audio.c +++ b/sound/mips/sgio2audio.c @@ -230,7 +230,7 @@ static int sgio2audio_source_put(struct snd_kcontrol *kcontrol, } /* dac1/pcm0 mixer control */ -static const struct snd_kcontrol_new sgio2audio_ctrl_pcm0 = { +static struct snd_kcontrol_new sgio2audio_ctrl_pcm0 = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Volume", .index = 0, @@ -242,7 +242,7 @@ static const struct snd_kcontrol_new sgio2audio_ctrl_pcm0 = { }; /* dac2/pcm1 mixer control */ -static const struct snd_kcontrol_new sgio2audio_ctrl_pcm1 = { +static struct snd_kcontrol_new sgio2audio_ctrl_pcm1 = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Volume", .index = 1, @@ -254,7 +254,7 @@ static const struct snd_kcontrol_new sgio2audio_ctrl_pcm1 = { }; /* record level mixer control */ -static const struct snd_kcontrol_new sgio2audio_ctrl_reclevel = { +static struct snd_kcontrol_new sgio2audio_ctrl_reclevel = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capture Volume", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, @@ -265,7 +265,7 @@ static const struct snd_kcontrol_new sgio2audio_ctrl_reclevel = { }; /* record level source control */ -static const struct snd_kcontrol_new sgio2audio_ctrl_recsource = { +static struct snd_kcontrol_new sgio2audio_ctrl_recsource = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capture Source", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, @@ -275,7 +275,7 @@ static const struct snd_kcontrol_new sgio2audio_ctrl_recsource = { }; /* line mixer control */ -static const struct snd_kcontrol_new sgio2audio_ctrl_line = { +static struct snd_kcontrol_new sgio2audio_ctrl_line = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Line Playback Volume", .index = 0, @@ -287,7 +287,7 @@ static const struct snd_kcontrol_new sgio2audio_ctrl_line = { }; /* cd mixer control */ -static const struct snd_kcontrol_new sgio2audio_ctrl_cd = { +static struct snd_kcontrol_new sgio2audio_ctrl_cd = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Line Playback Volume", .index = 1, @@ -299,7 +299,7 @@ static const struct snd_kcontrol_new sgio2audio_ctrl_cd = { }; /* mic mixer control */ -static const struct snd_kcontrol_new sgio2audio_ctrl_mic = { +static struct snd_kcontrol_new sgio2audio_ctrl_mic = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Mic Playback Volume", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 914b859770f8..32151d8c6bb8 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -465,7 +465,6 @@ config SND_EMU10K1 select SND_RAWMIDI select SND_AC97_CODEC select SND_TIMER - select SND_SEQ_DEVICE if SND_SEQUENCER != n depends on ZONE_DMA help Say Y to include support for Sound Blaster PCI 512, Live!, @@ -478,12 +477,6 @@ config SND_EMU10K1 To compile this driver as a module, choose M here: the module will be called snd-emu10k1. -# select SEQ stuff to min(SND_SEQUENCER,SND_XXX) -config SND_EMU10K1_SEQ - def_tristate SND_SEQUENCER && SND_EMU10K1 - select SND_SEQ_MIDI_EMUL - select SND_SEQ_VIRMIDI - config SND_EMU10K1X tristate "Emu10k1X (Dell OEM Version)" select SND_AC97_CODEC diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index d3203df50a1a..6a0e49ac5273 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -37,7 +37,7 @@ MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Creative Labs,SB Live!/PCI512/E-mu APS}," "{Creative Labs,SB Audigy}}"); -#if IS_ENABLED(CONFIG_SND_SEQUENCER) +#if IS_REACHABLE(CONFIG_SND_SEQUENCER) #define ENABLE_SYNTH #include <sound/emu10k1_synth.h> #endif diff --git a/sound/pcmcia/vx/vxp_mixer.c b/sound/pcmcia/vx/vxp_mixer.c index 425315cf60e2..a4a664259f0d 100644 --- a/sound/pcmcia/vx/vxp_mixer.c +++ b/sound/pcmcia/vx/vxp_mixer.c @@ -69,7 +69,7 @@ static int vx_mic_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v static const DECLARE_TLV_DB_SCALE(db_scale_mic, -21, 3, 0); -static const struct snd_kcontrol_new vx_control_mic_level = { +static struct snd_kcontrol_new vx_control_mic_level = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ), @@ -109,7 +109,7 @@ static int vx_mic_boost_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v return 0; } -static const struct snd_kcontrol_new vx_control_mic_boost = { +static struct snd_kcontrol_new vx_control_mic_boost = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Mic Boost", .info = vx_mic_boost_info, diff --git a/sound/ppc/awacs.c b/sound/ppc/awacs.c index d1e4ef1c5c30..1468e4b7bf93 100644 --- a/sound/ppc/awacs.c +++ b/sound/ppc/awacs.c @@ -514,7 +514,7 @@ static struct snd_kcontrol_new snd_pmac_awacs_amp_vol[] = { }, }; -static const struct snd_kcontrol_new snd_pmac_awacs_amp_hp_sw = { +static struct snd_kcontrol_new snd_pmac_awacs_amp_hp_sw = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Headphone Playback Switch", .info = snd_pmac_boolean_stereo_info, @@ -523,7 +523,7 @@ static const struct snd_kcontrol_new snd_pmac_awacs_amp_hp_sw = { .private_value = AMP_CH_HD, }; -static const struct snd_kcontrol_new snd_pmac_awacs_amp_spk_sw = { +static struct snd_kcontrol_new snd_pmac_awacs_amp_spk_sw = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Speaker Playback Switch", .info = snd_pmac_boolean_stereo_info, diff --git a/sound/ppc/beep.c b/sound/ppc/beep.c index f19eb3e39937..d3524f9fa05d 100644 --- a/sound/ppc/beep.c +++ b/sound/ppc/beep.c @@ -206,7 +206,7 @@ static int snd_pmac_put_beep(struct snd_kcontrol *kcontrol, return oval != chip->beep->volume; } -static const struct snd_kcontrol_new snd_pmac_beep_mixer = { +static struct snd_kcontrol_new snd_pmac_beep_mixer = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Beep Playback Volume", .info = snd_pmac_info_beep, diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index 0779a2912237..58ee8089bbf9 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c @@ -897,7 +897,7 @@ static struct snd_kcontrol_new snapper_mixers[] = { }, }; -static const struct snd_kcontrol_new tumbler_hp_sw = { +static struct snd_kcontrol_new tumbler_hp_sw = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Headphone Playback Switch", .info = snd_pmac_boolean_mono_info, @@ -905,7 +905,7 @@ static const struct snd_kcontrol_new tumbler_hp_sw = { .put = tumbler_put_mute_switch, .private_value = TUMBLER_MUTE_HP, }; -static const struct snd_kcontrol_new tumbler_speaker_sw = { +static struct snd_kcontrol_new tumbler_speaker_sw = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Speaker Playback Switch", .info = snd_pmac_boolean_mono_info, @@ -913,7 +913,7 @@ static const struct snd_kcontrol_new tumbler_speaker_sw = { .put = tumbler_put_mute_switch, .private_value = TUMBLER_MUTE_AMP, }; -static const struct snd_kcontrol_new tumbler_lineout_sw = { +static struct snd_kcontrol_new tumbler_lineout_sw = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Line Out Playback Switch", .info = snd_pmac_boolean_mono_info, @@ -921,7 +921,7 @@ static const struct snd_kcontrol_new tumbler_lineout_sw = { .put = tumbler_put_mute_switch, .private_value = TUMBLER_MUTE_LINE, }; -static const struct snd_kcontrol_new tumbler_drc_sw = { +static struct snd_kcontrol_new tumbler_drc_sw = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "DRC Switch", .info = snd_pmac_boolean_mono_info, diff --git a/sound/sh/aica.c b/sound/sh/aica.c index ab4802df62e1..fbbc25279559 100644 --- a/sound/sh/aica.c +++ b/sound/sh/aica.c @@ -535,7 +535,7 @@ static int aica_pcmvolume_put(struct snd_kcontrol *kcontrol, return 1; } -static const struct snd_kcontrol_new snd_aica_pcmswitch_control = { +static struct snd_kcontrol_new snd_aica_pcmswitch_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Switch", .index = 0, @@ -544,7 +544,7 @@ static const struct snd_kcontrol_new snd_aica_pcmswitch_control = { .put = aica_pcmswitch_put }; -static const struct snd_kcontrol_new snd_aica_pcmvolume_control = { +static struct snd_kcontrol_new snd_aica_pcmvolume_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Volume", .index = 0, diff --git a/sound/soc/sh/siu_dai.c b/sound/soc/sh/siu_dai.c index 4a22aadac294..76b2ab8c2b4a 100644 --- a/sound/soc/sh/siu_dai.c +++ b/sound/soc/sh/siu_dai.c @@ -441,7 +441,7 @@ static int siu_dai_put_volume(struct snd_kcontrol *kctrl, return 0; } -static const struct snd_kcontrol_new playback_controls = { +static struct snd_kcontrol_new playback_controls = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Volume", .index = 0, @@ -451,7 +451,7 @@ static const struct snd_kcontrol_new playback_controls = { .private_value = VOLUME_PLAYBACK, }; -static const struct snd_kcontrol_new capture_controls = { +static struct snd_kcontrol_new capture_controls = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Capture Volume", .index = 0, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 6e460bdb2b3e..8a64a1b22705 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -638,7 +638,9 @@ int snd_soc_suspend(struct device *dev) /* Due to the resume being scheduled into a workqueue we could * suspend before that's finished - wait for it to complete. */ + snd_power_lock(card->snd_card); snd_power_wait(card->snd_card, SNDRV_CTL_POWER_D0); + snd_power_unlock(card->snd_card); /* we're going to block userspace touching us until resume completes */ snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot); diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 5eeca313bd9a..914cb99a6ed2 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2744,9 +2744,8 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) if (platform->driver->ops) { rtd->ops.ack = platform->driver->ops->ack; - rtd->ops.copy_user = platform->driver->ops->copy_user; - rtd->ops.copy_kernel = platform->driver->ops->copy_kernel; - rtd->ops.fill_silence = platform->driver->ops->fill_silence; + rtd->ops.copy = platform->driver->ops->copy; + rtd->ops.silence = platform->driver->ops->silence; rtd->ops.page = platform->driver->ops->page; rtd->ops.mmap = platform->driver->ops->mmap; } diff --git a/sound/synth/emux/emux.c b/sound/synth/emux/emux.c index b9981e8c0027..9312cd8a6fdd 100644 --- a/sound/synth/emux/emux.c +++ b/sound/synth/emux/emux.c @@ -47,7 +47,7 @@ int snd_emux_new(struct snd_emux **remu) mutex_init(&emu->register_mutex); emu->client = -1; -#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS) +#ifdef CONFIG_SND_SEQUENCER_OSS emu->oss_synth = NULL; #endif emu->max_voices = 0; @@ -123,7 +123,7 @@ int snd_emux_register(struct snd_emux *emu, struct snd_card *card, int index, ch snd_emux_init_voices(emu); snd_emux_init_seq(emu, card, index); -#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS) +#ifdef CONFIG_SND_SEQUENCER_OSS snd_emux_init_seq_oss(emu); #endif snd_emux_init_virmidi(emu, card); @@ -150,7 +150,7 @@ int snd_emux_free(struct snd_emux *emu) snd_emux_proc_free(emu); snd_emux_delete_virmidi(emu); -#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS) +#ifdef CONFIG_SND_SEQUENCER_OSS snd_emux_detach_seq_oss(emu); #endif snd_emux_detach_seq(emu); diff --git a/sound/synth/emux/emux_effect.c b/sound/synth/emux/emux_effect.c index 9ac0bf531b4b..a447218b6160 100644 --- a/sound/synth/emux/emux_effect.c +++ b/sound/synth/emux/emux_effect.c @@ -150,7 +150,7 @@ effect_get_offset(struct snd_midi_channel *chan, int lo, int hi, int mode) return addr; } -#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS) +#ifdef CONFIG_SND_SEQUENCER_OSS /* change effects - for OSS sequencer compatibility */ void snd_emux_send_effect_oss(struct snd_emux_port *port, diff --git a/sound/synth/emux/emux_oss.c b/sound/synth/emux/emux_oss.c index de19e108974a..850fab4a8f3b 100644 --- a/sound/synth/emux/emux_oss.c +++ b/sound/synth/emux/emux_oss.c @@ -23,6 +23,8 @@ */ +#ifdef CONFIG_SND_SEQUENCER_OSS + #include <linux/export.h> #include <linux/uaccess.h> #include <sound/core.h> @@ -503,3 +505,5 @@ fake_event(struct snd_emux *emu, struct snd_emux_port *port, int ch, int param, ev.data.control.value = val; snd_emux_event_input(&ev, 0, port, atomic, hop); } + +#endif /* CONFIG_SND_SEQUENCER_OSS */ diff --git a/sound/usb/6fire/chip.c b/sound/usb/6fire/chip.c index 17d5e3ee6d73..dcddfc354ba6 100644 --- a/sound/usb/6fire/chip.c +++ b/sound/usb/6fire/chip.c @@ -143,40 +143,47 @@ static int usb6fire_chip_probe(struct usb_interface *intf, chip->card = card; ret = usb6fire_comm_init(chip); - if (ret < 0) - goto destroy_chip; + if (ret < 0) { + usb6fire_chip_destroy(chip); + return ret; + } ret = usb6fire_midi_init(chip); - if (ret < 0) - goto destroy_chip; + if (ret < 0) { + usb6fire_chip_destroy(chip); + return ret; + } ret = usb6fire_pcm_init(chip); - if (ret < 0) - goto destroy_chip; + if (ret < 0) { + usb6fire_chip_destroy(chip); + return ret; + } ret = usb6fire_control_init(chip); - if (ret < 0) - goto destroy_chip; + if (ret < 0) { + usb6fire_chip_destroy(chip); + return ret; + } ret = snd_card_register(card); if (ret < 0) { dev_err(&intf->dev, "cannot register card."); - goto destroy_chip; + usb6fire_chip_destroy(chip); + return ret; } usb_set_intfdata(intf, chip); return 0; - -destroy_chip: - usb6fire_chip_destroy(chip); - return ret; } static void usb6fire_chip_disconnect(struct usb_interface *intf) { struct sfire_chip *chip; + struct snd_card *card; chip = usb_get_intfdata(intf); if (chip) { /* if !chip, fw upload has been performed */ + card = chip->card; chip->intf_count--; if (!chip->intf_count) { mutex_lock(®ister_mutex); @@ -191,7 +198,7 @@ static void usb6fire_chip_disconnect(struct usb_interface *intf) } } -static const struct usb_device_id device_table[] = { +static struct usb_device_id device_table[] = { { .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = 0x0ccd, diff --git a/sound/usb/Makefile b/sound/usb/Makefile index a3ee9dba21b0..42cb33b94f6a 100644 --- a/sound/usb/Makefile +++ b/sound/usb/Makefile @@ -12,7 +12,6 @@ snd-usb-audio-objs := card.o \ mixer_scarlett.o \ mixer_us16x08.o \ pcm.o \ - power.o \ proc.o \ quirks.o \ stream.o diff --git a/sound/usb/bcd2000/bcd2000.c b/sound/usb/bcd2000/bcd2000.c index d6c8b29fe430..7ca44be0fb58 100644 --- a/sound/usb/bcd2000/bcd2000.c +++ b/sound/usb/bcd2000/bcd2000.c @@ -29,7 +29,7 @@ #define PREFIX "snd-bcd2000: " #define BUFSIZE 64 -static const struct usb_device_id id_table[] = { +static struct usb_device_id id_table[] = { { USB_DEVICE(0x1397, 0x00bd) }, { }, }; diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c index 60dac0587e04..8f66ba730d69 100644 --- a/sound/usb/caiaq/audio.c +++ b/sound/usb/caiaq/audio.c @@ -636,7 +636,6 @@ static void read_completed(struct urb *urb) struct device *dev; struct urb *out = NULL; int i, frame, len, send_it = 0, outframe = 0; - unsigned long flags; size_t offset = 0; if (urb->status || !info) @@ -673,10 +672,10 @@ static void read_completed(struct urb *urb) offset += len; if (len > 0) { - spin_lock_irqsave(&cdev->spinlock, flags); + spin_lock(&cdev->spinlock); fill_out_urb(cdev, out, &out->iso_frame_desc[outframe]); read_in_urb(cdev, urb, &urb->iso_frame_desc[frame]); - spin_unlock_irqrestore(&cdev->spinlock, flags); + spin_unlock(&cdev->spinlock); check_for_elapsed_periods(cdev, cdev->sub_playback); check_for_elapsed_periods(cdev, cdev->sub_capture); send_it = 1; diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c index f4a72e39ffa9..ca692b8b3690 100644 --- a/sound/usb/caiaq/device.c +++ b/sound/usb/caiaq/device.c @@ -81,7 +81,7 @@ enum { DEPTH_32 = 3 }; -static const struct usb_device_id snd_usb_id_table[] = { +static struct usb_device_id snd_usb_id_table[] = { { .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = USB_VID_NATIVEINSTRUMENTS, @@ -200,7 +200,6 @@ static void usb_ep1_command_reply_dispatch (struct urb* urb) break; } #ifdef CONFIG_SND_USB_CAIAQ_INPUT - /* fall through */ case EP1_CMD_READ_ERP: case EP1_CMD_READ_ANALOG: snd_usb_caiaq_input_dispatch(cdev, buf, urb->actual_length); diff --git a/sound/usb/card.c b/sound/usb/card.c index a105947eaf55..c505b1f8e263 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -7,7 +7,6 @@ * Alan Cox (alan@lxorguk.ukuu.org.uk) * Thomas Sailer (sailer@ife.ee.ethz.ch) * - * Audio Class 3.0 support by Ruslan Bilovol <ruslan.bilovol@gmail.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -45,7 +44,6 @@ #include <linux/mutex.h> #include <linux/usb/audio.h> #include <linux/usb/audio-v2.h> -#include <linux/usb/audio-v3.h> #include <linux/module.h> #include <sound/control.h> @@ -86,8 +84,6 @@ static bool ignore_ctl_error; static bool autoclock = true; static char *quirk_alias[SNDRV_CARDS]; -bool snd_usb_use_vmalloc = true; - module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for the USB audio adapter."); module_param_array(id, charp, NULL, 0444); @@ -107,8 +103,6 @@ module_param(autoclock, bool, 0444); MODULE_PARM_DESC(autoclock, "Enable auto-clock selection for UAC2 devices (default: yes)."); module_param_array(quirk_alias, charp, NULL, 0444); MODULE_PARM_DESC(quirk_alias, "Quirk aliases, e.g. 0123abcd:5678beef."); -module_param_named(use_vmalloc, snd_usb_use_vmalloc, bool, 0444); -MODULE_PARM_DESC(use_vmalloc, "Use vmalloc for PCM intermediate buffers (default: yes)."); /* * we keep the snd_usb_audio_t instances by ourselves for merging @@ -225,13 +219,32 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) struct usb_device *dev = chip->dev; struct usb_host_interface *host_iface; struct usb_interface_descriptor *altsd; + void *control_header; int i, protocol; + int rest_bytes; /* find audiocontrol interface */ host_iface = &usb_ifnum_to_if(dev, ctrlif)->altsetting[0]; + control_header = snd_usb_find_csint_desc(host_iface->extra, + host_iface->extralen, + NULL, UAC_HEADER); altsd = get_iface_desc(host_iface); protocol = altsd->bInterfaceProtocol; + if (!control_header) { + dev_err(&dev->dev, "cannot find UAC_HEADER\n"); + return -EINVAL; + } + + rest_bytes = (void *)(host_iface->extra + host_iface->extralen) - + control_header; + + /* just to be sure -- this shouldn't hit at all */ + if (rest_bytes <= 0) { + dev_err(&dev->dev, "invalid control header\n"); + return -EINVAL; + } + switch (protocol) { default: dev_warn(&dev->dev, @@ -240,25 +253,7 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) /* fall through */ case UAC_VERSION_1: { - struct uac1_ac_header_descriptor *h1; - int rest_bytes; - - h1 = snd_usb_find_csint_desc(host_iface->extra, - host_iface->extralen, - NULL, UAC_HEADER); - if (!h1) { - dev_err(&dev->dev, "cannot find UAC_HEADER\n"); - return -EINVAL; - } - - rest_bytes = (void *)(host_iface->extra + - host_iface->extralen) - (void *)h1; - - /* just to be sure -- this shouldn't hit at all */ - if (rest_bytes <= 0) { - dev_err(&dev->dev, "invalid control header\n"); - return -EINVAL; - } + struct uac1_ac_header_descriptor *h1 = control_header; if (rest_bytes < sizeof(*h1)) { dev_err(&dev->dev, "too short v1 buffer descriptor\n"); @@ -286,8 +281,7 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) break; } - case UAC_VERSION_2: - case UAC_VERSION_3: { + case UAC_VERSION_2: { struct usb_interface_assoc_descriptor *assoc = usb_ifnum_to_if(dev, ctrlif)->intf_assoc; @@ -307,24 +301,10 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) } if (!assoc) { - dev_err(&dev->dev, "Audio class v2/v3 interfaces need an interface association\n"); + dev_err(&dev->dev, "Audio class v2 interfaces need an interface association\n"); return -EINVAL; } - if (protocol == UAC_VERSION_3) { - int badd = assoc->bFunctionSubClass; - - if (badd != UAC3_FUNCTION_SUBCLASS_FULL_ADC_3_0 && - (badd < UAC3_FUNCTION_SUBCLASS_GENERIC_IO || - badd > UAC3_FUNCTION_SUBCLASS_SPEAKERPHONE)) { - dev_err(&dev->dev, - "Unsupported UAC3 BADD profile\n"); - return -EINVAL; - } - - chip->badd_profile = badd; - } - for (i = 0; i < assoc->bInterfaceCount; i++) { int intf = assoc->bFirstInterface + i; @@ -346,9 +326,8 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) * */ -static void snd_usb_audio_free(struct snd_card *card) +static int snd_usb_audio_free(struct snd_usb_audio *chip) { - struct snd_usb_audio *chip = card->private_data; struct snd_usb_endpoint *ep, *n; list_for_each_entry_safe(ep, n, &chip->ep_list, list) @@ -357,6 +336,14 @@ static void snd_usb_audio_free(struct snd_card *card) mutex_destroy(&chip->mutex); if (!atomic_read(&chip->shutdown)) dev_set_drvdata(&chip->dev->dev, NULL); + kfree(chip); + return 0; +} + +static int snd_usb_audio_dev_free(struct snd_device *device) +{ + struct snd_usb_audio *chip = device->device_data; + return snd_usb_audio_free(chip); } static void usb_audio_make_shortname(struct usb_device *dev, @@ -456,6 +443,9 @@ static int snd_usb_audio_create(struct usb_interface *intf, struct snd_usb_audio *chip; int err; char component[14]; + static struct snd_device_ops ops = { + .dev_free = snd_usb_audio_dev_free, + }; *rchip = NULL; @@ -473,13 +463,18 @@ static int snd_usb_audio_create(struct usb_interface *intf, } err = snd_card_new(&intf->dev, index[idx], id[idx], THIS_MODULE, - sizeof(*chip), &card); + 0, &card); if (err < 0) { dev_err(&dev->dev, "cannot create card instance %d\n", idx); return err; } - chip = card->private_data; + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (! chip) { + snd_card_free(card); + return -ENOMEM; + } + mutex_init(&chip->mutex); init_waitqueue_head(&chip->shutdown_wait); chip->index = idx; @@ -497,7 +492,11 @@ static int snd_usb_audio_create(struct usb_interface *intf, INIT_LIST_HEAD(&chip->midi_list); INIT_LIST_HEAD(&chip->mixer_list); - card->private_free = snd_usb_audio_free; + if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { + snd_usb_audio_free(chip); + snd_card_free(card); + return err; + } strcpy(card->driver, "USB-Audio"); sprintf(component, "USB%04x:%04x", @@ -535,7 +534,7 @@ static bool get_alias_id(struct usb_device *dev, unsigned int *id) return false; } -static const struct usb_device_id usb_audio_ids[]; /* defined below */ +static struct usb_device_id usb_audio_ids[]; /* defined below */ /* look for the corresponding quirk */ static const struct snd_usb_audio_quirk * @@ -812,7 +811,6 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) if (!chip->num_suspended_intf++) { list_for_each_entry(as, &chip->pcm_list, list) { snd_pcm_suspend_all(as->pcm); - snd_usb_pcm_suspend(as); as->substream[0].need_setup_ep = as->substream[1].need_setup_ep = true; } @@ -828,7 +826,6 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume) { struct snd_usb_audio *chip = usb_get_intfdata(intf); - struct snd_usb_stream *as; struct usb_mixer_interface *mixer; struct list_head *p; int err = 0; @@ -839,13 +836,6 @@ static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume) return 0; atomic_inc(&chip->active); /* avoid autopm */ - - list_for_each_entry(as, &chip->pcm_list, list) { - err = snd_usb_pcm_resume(as); - if (err < 0) - goto err_out; - } - /* * ALSA leaves material resumption to user space * we just notify and restart the mixers @@ -884,7 +874,7 @@ static int usb_audio_reset_resume(struct usb_interface *intf) #define usb_audio_reset_resume NULL #endif /* CONFIG_PM */ -static const struct usb_device_id usb_audio_ids [] = { +static struct usb_device_id usb_audio_ids [] = { #include "quirks-table.h" { .match_flags = (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS), .bInterfaceClass = USB_CLASS_AUDIO, diff --git a/sound/usb/card.h b/sound/usb/card.h index 5dc808e41f2a..cbcf2158e61d 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -21,7 +21,7 @@ struct audioformat { unsigned char endpoint; /* endpoint */ unsigned char ep_attr; /* endpoint attributes */ unsigned char datainterval; /* log_2 of data packet interval */ - unsigned char protocol; /* UAC_VERSION_1/2/3 */ + unsigned char protocol; /* UAC_VERSION_1/2 */ unsigned int maxpacksize; /* max. packet size */ unsigned int rates; /* rate bitmasks */ unsigned int rate_min, rate_max; /* min/max rates */ @@ -36,7 +36,6 @@ struct audioformat { struct snd_usb_substream; struct snd_usb_endpoint; -struct snd_usb_power_domain; struct snd_urb_ctx { struct urb *urb; @@ -115,7 +114,6 @@ struct snd_usb_substream { int interface; /* current interface */ int endpoint; /* assigned endpoint */ struct audioformat *cur_audiofmt; /* current audioformat pointer (for hw_params callback) */ - struct snd_usb_power_domain *str_pd; /* UAC3 Power Domain for streaming path */ snd_pcm_format_t pcm_format; /* current audio format (for hw_params callback) */ unsigned int channels; /* current number of channels (for hw_params callback) */ unsigned int channels_max; /* max channels in the all audiofmts */ diff --git a/sound/usb/clock.c b/sound/usb/clock.c index db5e39d67a90..eb3396ffba4c 100644 --- a/sound/usb/clock.c +++ b/sound/usb/clock.c @@ -23,7 +23,6 @@ #include <linux/usb.h> #include <linux/usb/audio.h> #include <linux/usb/audio-v2.h> -#include <linux/usb/audio-v3.h> #include <sound/core.h> #include <sound/info.h> @@ -35,85 +34,57 @@ #include "clock.h" #include "quirks.h" -static void *find_uac_clock_desc(struct usb_host_interface *iface, int id, - bool (*validator)(void *, int), u8 type) +static struct uac_clock_source_descriptor * + snd_usb_find_clock_source(struct usb_host_interface *ctrl_iface, + int clock_id) { - void *cs = NULL; + struct uac_clock_source_descriptor *cs = NULL; - while ((cs = snd_usb_find_csint_desc(iface->extra, iface->extralen, - cs, type))) { - if (validator(cs, id)) + while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra, + ctrl_iface->extralen, + cs, UAC2_CLOCK_SOURCE))) { + if (cs->bLength >= sizeof(*cs) && cs->bClockID == clock_id) return cs; } return NULL; } -static bool validate_clock_source_v2(void *p, int id) +static struct uac_clock_selector_descriptor * + snd_usb_find_clock_selector(struct usb_host_interface *ctrl_iface, + int clock_id) { - struct uac_clock_source_descriptor *cs = p; - return cs->bLength == sizeof(*cs) && cs->bClockID == id; -} - -static bool validate_clock_source_v3(void *p, int id) -{ - struct uac3_clock_source_descriptor *cs = p; - return cs->bLength == sizeof(*cs) && cs->bClockID == id; -} - -static bool validate_clock_selector_v2(void *p, int id) -{ - struct uac_clock_selector_descriptor *cs = p; - return cs->bLength >= sizeof(*cs) && cs->bClockID == id && - cs->bLength == 7 + cs->bNrInPins; -} + struct uac_clock_selector_descriptor *cs = NULL; + + while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra, + ctrl_iface->extralen, + cs, UAC2_CLOCK_SELECTOR))) { + if (cs->bLength >= sizeof(*cs) && cs->bClockID == clock_id) { + if (cs->bLength < 5 + cs->bNrInPins) + return NULL; + return cs; + } + } -static bool validate_clock_selector_v3(void *p, int id) -{ - struct uac3_clock_selector_descriptor *cs = p; - return cs->bLength >= sizeof(*cs) && cs->bClockID == id && - cs->bLength == 11 + cs->bNrInPins; + return NULL; } -static bool validate_clock_multiplier_v2(void *p, int id) +static struct uac_clock_multiplier_descriptor * + snd_usb_find_clock_multiplier(struct usb_host_interface *ctrl_iface, + int clock_id) { - struct uac_clock_multiplier_descriptor *cs = p; - return cs->bLength == sizeof(*cs) && cs->bClockID == id; -} + struct uac_clock_multiplier_descriptor *cs = NULL; -static bool validate_clock_multiplier_v3(void *p, int id) -{ - struct uac3_clock_multiplier_descriptor *cs = p; - return cs->bLength == sizeof(*cs) && cs->bClockID == id; -} + while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra, + ctrl_iface->extralen, + cs, UAC2_CLOCK_MULTIPLIER))) { + if (cs->bLength >= sizeof(*cs) && cs->bClockID == clock_id) + return cs; + } -#define DEFINE_FIND_HELPER(name, obj, validator, type) \ -static obj *name(struct usb_host_interface *iface, int id) \ -{ \ - return find_uac_clock_desc(iface, id, validator, type); \ + return NULL; } -DEFINE_FIND_HELPER(snd_usb_find_clock_source, - struct uac_clock_source_descriptor, - validate_clock_source_v2, UAC2_CLOCK_SOURCE); -DEFINE_FIND_HELPER(snd_usb_find_clock_source_v3, - struct uac3_clock_source_descriptor, - validate_clock_source_v3, UAC3_CLOCK_SOURCE); - -DEFINE_FIND_HELPER(snd_usb_find_clock_selector, - struct uac_clock_selector_descriptor, - validate_clock_selector_v2, UAC2_CLOCK_SELECTOR); -DEFINE_FIND_HELPER(snd_usb_find_clock_selector_v3, - struct uac3_clock_selector_descriptor, - validate_clock_selector_v3, UAC3_CLOCK_SELECTOR); - -DEFINE_FIND_HELPER(snd_usb_find_clock_multiplier, - struct uac_clock_multiplier_descriptor, - validate_clock_multiplier_v2, UAC2_CLOCK_MULTIPLIER); -DEFINE_FIND_HELPER(snd_usb_find_clock_multiplier_v3, - struct uac3_clock_multiplier_descriptor, - validate_clock_multiplier_v3, UAC3_CLOCK_MULTIPLIER); - static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_id) { unsigned char buf; @@ -167,34 +138,20 @@ static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_i return ret; } -static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, - int protocol, - int source_id) +static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id) { int err; unsigned char data; struct usb_device *dev = chip->dev; - u32 bmControls; - - if (protocol == UAC_VERSION_3) { - struct uac3_clock_source_descriptor *cs_desc = - snd_usb_find_clock_source_v3(chip->ctrl_intf, source_id); - - if (!cs_desc) - return 0; - bmControls = le32_to_cpu(cs_desc->bmControls); - } else { /* UAC_VERSION_1/2 */ - struct uac_clock_source_descriptor *cs_desc = - snd_usb_find_clock_source(chip->ctrl_intf, source_id); - - if (!cs_desc) - return 0; - bmControls = cs_desc->bmControls; - } + struct uac_clock_source_descriptor *cs_desc = + snd_usb_find_clock_source(chip->ctrl_intf, source_id); + + if (!cs_desc) + return 0; /* If a clock source can't tell us whether it's valid, we assume it is */ - if (!uac_v2v3_control_is_readable(bmControls, - UAC2_CS_CONTROL_CLOCK_VALID)) + if (!uac2_control_is_readable(cs_desc->bmControls, + UAC2_CS_CONTROL_CLOCK_VALID - 1)) return 1; err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, @@ -213,8 +170,9 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, return !!data; } -static int __uac_clock_find_source(struct snd_usb_audio *chip, int entity_id, - unsigned long *visited, bool validate) +static int __uac_clock_find_source(struct snd_usb_audio *chip, + int entity_id, unsigned long *visited, + bool validate) { struct uac_clock_source_descriptor *source; struct uac_clock_selector_descriptor *selector; @@ -233,8 +191,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, int entity_id, source = snd_usb_find_clock_source(chip->ctrl_intf, entity_id); if (source) { entity_id = source->bClockID; - if (validate && !uac_clock_source_is_valid(chip, UAC_VERSION_2, - entity_id)) { + if (validate && !uac_clock_source_is_valid(chip, entity_id)) { usb_audio_err(chip, "clock source %d is not valid, cannot use\n", entity_id); @@ -303,97 +260,6 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, int entity_id, return -EINVAL; } -static int __uac3_clock_find_source(struct snd_usb_audio *chip, int entity_id, - unsigned long *visited, bool validate) -{ - struct uac3_clock_source_descriptor *source; - struct uac3_clock_selector_descriptor *selector; - struct uac3_clock_multiplier_descriptor *multiplier; - - entity_id &= 0xff; - - if (test_and_set_bit(entity_id, visited)) { - usb_audio_warn(chip, - "%s(): recursive clock topology detected, id %d.\n", - __func__, entity_id); - return -EINVAL; - } - - /* first, see if the ID we're looking for is a clock source already */ - source = snd_usb_find_clock_source_v3(chip->ctrl_intf, entity_id); - if (source) { - entity_id = source->bClockID; - if (validate && !uac_clock_source_is_valid(chip, UAC_VERSION_3, - entity_id)) { - usb_audio_err(chip, - "clock source %d is not valid, cannot use\n", - entity_id); - return -ENXIO; - } - return entity_id; - } - - selector = snd_usb_find_clock_selector_v3(chip->ctrl_intf, entity_id); - if (selector) { - int ret, i, cur; - - /* the entity ID we are looking for is a selector. - * find out what it currently selects */ - ret = uac_clock_selector_get_val(chip, selector->bClockID); - if (ret < 0) - return ret; - - /* Selector values are one-based */ - - if (ret > selector->bNrInPins || ret < 1) { - usb_audio_err(chip, - "%s(): selector reported illegal value, id %d, ret %d\n", - __func__, selector->bClockID, ret); - - return -EINVAL; - } - - cur = ret; - ret = __uac3_clock_find_source(chip, selector->baCSourceID[ret - 1], - visited, validate); - if (!validate || ret > 0 || !chip->autoclock) - return ret; - - /* The current clock source is invalid, try others. */ - for (i = 1; i <= selector->bNrInPins; i++) { - int err; - - if (i == cur) - continue; - - ret = __uac3_clock_find_source(chip, selector->baCSourceID[i - 1], - visited, true); - if (ret < 0) - continue; - - err = uac_clock_selector_set_val(chip, entity_id, i); - if (err < 0) - continue; - - usb_audio_info(chip, - "found and selected valid clock source %d\n", - ret); - return ret; - } - - return -ENXIO; - } - - /* FIXME: multipliers only act as pass-thru element for now */ - multiplier = snd_usb_find_clock_multiplier_v3(chip->ctrl_intf, - entity_id); - if (multiplier) - return __uac3_clock_find_source(chip, multiplier->bCSourceID, - visited, validate); - - return -EINVAL; -} - /* * For all kinds of sample rate settings and other device queries, * the clock source (end-leaf) must be used. However, clock selectors, @@ -405,22 +271,12 @@ static int __uac3_clock_find_source(struct snd_usb_audio *chip, int entity_id, * * Returns the clock source UnitID (>=0) on success, or an error. */ -int snd_usb_clock_find_source(struct snd_usb_audio *chip, int protocol, - int entity_id, bool validate) +int snd_usb_clock_find_source(struct snd_usb_audio *chip, int entity_id, + bool validate) { DECLARE_BITMAP(visited, 256); memset(visited, 0, sizeof(visited)); - - switch (protocol) { - case UAC_VERSION_2: - return __uac_clock_find_source(chip, entity_id, visited, - validate); - case UAC_VERSION_3: - return __uac3_clock_find_source(chip, entity_id, visited, - validate); - default: - return -EINVAL; - } + return __uac_clock_find_source(chip, entity_id, visited, validate); } static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface, @@ -443,11 +299,10 @@ static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface, data[0] = rate; data[1] = rate >> 8; data[2] = rate >> 16; - err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, - USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT, - UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, - data, sizeof(data)); - if (err < 0) { + if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, + USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT, + UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, + data, sizeof(data))) < 0) { dev_err(&dev->dev, "%d:%d: cannot set freq %d to ep %#x\n", iface, fmt->altsetting, rate, ep); return err; @@ -461,11 +316,10 @@ static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface, if (chip->sample_rate_read_error > 2) return 0; - err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR, - USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN, - UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, - data, sizeof(data)); - if (err < 0) { + if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR, + USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN, + UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, + data, sizeof(data))) < 0) { dev_err(&dev->dev, "%d:%d: cannot get freq at ep %#x\n", iface, fmt->altsetting, ep); chip->sample_rate_read_error++; @@ -481,7 +335,7 @@ static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface, return 0; } -static int get_sample_rate_v2v3(struct snd_usb_audio *chip, int iface, +static int get_sample_rate_v2(struct snd_usb_audio *chip, int iface, int altsetting, int clock) { struct usb_device *dev = chip->dev; @@ -494,7 +348,7 @@ static int get_sample_rate_v2v3(struct snd_usb_audio *chip, int iface, snd_usb_ctrl_intf(chip) | (clock << 8), &data, sizeof(data)); if (err < 0) { - dev_warn(&dev->dev, "%d:%d: cannot get freq (v2/v3): err %d\n", + dev_warn(&dev->dev, "%d:%d: cannot get freq (v2): err %d\n", iface, altsetting, err); return 0; } @@ -502,7 +356,7 @@ static int get_sample_rate_v2v3(struct snd_usb_audio *chip, int iface, return le32_to_cpu(data); } -static int set_sample_rate_v2v3(struct snd_usb_audio *chip, int iface, +static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface, struct usb_host_interface *alts, struct audioformat *fmt, int rate) { @@ -511,45 +365,18 @@ static int set_sample_rate_v2v3(struct snd_usb_audio *chip, int iface, int err, cur_rate, prev_rate; int clock; bool writeable; - u32 bmControls; - - /* First, try to find a valid clock. This may trigger - * automatic clock selection if the current clock is not - * valid. - */ - clock = snd_usb_clock_find_source(chip, fmt->protocol, - fmt->clock, true); - if (clock < 0) { - /* We did not find a valid clock, but that might be - * because the current sample rate does not match an - * external clock source. Try again without validation - * and we will do another validation after setting the - * rate. - */ - clock = snd_usb_clock_find_source(chip, fmt->protocol, - fmt->clock, false); - if (clock < 0) - return clock; - } - - prev_rate = get_sample_rate_v2v3(chip, iface, fmt->altsetting, clock); - if (prev_rate == rate) - goto validation; + struct uac_clock_source_descriptor *cs_desc; - if (fmt->protocol == UAC_VERSION_3) { - struct uac3_clock_source_descriptor *cs_desc; + clock = snd_usb_clock_find_source(chip, fmt->clock, true); + if (clock < 0) + return clock; - cs_desc = snd_usb_find_clock_source_v3(chip->ctrl_intf, clock); - bmControls = le32_to_cpu(cs_desc->bmControls); - } else { - struct uac_clock_source_descriptor *cs_desc; - - cs_desc = snd_usb_find_clock_source(chip->ctrl_intf, clock); - bmControls = cs_desc->bmControls; - } + prev_rate = get_sample_rate_v2(chip, iface, fmt->altsetting, clock); + if (prev_rate == rate) + return 0; - writeable = uac_v2v3_control_is_writeable(bmControls, - UAC2_CS_CONTROL_SAM_FREQ); + cs_desc = snd_usb_find_clock_source(chip->ctrl_intf, clock); + writeable = uac2_control_is_writeable(cs_desc->bmControls, UAC2_CS_CONTROL_SAM_FREQ - 1); if (writeable) { data = cpu_to_le32(rate); err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR, @@ -559,13 +386,12 @@ static int set_sample_rate_v2v3(struct snd_usb_audio *chip, int iface, &data, sizeof(data)); if (err < 0) { usb_audio_err(chip, - "%d:%d: cannot set freq %d (v2/v3): err %d\n", + "%d:%d: cannot set freq %d (v2): err %d\n", iface, fmt->altsetting, rate, err); return err; } - cur_rate = get_sample_rate_v2v3(chip, iface, - fmt->altsetting, clock); + cur_rate = get_sample_rate_v2(chip, iface, fmt->altsetting, clock); } else { cur_rate = prev_rate; } @@ -591,10 +417,6 @@ static int set_sample_rate_v2v3(struct snd_usb_audio *chip, int iface, snd_usb_set_interface_quirk(dev); } -validation: - /* validate clock after rate change */ - if (!uac_clock_source_is_valid(chip, fmt->protocol, clock)) - return -ENXIO; return 0; } @@ -607,16 +429,8 @@ int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface, default: return set_sample_rate_v1(chip, iface, alts, fmt, rate); - case UAC_VERSION_3: - if (chip->badd_profile >= UAC3_FUNCTION_SUBCLASS_GENERIC_IO) { - if (rate != UAC3_BADD_SAMPLING_RATE) - return -ENXIO; - else - return 0; - } - /* fall through */ case UAC_VERSION_2: - return set_sample_rate_v2v3(chip, iface, alts, fmt, rate); + return set_sample_rate_v2(chip, iface, alts, fmt, rate); } } diff --git a/sound/usb/clock.h b/sound/usb/clock.h index e465ff58653b..d592e4a29856 100644 --- a/sound/usb/clock.h +++ b/sound/usb/clock.h @@ -5,7 +5,7 @@ int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface, struct usb_host_interface *alts, struct audioformat *fmt, int rate); -int snd_usb_clock_find_source(struct snd_usb_audio *chip, int protocol, - int entity_id, bool validate); +int snd_usb_clock_find_source(struct snd_usb_audio *chip, int entity_id, + bool validate); #endif /* __USBAUDIO_CLOCK_H */ diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index d86be8bfe412..c90607ebe155 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -325,6 +325,7 @@ static void queue_pending_output_urbs(struct snd_usb_endpoint *ep) unsigned long flags; struct snd_usb_packet_info *uninitialized_var(packet); struct snd_urb_ctx *ctx = NULL; + struct urb *urb; int err, i; spin_lock_irqsave(&ep->lock, flags); @@ -344,6 +345,7 @@ static void queue_pending_output_urbs(struct snd_usb_endpoint *ep) return; list_del_init(&ctx->ready_list); + urb = ctx->urb; /* copy over the length information */ for (i = 0; i < packet->packets; i++) diff --git a/sound/usb/format.c b/sound/usb/format.c index 0a2a27f2854d..916ff842c437 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c @@ -20,7 +20,6 @@ #include <linux/usb.h> #include <linux/usb/audio.h> #include <linux/usb/audio-v2.h> -#include <linux/usb/audio-v3.h> #include <sound/core.h> #include <sound/pcm.h> @@ -40,11 +39,11 @@ * @dev: usb device * @fp: audioformat record * @format: the format tag (wFormatTag) - * @fmt: the format type descriptor (v1/v2) or AudioStreaming descriptor (v3) + * @fmt: the format type descriptor */ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip, struct audioformat *fp, - u64 format, void *_fmt) + unsigned int format, void *_fmt) { int sample_width, sample_bytes; u64 pcm_formats = 0; @@ -55,7 +54,7 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip, struct uac_format_type_i_discrete_descriptor *fmt = _fmt; sample_width = fmt->bBitResolution; sample_bytes = fmt->bSubframeSize; - format = 1ULL << format; + format = 1 << format; break; } @@ -73,18 +72,6 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip, format <<= 1; break; } - case UAC_VERSION_3: { - struct uac3_as_header_descriptor *as = _fmt; - - sample_width = as->bBitResolution; - sample_bytes = as->bSubslotSize; - - if (format & UAC3_FORMAT_TYPE_I_RAW_DATA) - pcm_formats |= SNDRV_PCM_FMTBIT_SPECIAL; - - format <<= 1; - break; - } } if ((pcm_formats == 0) && @@ -153,7 +140,7 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip, } if (format & ~0x3f) { usb_audio_info(chip, - "%u:%d : unsupported format bits %#llx\n", + "%u:%d : unsupported format bits %#x\n", fp->iface, fp->altsetting, format); } @@ -297,16 +284,15 @@ static int parse_uac2_sample_rate_range(struct snd_usb_audio *chip, /* * parse the format descriptor and stores the possible sample rates - * on the audioformat table (audio class v2 and v3). + * on the audioformat table (audio class v2). */ -static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip, +static int parse_audio_format_rates_v2(struct snd_usb_audio *chip, struct audioformat *fp) { struct usb_device *dev = chip->dev; unsigned char tmp[2], *data; int nr_triplets, data_size, ret = 0; - int clock = snd_usb_clock_find_source(chip, fp->protocol, - fp->clock, false); + int clock = snd_usb_clock_find_source(chip, fp->clock, false); if (clock < 0) { dev_err(&dev->dev, @@ -385,30 +371,13 @@ err: * parse the format type I and III descriptors */ static int parse_audio_format_i(struct snd_usb_audio *chip, - struct audioformat *fp, u64 format, - void *_fmt) + struct audioformat *fp, unsigned int format, + struct uac_format_type_i_continuous_descriptor *fmt) { snd_pcm_format_t pcm_format; - unsigned int fmt_type; int ret; - switch (fp->protocol) { - default: - case UAC_VERSION_1: - case UAC_VERSION_2: { - struct uac_format_type_i_continuous_descriptor *fmt = _fmt; - - fmt_type = fmt->bFormatType; - break; - } - case UAC_VERSION_3: { - /* fp->fmt_type is already set in this case */ - fmt_type = fp->fmt_type; - break; - } - } - - if (fmt_type == UAC_FORMAT_TYPE_III) { + if (fmt->bFormatType == UAC_FORMAT_TYPE_III) { /* FIXME: the format type is really IECxxx * but we give normal PCM format to get the existing * apps working... @@ -427,7 +396,7 @@ static int parse_audio_format_i(struct snd_usb_audio *chip, } fp->formats = pcm_format_to_bits(pcm_format); } else { - fp->formats = parse_audio_format_i_type(chip, fp, format, _fmt); + fp->formats = parse_audio_format_i_type(chip, fp, format, fmt); if (!fp->formats) return -EINVAL; } @@ -439,20 +408,15 @@ static int parse_audio_format_i(struct snd_usb_audio *chip, */ switch (fp->protocol) { default: - case UAC_VERSION_1: { - struct uac_format_type_i_continuous_descriptor *fmt = _fmt; - + case UAC_VERSION_1: fp->channels = fmt->bNrChannels; ret = parse_audio_format_rates_v1(chip, fp, (unsigned char *) fmt, 7); break; - } case UAC_VERSION_2: - case UAC_VERSION_3: { /* fp->channels is already set in this case */ - ret = parse_audio_format_rates_v2v3(chip, fp); + ret = parse_audio_format_rates_v2(chip, fp); break; } - } if (fp->channels < 1) { usb_audio_err(chip, @@ -469,7 +433,7 @@ static int parse_audio_format_i(struct snd_usb_audio *chip, */ static int parse_audio_format_ii(struct snd_usb_audio *chip, struct audioformat *fp, - u64 format, void *_fmt) + int format, void *_fmt) { int brate, framesize, ret; @@ -484,7 +448,7 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip, break; default: usb_audio_info(chip, - "%u:%d : unknown format tag %#llx is detected. processed as MPEG.\n", + "%u:%d : unknown format tag %#x is detected. processed as MPEG.\n", fp->iface, fp->altsetting, format); fp->formats = SNDRV_PCM_FMTBIT_MPEG; break; @@ -509,7 +473,7 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip, framesize = le16_to_cpu(fmt->wSamplesPerFrame); usb_audio_info(chip, "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize); fp->frame_size = framesize; - ret = parse_audio_format_rates_v2v3(chip, fp); + ret = parse_audio_format_rates_v2(chip, fp); break; } } @@ -518,7 +482,7 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip, } int snd_usb_parse_audio_format(struct snd_usb_audio *chip, - struct audioformat *fp, u64 format, + struct audioformat *fp, unsigned int format, struct uac_format_type_i_continuous_descriptor *fmt, int stream) { @@ -559,26 +523,3 @@ int snd_usb_parse_audio_format(struct snd_usb_audio *chip, return 0; } -int snd_usb_parse_audio_format_v3(struct snd_usb_audio *chip, - struct audioformat *fp, - struct uac3_as_header_descriptor *as, - int stream) -{ - u64 format = le64_to_cpu(as->bmFormats); - int err; - - /* - * Type I format bits are D0..D6 - * This test works because type IV is not supported - */ - if (format & 0x7f) - fp->fmt_type = UAC_FORMAT_TYPE_I; - else - fp->fmt_type = UAC_FORMAT_TYPE_III; - - err = parse_audio_format_i(chip, fp, format, as); - if (err < 0) - return err; - - return 0; -} diff --git a/sound/usb/format.h b/sound/usb/format.h index 46c9de714f83..4b8a01129f24 100644 --- a/sound/usb/format.h +++ b/sound/usb/format.h @@ -2,12 +2,8 @@ #define __USBAUDIO_FORMAT_H int snd_usb_parse_audio_format(struct snd_usb_audio *chip, - struct audioformat *fp, u64 format, + struct audioformat *fp, unsigned int format, struct uac_format_type_i_continuous_descriptor *fmt, int stream); -int snd_usb_parse_audio_format_v3(struct snd_usb_audio *chip, - struct audioformat *fp, - struct uac3_as_header_descriptor *as, - int stream); #endif /* __USBAUDIO_FORMAT_H */ diff --git a/sound/usb/helper.h b/sound/usb/helper.h index 693f247de197..805c300dd004 100644 --- a/sound/usb/helper.h +++ b/sound/usb/helper.h @@ -17,12 +17,16 @@ unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip, * retrieve usb_interface descriptor from the host interface * (conditional for compatibility with the older API) */ +#ifndef get_iface_desc #define get_iface_desc(iface) (&(iface)->desc) #define get_endpoint(alt,ep) (&(alt)->endpoint[ep].desc) #define get_ep_desc(ep) (&(ep)->desc) #define get_cfg_desc(cfg) (&(cfg)->desc) +#endif +#ifndef snd_usb_get_speed #define snd_usb_get_speed(dev) ((dev)->speed) +#endif static inline int snd_usb_ctrl_intf(struct snd_usb_audio *chip) { diff --git a/sound/usb/line6/capture.c b/sound/usb/line6/capture.c index 947d6168f24a..7c812565f90d 100644 --- a/sound/usb/line6/capture.c +++ b/sound/usb/line6/capture.c @@ -248,7 +248,7 @@ static int snd_line6_capture_close(struct snd_pcm_substream *substream) } /* capture operators */ -const struct snd_pcm_ops snd_line6_capture_ops = { +struct snd_pcm_ops snd_line6_capture_ops = { .open = snd_line6_capture_open, .close = snd_line6_capture_close, .ioctl = snd_pcm_lib_ioctl, diff --git a/sound/usb/line6/capture.h b/sound/usb/line6/capture.h index b67ccc39fd25..890b21bff18c 100644 --- a/sound/usb/line6/capture.h +++ b/sound/usb/line6/capture.h @@ -17,7 +17,7 @@ #include "driver.h" #include "pcm.h" -extern const struct snd_pcm_ops snd_line6_capture_ops; +extern struct snd_pcm_ops snd_line6_capture_ops; extern void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize); diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c index 4f9613e5fc9e..8d5a454842f4 100644 --- a/sound/usb/line6/driver.c +++ b/sound/usb/line6/driver.c @@ -199,9 +199,9 @@ static int line6_send_raw_message_async_part(struct message *msg, Setup and start timer. */ void line6_start_timer(struct timer_list *timer, unsigned long msecs, - void (*function)(struct timer_list *t)) + void (*function)(unsigned long), unsigned long data) { - timer->function = (TIMER_FUNC_TYPE)function; + setup_timer(timer, function, data); mod_timer(timer, jiffies + msecs_to_jiffies(msecs)); } EXPORT_SYMBOL_GPL(line6_start_timer); diff --git a/sound/usb/line6/driver.h b/sound/usb/line6/driver.h index 61425597eb61..dc97895547be 100644 --- a/sound/usb/line6/driver.h +++ b/sound/usb/line6/driver.h @@ -198,7 +198,8 @@ extern int line6_send_sysex_message(struct usb_line6 *line6, extern ssize_t line6_set_raw(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); extern void line6_start_timer(struct timer_list *timer, unsigned long msecs, - void (*function)(struct timer_list *t)); + void (*function)(unsigned long), + unsigned long data); extern int line6_version_request_async(struct usb_line6 *line6); extern int line6_write_data(struct usb_line6 *line6, unsigned address, void *data, unsigned datalen); diff --git a/sound/usb/line6/playback.c b/sound/usb/line6/playback.c index 819e9b2d1d6e..812d18191e01 100644 --- a/sound/usb/line6/playback.c +++ b/sound/usb/line6/playback.c @@ -393,7 +393,7 @@ static int snd_line6_playback_close(struct snd_pcm_substream *substream) } /* playback operators */ -const struct snd_pcm_ops snd_line6_playback_ops = { +struct snd_pcm_ops snd_line6_playback_ops = { .open = snd_line6_playback_open, .close = snd_line6_playback_close, .ioctl = snd_pcm_lib_ioctl, diff --git a/sound/usb/line6/playback.h b/sound/usb/line6/playback.h index d8d3b8a07a72..51fce29e8726 100644 --- a/sound/usb/line6/playback.h +++ b/sound/usb/line6/playback.h @@ -27,7 +27,7 @@ */ #define USE_CLEAR_BUFFER_WORKAROUND 1 -extern const struct snd_pcm_ops snd_line6_playback_ops; +extern struct snd_pcm_ops snd_line6_playback_ops; extern int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm); extern int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm); diff --git a/sound/usb/line6/pod.c b/sound/usb/line6/pod.c index 020c81818951..358224cc5638 100644 --- a/sound/usb/line6/pod.c +++ b/sound/usb/line6/pod.c @@ -174,7 +174,7 @@ static const char pod_version_header[] = { }; /* forward declarations: */ -static void pod_startup2(struct timer_list *t); +static void pod_startup2(unsigned long data); static void pod_startup3(struct usb_line6_pod *pod); static char *pod_alloc_sysex_buffer(struct usb_line6_pod *pod, int code, @@ -286,12 +286,13 @@ static void pod_startup1(struct usb_line6_pod *pod) CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_INIT); /* delay startup procedure: */ - line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2); + line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2, + (unsigned long)pod); } -static void pod_startup2(struct timer_list *t) +static void pod_startup2(unsigned long data) { - struct usb_line6_pod *pod = from_timer(pod, t, startup_timer); + struct usb_line6_pod *pod = (struct usb_line6_pod *)data; struct usb_line6 *line6 = &pod->line6; CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_VERSIONREQ); @@ -412,7 +413,7 @@ static int pod_init(struct usb_line6 *line6, line6->process_message = line6_pod_process_message; line6->disconnect = line6_pod_disconnect; - timer_setup(&pod->startup_timer, NULL, 0); + init_timer(&pod->startup_timer); INIT_WORK(&pod->startup_work, pod_startup4); /* create sysfs entries: */ diff --git a/sound/usb/line6/podhd.c b/sound/usb/line6/podhd.c index 36ed9c85c0eb..46fa8c046cb5 100644 --- a/sound/usb/line6/podhd.c +++ b/sound/usb/line6/podhd.c @@ -158,7 +158,7 @@ static struct line6_pcm_properties podx3_pcm_properties = { }; static struct usb_driver podhd_driver; -static void podhd_startup_start_workqueue(struct timer_list *t); +static void podhd_startup_start_workqueue(unsigned long data); static void podhd_startup_workqueue(struct work_struct *work); static int podhd_startup_finalize(struct usb_line6_podhd *pod); @@ -208,12 +208,12 @@ static void podhd_startup(struct usb_line6_podhd *pod) /* delay startup procedure: */ line6_start_timer(&pod->startup_timer, PODHD_STARTUP_DELAY, - podhd_startup_start_workqueue); + podhd_startup_start_workqueue, (unsigned long)pod); } -static void podhd_startup_start_workqueue(struct timer_list *t) +static void podhd_startup_start_workqueue(unsigned long data) { - struct usb_line6_podhd *pod = from_timer(pod, t, startup_timer); + struct usb_line6_podhd *pod = (struct usb_line6_podhd *)data; CHECK_STARTUP_PROGRESS(pod->startup_progress, PODHD_STARTUP_SCHEDULE_WORKQUEUE); @@ -319,7 +319,7 @@ static int podhd_init(struct usb_line6 *line6, line6->disconnect = podhd_disconnect; - timer_setup(&pod->startup_timer, NULL, 0); + init_timer(&pod->startup_timer); INIT_WORK(&pod->startup_work, podhd_startup_workqueue); if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL) { diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c index f47ba94e6f4a..ba7975c0d03d 100644 --- a/sound/usb/line6/toneport.c +++ b/sound/usb/line6/toneport.c @@ -241,9 +241,9 @@ static int snd_toneport_source_put(struct snd_kcontrol *kcontrol, return 1; } -static void toneport_start_pcm(struct timer_list *t) +static void toneport_start_pcm(unsigned long arg) { - struct usb_line6_toneport *toneport = from_timer(toneport, t, timer); + struct usb_line6_toneport *toneport = (struct usb_line6_toneport *)arg; struct usb_line6 *line6 = &toneport->line6; line6_pcm_acquire(line6->line6pcm, LINE6_STREAM_MONITOR, true); @@ -367,13 +367,12 @@ static bool toneport_has_source_select(struct usb_line6_toneport *toneport) */ static void toneport_setup(struct usb_line6_toneport *toneport) { - u32 ticks; + int ticks; struct usb_line6 *line6 = &toneport->line6; struct usb_device *usbdev = line6->usbdev; /* sync time on device with host: */ - /* note: 32-bit timestamps overflow in year 2106 */ - ticks = (u32)ktime_get_real_seconds(); + ticks = (int)get_seconds(); line6_write_data(line6, 0x80c6, &ticks, 4); /* enable device: */ @@ -416,7 +415,8 @@ static int toneport_init(struct usb_line6 *line6, struct usb_line6_toneport *toneport = (struct usb_line6_toneport *) line6; toneport->type = id->driver_info; - timer_setup(&toneport->timer, toneport_start_pcm, 0); + setup_timer(&toneport->timer, toneport_start_pcm, + (unsigned long)toneport); line6->disconnect = line6_toneport_disconnect; diff --git a/sound/usb/line6/variax.c b/sound/usb/line6/variax.c index e8c852b2ce35..0c4512d0382e 100644 --- a/sound/usb/line6/variax.c +++ b/sound/usb/line6/variax.c @@ -82,9 +82,9 @@ static const char variax_activate[] = { }; /* forward declarations: */ -static void variax_startup2(struct timer_list *t); -static void variax_startup4(struct timer_list *t); -static void variax_startup5(struct timer_list *t); +static void variax_startup2(unsigned long data); +static void variax_startup4(unsigned long data); +static void variax_startup5(unsigned long data); static void variax_activate_async(struct usb_line6_variax *variax, int a) { @@ -106,12 +106,12 @@ static void variax_startup1(struct usb_line6_variax *variax) /* delay startup procedure: */ line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1, - variax_startup2); + variax_startup2, (unsigned long)variax); } -static void variax_startup2(struct timer_list *t) +static void variax_startup2(unsigned long data) { - struct usb_line6_variax *variax = from_timer(variax, t, startup_timer1); + struct usb_line6_variax *variax = (struct usb_line6_variax *)data; struct usb_line6 *line6 = &variax->line6; /* schedule another startup procedure until startup is complete: */ @@ -120,7 +120,7 @@ static void variax_startup2(struct timer_list *t) variax->startup_progress = VARIAX_STARTUP_VERSIONREQ; line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1, - variax_startup2); + variax_startup2, (unsigned long)variax); /* request firmware version: */ line6_version_request_async(line6); @@ -132,12 +132,12 @@ static void variax_startup3(struct usb_line6_variax *variax) /* delay startup procedure: */ line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY3, - variax_startup4); + variax_startup4, (unsigned long)variax); } -static void variax_startup4(struct timer_list *t) +static void variax_startup4(unsigned long data) { - struct usb_line6_variax *variax = from_timer(variax, t, startup_timer2); + struct usb_line6_variax *variax = (struct usb_line6_variax *)data; CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_ACTIVATE); @@ -145,12 +145,12 @@ static void variax_startup4(struct timer_list *t) /* activate device: */ variax_activate_async(variax, 1); line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY4, - variax_startup5); + variax_startup5, (unsigned long)variax); } -static void variax_startup5(struct timer_list *t) +static void variax_startup5(unsigned long data) { - struct usb_line6_variax *variax = from_timer(variax, t, startup_timer2); + struct usb_line6_variax *variax = (struct usb_line6_variax *)data; CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_WORKQUEUE); @@ -190,7 +190,7 @@ static void line6_variax_process_message(struct usb_line6 *line6) } else if (memcmp(buf + 1, variax_init_done + 1, sizeof(variax_init_done) - 1) == 0) { /* notify of complete initialization: */ - variax_startup4(&variax->startup_timer2); + variax_startup4((unsigned long)variax); } break; } @@ -222,8 +222,8 @@ static int variax_init(struct usb_line6 *line6, line6->process_message = line6_variax_process_message; line6->disconnect = line6_variax_disconnect; - timer_setup(&variax->startup_timer1, NULL, 0); - timer_setup(&variax->startup_timer2, NULL, 0); + init_timer(&variax->startup_timer1); + init_timer(&variax->startup_timer2); INIT_WORK(&variax->startup_work, variax_startup6); /* initialize USB buffers: */ diff --git a/sound/usb/midi.c b/sound/usb/midi.c index c62ae8c7393e..66c36c100177 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -281,16 +281,15 @@ static void snd_usbmidi_out_urb_complete(struct urb *urb) struct out_urb_context *context = urb->context; struct snd_usb_midi_out_endpoint *ep = context->ep; unsigned int urb_index; - unsigned long flags; - spin_lock_irqsave(&ep->buffer_lock, flags); + spin_lock(&ep->buffer_lock); urb_index = context - ep->urbs; ep->active_urbs &= ~(1 << urb_index); if (unlikely(ep->drain_urbs)) { ep->drain_urbs &= ~(1 << urb_index); wake_up(&ep->drain_wait); } - spin_unlock_irqrestore(&ep->buffer_lock, flags); + spin_unlock(&ep->buffer_lock); if (urb->status < 0) { int err = snd_usbmidi_urb_error(urb); if (err < 0) { @@ -353,9 +352,9 @@ static void snd_usbmidi_out_tasklet(unsigned long data) } /* called after transfers had been interrupted due to some USB error */ -static void snd_usbmidi_error_timer(struct timer_list *t) +static void snd_usbmidi_error_timer(unsigned long data) { - struct snd_usb_midi *umidi = from_timer(umidi, t, error_timer); + struct snd_usb_midi *umidi = (struct snd_usb_midi *)data; unsigned int i, j; spin_lock(&umidi->disc_lock); @@ -1175,7 +1174,8 @@ static void snd_usbmidi_output_trigger(struct snd_rawmidi_substream *substream, if (port->ep->umidi->disconnected) { /* gobble up remaining bytes to prevent wait in * snd_rawmidi_drain_output */ - snd_rawmidi_proceed(substream); + while (!snd_rawmidi_transmit_empty(substream)) + snd_rawmidi_transmit_ack(substream, 1); return; } tasklet_schedule(&port->ep->tasklet); @@ -2369,7 +2369,8 @@ int __snd_usbmidi_create(struct snd_card *card, usb_id = USB_ID(le16_to_cpu(umidi->dev->descriptor.idVendor), le16_to_cpu(umidi->dev->descriptor.idProduct)); umidi->usb_id = usb_id; - timer_setup(&umidi->error_timer, snd_usbmidi_error_timer, 0); + setup_timer(&umidi->error_timer, snd_usbmidi_error_timer, + (unsigned long)umidi); /* detect the endpoint(s) to use */ memset(endpoints, 0, sizeof(endpoints)); diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c index b05cd38400ff..c19a5dd05631 100644 --- a/sound/usb/misc/ua101.c +++ b/sound/usb/misc/ua101.c @@ -1366,7 +1366,7 @@ static void ua101_disconnect(struct usb_interface *interface) mutex_unlock(&devices_mutex); } -static const struct usb_device_id ua101_ids[] = { +static struct usb_device_id ua101_ids[] = { { USB_DEVICE(0x0582, 0x0044) }, /* UA-1000 high speed */ { USB_DEVICE(0x0582, 0x007d) }, /* UA-101 high speed */ { USB_DEVICE(0x0582, 0x008d) }, /* UA-101 full speed */ diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index c3712af100f0..20c008191eeb 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -51,7 +51,6 @@ #include <linux/usb.h> #include <linux/usb/audio.h> #include <linux/usb/audio-v2.h> -#include <linux/usb/audio-v3.h> #include <sound/core.h> #include <sound/control.h> @@ -112,12 +111,14 @@ enum { #include "mixer_maps.c" static const struct usbmix_name_map * -find_map(const struct usbmix_name_map *p, int unitid, int control) +find_map(struct mixer_build *state, int unitid, int control) { + const struct usbmix_name_map *p = state->map; + if (!p) return NULL; - for (; p->id; p++) { + for (p = state->map; p->id; p++) { if (p->id == unitid && (!control || !p->control || control == p->control)) return p; @@ -188,7 +189,7 @@ static void *find_audio_control_unit(struct mixer_build *state, USB_DT_CS_INTERFACE)) != NULL) { if (hdr->bLength >= 4 && hdr->bDescriptorSubtype >= UAC_INPUT_TERMINAL && - hdr->bDescriptorSubtype <= UAC3_SAMPLE_RATE_CONVERTER && + hdr->bDescriptorSubtype <= UAC2_SAMPLE_RATE_CONVERTER && hdr->bUnitID == unit) return hdr; } @@ -199,10 +200,10 @@ static void *find_audio_control_unit(struct mixer_build *state, /* * copy a string with the given id */ -static int snd_usb_copy_string_desc(struct snd_usb_audio *chip, +static int snd_usb_copy_string_desc(struct mixer_build *state, int index, char *buf, int maxlen) { - int len = usb_string(chip->dev, index, buf, maxlen - 1); + int len = usb_string(state->chip->dev, index, buf, maxlen - 1); if (len < 0) return 0; @@ -464,10 +465,9 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, validx += cval->idx_off; - if (cval->head.mixer->protocol == UAC_VERSION_1) { val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1; - } else { /* UAC_VERSION_2/3 */ + } else { /* UAC_VERSION_2 */ val_len = uac2_ctl_value_size(cval->val_type); /* FIXME */ @@ -592,8 +592,7 @@ int snd_usb_mixer_add_control(struct usb_mixer_elem_list *list, while (snd_ctl_find_id(mixer->chip->card, &kctl->id)) kctl->id.index++; - err = snd_ctl_add(mixer->chip->card, kctl); - if (err < 0) { + if ((err = snd_ctl_add(mixer->chip->card, kctl)) < 0) { usb_audio_dbg(mixer->chip, "cannot add control (err = %d)\n", err); return err; @@ -651,34 +650,30 @@ static struct iterm_name_combo { { 0 }, }; -static int get_term_name(struct snd_usb_audio *chip, struct usb_audio_term *iterm, +static int get_term_name(struct mixer_build *state, struct usb_audio_term *iterm, unsigned char *name, int maxlen, int term_only) { struct iterm_name_combo *names; - int len; - if (iterm->name) { - len = snd_usb_copy_string_desc(chip, iterm->name, + if (iterm->name) + return snd_usb_copy_string_desc(state, iterm->name, name, maxlen); - if (len) - return len; - } /* virtual type - not a real terminal */ if (iterm->type >> 16) { if (term_only) return 0; switch (iterm->type >> 16) { - case UAC3_SELECTOR_UNIT: + case UAC_SELECTOR_UNIT: strcpy(name, "Selector"); return 8; - case UAC3_PROCESSING_UNIT: + case UAC1_PROCESSING_UNIT: strcpy(name, "Process Unit"); return 12; - case UAC3_EXTENSION_UNIT: + case UAC1_EXTENSION_UNIT: strcpy(name, "Ext Unit"); return 8; - case UAC3_MIXER_UNIT: + case UAC_MIXER_UNIT: strcpy(name, "Mixer"); return 5; default: @@ -712,73 +707,12 @@ static int get_term_name(struct snd_usb_audio *chip, struct usb_audio_term *iter } /* - * Get logical cluster information for UAC3 devices. - */ -static int get_cluster_channels_v3(struct mixer_build *state, unsigned int cluster_id) -{ - struct uac3_cluster_header_descriptor c_header; - int err; - - err = snd_usb_ctl_msg(state->chip->dev, - usb_rcvctrlpipe(state->chip->dev, 0), - UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR, - USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - cluster_id, - snd_usb_ctrl_intf(state->chip), - &c_header, sizeof(c_header)); - if (err < 0) - goto error; - if (err != sizeof(c_header)) { - err = -EIO; - goto error; - } - - return c_header.bNrChannels; - -error: - usb_audio_err(state->chip, "cannot request logical cluster ID: %d (err: %d)\n", cluster_id, err); - return err; -} - -/* - * Get number of channels for a Mixer Unit. - */ -static int uac_mixer_unit_get_channels(struct mixer_build *state, - struct uac_mixer_unit_descriptor *desc) -{ - int mu_channels; - - if (desc->bLength < 11) - return -EINVAL; - if (!desc->bNrInPins) - return -EINVAL; - - switch (state->mixer->protocol) { - case UAC_VERSION_1: - case UAC_VERSION_2: - default: - mu_channels = uac_mixer_unit_bNrChannels(desc); - break; - case UAC_VERSION_3: - mu_channels = get_cluster_channels_v3(state, - uac3_mixer_unit_wClusterDescrID(desc)); - break; - } - - if (!mu_channels) - return -EINVAL; - - return mu_channels; -} - -/* * parse the source unit recursively until it reaches to a terminal * or a branched unit. */ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_term *term) { - int protocol = state->mixer->protocol; int err; void *p1; @@ -786,116 +720,16 @@ static int check_input_term(struct mixer_build *state, int id, while ((p1 = find_audio_control_unit(state, id)) != NULL) { unsigned char *hdr = p1; term->id = id; - - if (protocol == UAC_VERSION_1 || protocol == UAC_VERSION_2) { - switch (hdr[2]) { - case UAC_INPUT_TERMINAL: - if (protocol == UAC_VERSION_1) { - struct uac_input_terminal_descriptor *d = p1; - - term->type = le16_to_cpu(d->wTerminalType); - term->channels = d->bNrChannels; - term->chconfig = le16_to_cpu(d->wChannelConfig); - term->name = d->iTerminal; - } else { /* UAC_VERSION_2 */ - struct uac2_input_terminal_descriptor *d = p1; - - /* call recursively to verify that the - * referenced clock entity is valid */ - err = check_input_term(state, d->bCSourceID, term); - if (err < 0) - return err; - - /* save input term properties after recursion, - * to ensure they are not overriden by the - * recursion calls */ - term->id = id; - term->type = le16_to_cpu(d->wTerminalType); - term->channels = d->bNrChannels; - term->chconfig = le32_to_cpu(d->bmChannelConfig); - term->name = d->iTerminal; - } - return 0; - case UAC_FEATURE_UNIT: { - /* the header is the same for v1 and v2 */ - struct uac_feature_unit_descriptor *d = p1; - - id = d->bSourceID; - break; /* continue to parse */ - } - case UAC_MIXER_UNIT: { - struct uac_mixer_unit_descriptor *d = p1; - - term->type = UAC3_MIXER_UNIT << 16; /* virtual type */ - term->channels = uac_mixer_unit_bNrChannels(d); - term->chconfig = uac_mixer_unit_wChannelConfig(d, protocol); - term->name = uac_mixer_unit_iMixer(d); - return 0; - } - case UAC_SELECTOR_UNIT: - case UAC2_CLOCK_SELECTOR: { - struct uac_selector_unit_descriptor *d = p1; - /* call recursively to retrieve the channel info */ - err = check_input_term(state, d->baSourceID[0], term); - if (err < 0) - return err; - term->type = UAC3_SELECTOR_UNIT << 16; /* virtual type */ - term->id = id; - term->name = uac_selector_unit_iSelector(d); - return 0; - } - case UAC1_PROCESSING_UNIT: - /* UAC2_EFFECT_UNIT */ - if (protocol == UAC_VERSION_1) - term->type = UAC3_PROCESSING_UNIT << 16; /* virtual type */ - else /* UAC_VERSION_2 */ - term->type = UAC3_EFFECT_UNIT << 16; /* virtual type */ - /* fall through */ - case UAC1_EXTENSION_UNIT: - /* UAC2_PROCESSING_UNIT_V2 */ - if (protocol == UAC_VERSION_1 && !term->type) - term->type = UAC3_EXTENSION_UNIT << 16; /* virtual type */ - else if (protocol == UAC_VERSION_2 && !term->type) - term->type = UAC3_PROCESSING_UNIT << 16; /* virtual type */ - /* fall through */ - case UAC2_EXTENSION_UNIT_V2: { - struct uac_processing_unit_descriptor *d = p1; - - if (protocol == UAC_VERSION_2 && - hdr[2] == UAC2_EFFECT_UNIT) { - /* UAC2/UAC1 unit IDs overlap here in an - * uncompatible way. Ignore this unit for now. - */ - return 0; - } - - if (d->bNrInPins) { - id = d->baSourceID[0]; - break; /* continue to parse */ - } - if (!term->type) - term->type = UAC3_EXTENSION_UNIT << 16; /* virtual type */ - - term->channels = uac_processing_unit_bNrChannels(d); - term->chconfig = uac_processing_unit_wChannelConfig(d, protocol); - term->name = uac_processing_unit_iProcessing(d, protocol); - return 0; - } - case UAC2_CLOCK_SOURCE: { - struct uac_clock_source_descriptor *d = p1; - - term->type = UAC3_CLOCK_SOURCE << 16; /* virtual type */ - term->id = id; - term->name = d->iClockSource; - return 0; - } - default: - return -ENODEV; - } - } else { /* UAC_VERSION_3 */ - switch (hdr[2]) { - case UAC_INPUT_TERMINAL: { - struct uac3_input_terminal_descriptor *d = p1; + switch (hdr[2]) { + case UAC_INPUT_TERMINAL: + if (state->mixer->protocol == UAC_VERSION_1) { + struct uac_input_terminal_descriptor *d = p1; + term->type = le16_to_cpu(d->wTerminalType); + term->channels = d->bNrChannels; + term->chconfig = le16_to_cpu(d->wChannelConfig); + term->name = d->iTerminal; + } else { /* UAC_VERSION_2 */ + struct uac2_input_terminal_descriptor *d = p1; /* call recursively to verify that the * referenced clock entity is valid */ @@ -908,77 +742,71 @@ static int check_input_term(struct mixer_build *state, int id, * recursion calls */ term->id = id; term->type = le16_to_cpu(d->wTerminalType); - - err = get_cluster_channels_v3(state, le16_to_cpu(d->wClusterDescrID)); - if (err < 0) - return err; - term->channels = err; - - /* REVISIT: UAC3 IT doesn't have channels cfg */ - term->chconfig = 0; - - term->name = le16_to_cpu(d->wTerminalDescrStr); - return 0; - } - case UAC3_FEATURE_UNIT: { - struct uac3_feature_unit_descriptor *d = p1; - - id = d->bSourceID; - break; /* continue to parse */ + term->channels = d->bNrChannels; + term->chconfig = le32_to_cpu(d->bmChannelConfig); + term->name = d->iTerminal; } - case UAC3_CLOCK_SOURCE: { - struct uac3_clock_source_descriptor *d = p1; - - term->type = UAC3_CLOCK_SOURCE << 16; /* virtual type */ - term->id = id; - term->name = le16_to_cpu(d->wClockSourceStr); - return 0; - } - case UAC3_MIXER_UNIT: { - struct uac_mixer_unit_descriptor *d = p1; - - err = uac_mixer_unit_get_channels(state, d); - if (err < 0) - return err; - - term->channels = err; - term->type = UAC3_MIXER_UNIT << 16; /* virtual type */ - - return 0; - } - case UAC3_SELECTOR_UNIT: - case UAC3_CLOCK_SELECTOR: { - struct uac_selector_unit_descriptor *d = p1; - /* call recursively to retrieve the channel info */ - err = check_input_term(state, d->baSourceID[0], term); - if (err < 0) - return err; - term->type = UAC3_SELECTOR_UNIT << 16; /* virtual type */ - term->id = id; - term->name = 0; /* TODO: UAC3 Class-specific strings */ - + return 0; + case UAC_FEATURE_UNIT: { + /* the header is the same for v1 and v2 */ + struct uac_feature_unit_descriptor *d = p1; + id = d->bSourceID; + break; /* continue to parse */ + } + case UAC_MIXER_UNIT: { + struct uac_mixer_unit_descriptor *d = p1; + term->type = d->bDescriptorSubtype << 16; /* virtual type */ + term->channels = uac_mixer_unit_bNrChannels(d); + term->chconfig = uac_mixer_unit_wChannelConfig(d, state->mixer->protocol); + term->name = uac_mixer_unit_iMixer(d); + return 0; + } + case UAC_SELECTOR_UNIT: + case UAC2_CLOCK_SELECTOR: { + struct uac_selector_unit_descriptor *d = p1; + /* call recursively to retrieve the channel info */ + err = check_input_term(state, d->baSourceID[0], term); + if (err < 0) + return err; + term->type = d->bDescriptorSubtype << 16; /* virtual type */ + term->id = id; + term->name = uac_selector_unit_iSelector(d); + return 0; + } + case UAC1_PROCESSING_UNIT: + case UAC1_EXTENSION_UNIT: + /* UAC2_PROCESSING_UNIT_V2 */ + /* UAC2_EFFECT_UNIT */ + case UAC2_EXTENSION_UNIT_V2: { + struct uac_processing_unit_descriptor *d = p1; + + if (state->mixer->protocol == UAC_VERSION_2 && + hdr[2] == UAC2_EFFECT_UNIT) { + /* UAC2/UAC1 unit IDs overlap here in an + * uncompatible way. Ignore this unit for now. + */ return 0; } - case UAC3_PROCESSING_UNIT: { - struct uac_processing_unit_descriptor *d = p1; - - if (!d->bNrInPins) - return -EINVAL; - - /* call recursively to retrieve the channel info */ - err = check_input_term(state, d->baSourceID[0], term); - if (err < 0) - return err; - term->type = UAC3_PROCESSING_UNIT << 16; /* virtual type */ - term->id = id; - term->name = 0; /* TODO: UAC3 Class-specific strings */ - - return 0; - } - default: - return -ENODEV; + if (d->bNrInPins) { + id = d->baSourceID[0]; + break; /* continue to parse */ } + term->type = d->bDescriptorSubtype << 16; /* virtual type */ + term->channels = uac_processing_unit_bNrChannels(d); + term->chconfig = uac_processing_unit_wChannelConfig(d, state->mixer->protocol); + term->name = uac_processing_unit_iProcessing(d, state->mixer->protocol); + return 0; + } + case UAC2_CLOCK_SOURCE: { + struct uac_clock_source_descriptor *d = p1; + term->type = d->bDescriptorSubtype << 16; /* virtual type */ + term->id = id; + term->name = d->iClockSource; + return 0; + } + default: + return -ENODEV; } } return -ENODEV; @@ -990,27 +818,26 @@ static int check_input_term(struct mixer_build *state, int id, /* feature unit control information */ struct usb_feature_control_info { - int control; const char *name; int type; /* data type for uac1 */ int type_uac2; /* data type for uac2 if different from uac1, else -1 */ }; static struct usb_feature_control_info audio_feature_info[] = { - { UAC_FU_MUTE, "Mute", USB_MIXER_INV_BOOLEAN, -1 }, - { UAC_FU_VOLUME, "Volume", USB_MIXER_S16, -1 }, - { UAC_FU_BASS, "Tone Control - Bass", USB_MIXER_S8, -1 }, - { UAC_FU_MID, "Tone Control - Mid", USB_MIXER_S8, -1 }, - { UAC_FU_TREBLE, "Tone Control - Treble", USB_MIXER_S8, -1 }, - { UAC_FU_GRAPHIC_EQUALIZER, "Graphic Equalizer", USB_MIXER_S8, -1 }, /* FIXME: not implemented yet */ - { UAC_FU_AUTOMATIC_GAIN, "Auto Gain Control", USB_MIXER_BOOLEAN, -1 }, - { UAC_FU_DELAY, "Delay Control", USB_MIXER_U16, USB_MIXER_U32 }, - { UAC_FU_BASS_BOOST, "Bass Boost", USB_MIXER_BOOLEAN, -1 }, - { UAC_FU_LOUDNESS, "Loudness", USB_MIXER_BOOLEAN, -1 }, + { "Mute", USB_MIXER_INV_BOOLEAN, -1 }, + { "Volume", USB_MIXER_S16, -1 }, + { "Tone Control - Bass", USB_MIXER_S8, -1 }, + { "Tone Control - Mid", USB_MIXER_S8, -1 }, + { "Tone Control - Treble", USB_MIXER_S8, -1 }, + { "Graphic Equalizer", USB_MIXER_S8, -1 }, /* FIXME: not implemeted yet */ + { "Auto Gain Control", USB_MIXER_BOOLEAN, -1 }, + { "Delay Control", USB_MIXER_U16, USB_MIXER_U32 }, + { "Bass Boost", USB_MIXER_BOOLEAN, -1 }, + { "Loudness", USB_MIXER_BOOLEAN, -1 }, /* UAC2 specific */ - { UAC2_FU_INPUT_GAIN, "Input Gain Control", USB_MIXER_S16, -1 }, - { UAC2_FU_INPUT_GAIN_PAD, "Input Gain Pad Control", USB_MIXER_S16, -1 }, - { UAC2_FU_PHASE_INVERTER, "Phase Inverter Control", USB_MIXER_BOOLEAN, -1 }, + { "Input Gain Control", USB_MIXER_S16, -1 }, + { "Input Gain Pad Control", USB_MIXER_S16, -1 }, + { "Phase Inverter Control", USB_MIXER_BOOLEAN, -1 }, }; /* private_free callback */ @@ -1354,66 +1181,6 @@ static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol, return changed; } -/* get the boolean value from the master channel of a UAC control */ -static int mixer_ctl_master_bool_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct usb_mixer_elem_info *cval = kcontrol->private_data; - int val, err; - - err = snd_usb_get_cur_mix_value(cval, 0, 0, &val); - if (err < 0) - return filter_error(cval, err); - val = (val != 0); - ucontrol->value.integer.value[0] = val; - return 0; -} - -/* get the connectors status and report it as boolean type */ -static int mixer_ctl_connector_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct usb_mixer_elem_info *cval = kcontrol->private_data; - struct snd_usb_audio *chip = cval->head.mixer->chip; - int idx = 0, validx, ret, val; - - validx = cval->control << 8 | 0; - - ret = snd_usb_lock_shutdown(chip) ? -EIO : 0; - if (ret) - goto error; - - idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8); - if (cval->head.mixer->protocol == UAC_VERSION_2) { - struct uac2_connectors_ctl_blk uac2_conn; - - ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), UAC2_CS_CUR, - USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - validx, idx, &uac2_conn, sizeof(uac2_conn)); - val = !!uac2_conn.bNrChannels; - } else { /* UAC_VERSION_3 */ - struct uac3_insertion_ctl_blk uac3_conn; - - ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), UAC2_CS_CUR, - USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - validx, idx, &uac3_conn, sizeof(uac3_conn)); - val = !!uac3_conn.bmConInserted; - } - - snd_usb_unlock_shutdown(chip); - - if (ret < 0) { -error: - usb_audio_err(chip, - "cannot get connectors status: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", - UAC_GET_CUR, validx, idx, cval->val_type); - return ret; - } - - ucontrol->value.integer.value[0] = val; - return 0; -} - static struct snd_kcontrol_new usb_feature_unit_ctl = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "", /* will be filled later manually */ @@ -1432,28 +1199,6 @@ static const struct snd_kcontrol_new usb_feature_unit_ctl_ro = { }; /* - * A control which shows the boolean value from reading a UAC control on - * the master channel. - */ -static struct snd_kcontrol_new usb_bool_master_control_ctl_ro = { - .iface = SNDRV_CTL_ELEM_IFACE_CARD, - .name = "", /* will be filled later manually */ - .access = SNDRV_CTL_ELEM_ACCESS_READ, - .info = snd_ctl_boolean_mono_info, - .get = mixer_ctl_master_bool_get, - .put = NULL, -}; - -static const struct snd_kcontrol_new usb_connector_ctl_ro = { - .iface = SNDRV_CTL_ELEM_IFACE_CARD, - .name = "", /* will be filled later manually */ - .access = SNDRV_CTL_ELEM_ACCESS_READ, - .info = snd_ctl_boolean_mono_info, - .get = mixer_ctl_connector_get, - .put = NULL, -}; - -/* * This symbol is exported in order to allow the mixer quirks to * hook up to the standard feature unit control mechanism */ @@ -1495,54 +1240,40 @@ static void check_no_speaker_on_headset(struct snd_kcontrol *kctl, strlcpy(kctl->id.name, "Headphone", sizeof(kctl->id.name)); } -static struct usb_feature_control_info *get_feature_control_info(int control) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(audio_feature_info); ++i) { - if (audio_feature_info[i].control == control) - return &audio_feature_info[i]; - } - return NULL; -} - -static void __build_feature_ctl(struct usb_mixer_interface *mixer, - const struct usbmix_name_map *imap, - unsigned int ctl_mask, int control, - struct usb_audio_term *iterm, - struct usb_audio_term *oterm, - int unitid, int nameid, int readonly_mask) +static void build_feature_ctl(struct mixer_build *state, void *raw_desc, + unsigned int ctl_mask, int control, + struct usb_audio_term *iterm, int unitid, + int readonly_mask) { + struct uac_feature_unit_descriptor *desc = raw_desc; struct usb_feature_control_info *ctl_info; unsigned int len = 0; int mapped_name = 0; + int nameid = uac_feature_unit_iFeature(desc); struct snd_kcontrol *kctl; struct usb_mixer_elem_info *cval; const struct usbmix_name_map *map; unsigned int range; + control++; /* change from zero-based to 1-based value */ + if (control == UAC_FU_GRAPHIC_EQUALIZER) { /* FIXME: not supported yet */ return; } - map = find_map(imap, unitid, control); + map = find_map(state, unitid, control); if (check_ignored_ctl(map)) return; cval = kzalloc(sizeof(*cval), GFP_KERNEL); if (!cval) return; - snd_usb_mixer_elem_init_std(&cval->head, mixer, unitid); + snd_usb_mixer_elem_init_std(&cval->head, state->mixer, unitid); cval->control = control; cval->cmask = ctl_mask; - - ctl_info = get_feature_control_info(control); - if (!ctl_info) { - kfree(cval); - return; - } - if (mixer->protocol == UAC_VERSION_1) + ctl_info = &audio_feature_info[control-1]; + if (state->mixer->protocol == UAC_VERSION_1) cval->val_type = ctl_info->type; else /* UAC_VERSION_2 */ cval->val_type = ctl_info->type_uac2 >= 0 ? @@ -1571,7 +1302,7 @@ static void __build_feature_ctl(struct usb_mixer_interface *mixer, kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval); if (!kctl) { - usb_audio_err(mixer->chip, "cannot malloc kcontrol\n"); + usb_audio_err(state->chip, "cannot malloc kcontrol\n"); kfree(cval); return; } @@ -1580,7 +1311,7 @@ static void __build_feature_ctl(struct usb_mixer_interface *mixer, len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)); mapped_name = len != 0; if (!len && nameid) - len = snd_usb_copy_string_desc(mixer->chip, nameid, + len = snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name)); switch (control) { @@ -1595,12 +1326,10 @@ static void __build_feature_ctl(struct usb_mixer_interface *mixer, * - otherwise, anonymous name. */ if (!len) { - if (iterm) - len = get_term_name(mixer->chip, iterm, - kctl->id.name, - sizeof(kctl->id.name), 1); - if (!len && oterm) - len = get_term_name(mixer->chip, oterm, + len = get_term_name(state, iterm, kctl->id.name, + sizeof(kctl->id.name), 1); + if (!len) + len = get_term_name(state, &state->oterm, kctl->id.name, sizeof(kctl->id.name), 1); if (!len) @@ -1609,15 +1338,15 @@ static void __build_feature_ctl(struct usb_mixer_interface *mixer, } if (!mapped_name) - check_no_speaker_on_headset(kctl, mixer->chip->card); + check_no_speaker_on_headset(kctl, state->mixer->chip->card); /* * determine the stream direction: * if the connected output is USB stream, then it's likely a * capture stream. otherwise it should be playback (hopefully :) */ - if (!mapped_name && oterm && !(oterm->type >> 16)) { - if ((oterm->type & 0xff00) == 0x0100) + if (!mapped_name && !(state->oterm.type >> 16)) { + if ((state->oterm.type & 0xff00) == 0x0100) append_ctl_name(kctl, " Capture"); else append_ctl_name(kctl, " Playback"); @@ -1645,7 +1374,7 @@ static void __build_feature_ctl(struct usb_mixer_interface *mixer, } } - snd_usb_mixer_fu_apply_quirk(mixer, cval, unitid, kctl); + snd_usb_mixer_fu_apply_quirk(state->mixer, cval, unitid, kctl); range = (cval->max - cval->min) / cval->res; /* @@ -1654,103 +1383,21 @@ static void __build_feature_ctl(struct usb_mixer_interface *mixer, * devices. It will definitively catch all buggy Logitech devices. */ if (range > 384) { - usb_audio_warn(mixer->chip, + usb_audio_warn(state->chip, "Warning! Unlikely big volume range (=%u), cval->res is probably wrong.", range); - usb_audio_warn(mixer->chip, + usb_audio_warn(state->chip, "[%d] FU [%s] ch = %d, val = %d/%d/%d", cval->head.id, kctl->id.name, cval->channels, cval->min, cval->max, cval->res); } - usb_audio_dbg(mixer->chip, "[%d] FU [%s] ch = %d, val = %d/%d/%d\n", + usb_audio_dbg(state->chip, "[%d] FU [%s] ch = %d, val = %d/%d/%d\n", cval->head.id, kctl->id.name, cval->channels, cval->min, cval->max, cval->res); snd_usb_mixer_add_control(&cval->head, kctl); } -static void build_feature_ctl(struct mixer_build *state, void *raw_desc, - unsigned int ctl_mask, int control, - struct usb_audio_term *iterm, int unitid, - int readonly_mask) -{ - struct uac_feature_unit_descriptor *desc = raw_desc; - int nameid = uac_feature_unit_iFeature(desc); - - __build_feature_ctl(state->mixer, state->map, ctl_mask, control, - iterm, &state->oterm, unitid, nameid, readonly_mask); -} - -static void build_feature_ctl_badd(struct usb_mixer_interface *mixer, - unsigned int ctl_mask, int control, int unitid, - const struct usbmix_name_map *badd_map) -{ - __build_feature_ctl(mixer, badd_map, ctl_mask, control, - NULL, NULL, unitid, 0, 0); -} - -static void get_connector_control_name(struct usb_mixer_interface *mixer, - struct usb_audio_term *term, - bool is_input, char *name, int name_size) -{ - int name_len = get_term_name(mixer->chip, term, name, name_size, 0); - - if (name_len == 0) - strlcpy(name, "Unknown", name_size); - - /* - * sound/core/ctljack.c has a convention of naming jack controls - * by ending in " Jack". Make it slightly more useful by - * indicating Input or Output after the terminal name. - */ - if (is_input) - strlcat(name, " - Input Jack", name_size); - else - strlcat(name, " - Output Jack", name_size); -} - -/* Build a mixer control for a UAC connector control (jack-detect) */ -static void build_connector_control(struct usb_mixer_interface *mixer, - struct usb_audio_term *term, bool is_input) -{ - struct snd_kcontrol *kctl; - struct usb_mixer_elem_info *cval; - - cval = kzalloc(sizeof(*cval), GFP_KERNEL); - if (!cval) - return; - snd_usb_mixer_elem_init_std(&cval->head, mixer, term->id); - /* - * UAC2: The first byte from reading the UAC2_TE_CONNECTOR control returns the - * number of channels connected. - * - * UAC3: The first byte specifies size of bitmap for the inserted controls. The - * following byte(s) specifies which connectors are inserted. - * - * This boolean ctl will simply report if any channels are connected - * or not. - */ - if (mixer->protocol == UAC_VERSION_2) - cval->control = UAC2_TE_CONNECTOR; - else /* UAC_VERSION_3 */ - cval->control = UAC3_TE_INSERTION; - - cval->val_type = USB_MIXER_BOOLEAN; - cval->channels = 1; /* report true if any channel is connected */ - cval->min = 0; - cval->max = 1; - kctl = snd_ctl_new1(&usb_connector_ctl_ro, cval); - if (!kctl) { - usb_audio_err(mixer->chip, "cannot malloc kcontrol\n"); - kfree(cval); - return; - } - get_connector_control_name(mixer, term, is_input, kctl->id.name, - sizeof(kctl->id.name)); - kctl->private_free = snd_usb_mixer_elem_free; - snd_usb_mixer_add_control(&cval->head, kctl); -} - static int parse_clock_source_unit(struct mixer_build *state, int unitid, void *_ftr) { @@ -1774,8 +1421,8 @@ static int parse_clock_source_unit(struct mixer_build *state, int unitid, * The only property of this unit we are interested in is the * clock source validity. If that isn't readable, just bail out. */ - if (!uac_v2v3_control_is_readable(hdr->bmControls, - UAC2_CS_CONTROL_CLOCK_VALID)) + if (!uac2_control_is_readable(hdr->bmControls, + ilog2(UAC2_CS_CONTROL_CLOCK_VALID))) return 0; cval = kzalloc(sizeof(*cval), GFP_KERNEL); @@ -1790,9 +1437,13 @@ static int parse_clock_source_unit(struct mixer_build *state, int unitid, cval->val_type = USB_MIXER_BOOLEAN; cval->control = UAC2_CS_CONTROL_CLOCK_VALID; - cval->master_readonly = 1; - /* From UAC2 5.2.5.1.2 "Only the get request is supported." */ - kctl = snd_ctl_new1(&usb_bool_master_control_ctl_ro, cval); + if (uac2_control_is_writeable(hdr->bmControls, + ilog2(UAC2_CS_CONTROL_CLOCK_VALID))) + kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval); + else { + cval->master_readonly = 1; + kctl = snd_ctl_new1(&usb_feature_unit_ctl_ro, cval); + } if (!kctl) { kfree(cval); @@ -1800,7 +1451,7 @@ static int parse_clock_source_unit(struct mixer_build *state, int unitid, } kctl->private_free = snd_usb_mixer_elem_free; - ret = snd_usb_copy_string_desc(state->chip, hdr->iClockSource, + ret = snd_usb_copy_string_desc(state, hdr->iClockSource, name, sizeof(name)); if (ret > 0) snprintf(kctl->id.name, sizeof(kctl->id.name), @@ -1849,7 +1500,7 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, unitid); return -EINVAL; } - } else if (state->mixer->protocol == UAC_VERSION_2) { + } else { struct uac2_feature_unit_descriptor *ftr = _ftr; if (hdr->bLength < 6) { usb_audio_err(state->chip, @@ -1866,29 +1517,10 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, unitid); return -EINVAL; } - } else { /* UAC_VERSION_3 */ - struct uac3_feature_unit_descriptor *ftr = _ftr; - - if (hdr->bLength < 7) { - usb_audio_err(state->chip, - "unit %u: invalid UAC3_FEATURE_UNIT descriptor\n", - unitid); - return -EINVAL; - } - csize = 4; - channels = (ftr->bLength - 7) / 4 - 1; - bmaControls = ftr->bmaControls; - if (hdr->bLength < 7 + csize) { - usb_audio_err(state->chip, - "unit %u: invalid UAC3_FEATURE_UNIT descriptor\n", - unitid); - return -EINVAL; - } } /* parse the source unit */ - err = parse_audio_unit(state, hdr->bSourceID); - if (err < 0) + if ((err = parse_audio_unit(state, hdr->bSourceID)) < 0) return err; /* determine the input source type and name */ @@ -1922,8 +1554,6 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, /* check all control types */ for (i = 0; i < 10; i++) { unsigned int ch_bits = 0; - int control = audio_feature_info[i].control; - for (j = 0; j < channels; j++) { unsigned int mask; @@ -1939,26 +1569,25 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, * (for ease of programming). */ if (ch_bits & 1) - build_feature_ctl(state, _ftr, ch_bits, control, + build_feature_ctl(state, _ftr, ch_bits, i, &iterm, unitid, 0); if (master_bits & (1 << i)) - build_feature_ctl(state, _ftr, 0, control, - &iterm, unitid, 0); + build_feature_ctl(state, _ftr, 0, i, &iterm, + unitid, 0); } - } else { /* UAC_VERSION_2/3 */ + } else { /* UAC_VERSION_2 */ for (i = 0; i < ARRAY_SIZE(audio_feature_info); i++) { unsigned int ch_bits = 0; unsigned int ch_read_only = 0; - int control = audio_feature_info[i].control; for (j = 0; j < channels; j++) { unsigned int mask; mask = snd_usb_combine_bytes(bmaControls + csize * (j+1), csize); - if (uac_v2v3_control_is_readable(mask, control)) { + if (uac2_control_is_readable(mask, i)) { ch_bits |= (1 << j); - if (!uac_v2v3_control_is_writeable(mask, control)) + if (!uac2_control_is_writeable(mask, i)) ch_read_only |= (1 << j); } } @@ -1977,13 +1606,11 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, * (for ease of programming). */ if (ch_bits & 1) - build_feature_ctl(state, _ftr, ch_bits, control, + build_feature_ctl(state, _ftr, ch_bits, i, &iterm, unitid, ch_read_only); - if (uac_v2v3_control_is_readable(master_bits, control)) - build_feature_ctl(state, _ftr, 0, control, - &iterm, unitid, - !uac_v2v3_control_is_writeable(master_bits, - control)); + if (uac2_control_is_readable(master_bits, i)) + build_feature_ctl(state, _ftr, 0, i, &iterm, unitid, + !uac2_control_is_writeable(master_bits, i)); } } @@ -2002,15 +1629,16 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, */ static void build_mixer_unit_ctl(struct mixer_build *state, struct uac_mixer_unit_descriptor *desc, - int in_pin, int in_ch, int num_outs, - int unitid, struct usb_audio_term *iterm) + int in_pin, int in_ch, int unitid, + struct usb_audio_term *iterm) { struct usb_mixer_elem_info *cval; + unsigned int num_outs = uac_mixer_unit_bNrChannels(desc); unsigned int i, len; struct snd_kcontrol *kctl; const struct usbmix_name_map *map; - map = find_map(state->map, unitid, 0); + map = find_map(state, unitid, 0); if (check_ignored_ctl(map)) return; @@ -2043,7 +1671,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state, len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)); if (!len) - len = get_term_name(state->chip, iterm, kctl->id.name, + len = get_term_name(state, iterm, kctl->id.name, sizeof(kctl->id.name), 0); if (!len) len = sprintf(kctl->id.name, "Mixer Source %d", in_ch + 1); @@ -2054,35 +1682,6 @@ static void build_mixer_unit_ctl(struct mixer_build *state, snd_usb_mixer_add_control(&cval->head, kctl); } -static int parse_audio_input_terminal(struct mixer_build *state, int unitid, - void *raw_desc) -{ - struct usb_audio_term iterm; - unsigned int control, bmctls, term_id; - - if (state->mixer->protocol == UAC_VERSION_2) { - struct uac2_input_terminal_descriptor *d_v2 = raw_desc; - control = UAC2_TE_CONNECTOR; - term_id = d_v2->bTerminalID; - bmctls = le16_to_cpu(d_v2->bmControls); - } else if (state->mixer->protocol == UAC_VERSION_3) { - struct uac3_input_terminal_descriptor *d_v3 = raw_desc; - control = UAC3_TE_INSERTION; - term_id = d_v3->bTerminalID; - bmctls = le32_to_cpu(d_v3->bmControls); - } else { - return 0; /* UAC1. No Insertion control */ - } - - check_input_term(state, term_id, &iterm); - - /* Check for jack detection. */ - if (uac_v2v3_control_is_readable(bmctls, control)) - build_connector_control(state->mixer, &iterm, true); - - return 0; -} - /* * parse a mixer unit */ @@ -2094,17 +1693,14 @@ static int parse_audio_mixer_unit(struct mixer_build *state, int unitid, int input_pins, num_ins, num_outs; int pin, ich, err; - err = uac_mixer_unit_get_channels(state, desc); - if (err < 0) { + if (desc->bLength < 11 || !(input_pins = desc->bNrInPins) || + !(num_outs = uac_mixer_unit_bNrChannels(desc))) { usb_audio_err(state->chip, "invalid MIXER UNIT descriptor %d\n", unitid); - return err; + return -EINVAL; } - num_outs = err; - input_pins = desc->bNrInPins; - num_ins = 0; ich = 0; for (pin = 0; pin < input_pins; pin++) { @@ -2131,7 +1727,7 @@ static int parse_audio_mixer_unit(struct mixer_build *state, int unitid, } } if (ich_has_controls) - build_mixer_unit_ctl(state, desc, pin, ich, num_outs, + build_mixer_unit_ctl(state, desc, pin, ich, unitid, &iterm); } } @@ -2203,11 +1799,6 @@ struct procunit_info { struct procunit_value_info *values; }; -static struct procunit_value_info undefined_proc_info[] = { - { 0x00, "Control Undefined", 0 }, - { 0 } -}; - static struct procunit_value_info updown_proc_info[] = { { UAC_UD_ENABLE, "Switch", USB_MIXER_BOOLEAN }, { UAC_UD_MODE_SELECT, "Mode Select", USB_MIXER_U8, 1 }, @@ -2256,23 +1847,6 @@ static struct procunit_info procunits[] = { { UAC_PROCESS_DYN_RANGE_COMP, "DCR", dcr_proc_info }, { 0 }, }; - -static struct procunit_value_info uac3_updown_proc_info[] = { - { UAC3_UD_MODE_SELECT, "Mode Select", USB_MIXER_U8, 1 }, - { 0 } -}; -static struct procunit_value_info uac3_stereo_ext_proc_info[] = { - { UAC3_EXT_WIDTH_CONTROL, "Width Control", USB_MIXER_U8 }, - { 0 } -}; - -static struct procunit_info uac3_procunits[] = { - { UAC3_PROCESS_UP_DOWNMIX, "Up Down", uac3_updown_proc_info }, - { UAC3_PROCESS_STEREO_EXTENDER, "3D Stereo Extender", uac3_stereo_ext_proc_info }, - { UAC3_PROCESS_MULTI_FUNCTION, "Multi-Function", undefined_proc_info }, - { 0 }, -}; - /* * predefined data for extension units */ @@ -2330,8 +1904,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, } for (i = 0; i < num_ins; i++) { - err = parse_audio_unit(state, desc->baSourceID[i]); - if (err < 0) + if ((err = parse_audio_unit(state, desc->baSourceID[i])) < 0) return err; } @@ -2345,17 +1918,9 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, for (valinfo = info->values; valinfo->control; valinfo++) { __u8 *controls = uac_processing_unit_bmControls(desc, state->mixer->protocol); - if (state->mixer->protocol == UAC_VERSION_1) { - if (!(controls[valinfo->control / 8] & - (1 << ((valinfo->control % 8) - 1)))) - continue; - } else { /* UAC_VERSION_2/3 */ - if (!uac_v2v3_control_is_readable(controls[valinfo->control / 8], - valinfo->control)) - continue; - } - - map = find_map(state->map, unitid, valinfo->control); + if (!(controls[valinfo->control / 8] & (1 << ((valinfo->control % 8) - 1)))) + continue; + map = find_map(state, unitid, valinfo->control); if (check_ignored_ctl(map)) continue; cval = kzalloc(sizeof(*cval), GFP_KERNEL); @@ -2366,55 +1931,26 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, cval->val_type = valinfo->val_type; cval->channels = 1; - if (state->mixer->protocol > UAC_VERSION_1 && - !uac_v2v3_control_is_writeable(controls[valinfo->control / 8], - valinfo->control)) - cval->master_readonly = 1; - /* get min/max values */ - switch (type) { - case UAC_PROCESS_UP_DOWNMIX: { - bool mode_sel = false; - - switch (state->mixer->protocol) { - case UAC_VERSION_1: - case UAC_VERSION_2: - default: - if (cval->control == UAC_UD_MODE_SELECT) - mode_sel = true; - break; - case UAC_VERSION_3: - if (cval->control == UAC3_UD_MODE_SELECT) - mode_sel = true; - break; - } - - if (mode_sel) { - __u8 *control_spec = uac_processing_unit_specific(desc, - state->mixer->protocol); - cval->min = 1; - cval->max = control_spec[0]; - cval->res = 1; - cval->initialized = 1; - break; - } - - get_min_max(cval, valinfo->min_value); - break; - } - case USB_XU_CLOCK_RATE: - /* - * E-Mu USB 0404/0202/TrackerPre/0204 - * samplerate control quirk - */ - cval->min = 0; - cval->max = 5; + if (type == UAC_PROCESS_UP_DOWNMIX && cval->control == UAC_UD_MODE_SELECT) { + __u8 *control_spec = uac_processing_unit_specific(desc, state->mixer->protocol); + /* FIXME: hard-coded */ + cval->min = 1; + cval->max = control_spec[0]; cval->res = 1; cval->initialized = 1; - break; - default: - get_min_max(cval, valinfo->min_value); - break; + } else { + if (type == USB_XU_CLOCK_RATE) { + /* + * E-Mu USB 0404/0202/TrackerPre/0204 + * samplerate control quirk + */ + cval->min = 0; + cval->max = 5; + cval->res = 1; + cval->initialized = 1; + } else + get_min_max(cval, valinfo->min_value); } kctl = snd_ctl_new1(&mixer_procunit_ctl, cval); @@ -2432,8 +1968,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, nameid = uac_processing_unit_iProcessing(desc, state->mixer->protocol); len = 0; if (nameid) - len = snd_usb_copy_string_desc(state->chip, - nameid, + len = snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name)); if (!len) @@ -2457,16 +1992,8 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, static int parse_audio_processing_unit(struct mixer_build *state, int unitid, void *raw_desc) { - switch (state->mixer->protocol) { - case UAC_VERSION_1: - case UAC_VERSION_2: - default: - return build_audio_procunit(state, unitid, raw_desc, - procunits, "Processing Unit"); - case UAC_VERSION_3: - return build_audio_procunit(state, unitid, raw_desc, - uac3_procunits, "Processing Unit"); - } + return build_audio_procunit(state, unitid, raw_desc, + procunits, "Processing Unit"); } static int parse_audio_extension_unit(struct mixer_build *state, int unitid, @@ -2589,15 +2116,14 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, } for (i = 0; i < desc->bNrInPins; i++) { - err = parse_audio_unit(state, desc->baSourceID[i]); - if (err < 0) + if ((err = parse_audio_unit(state, desc->baSourceID[i])) < 0) return err; } if (desc->bNrInPins == 1) /* only one ? nonsense! */ return 0; - map = find_map(state->map, unitid, 0); + map = find_map(state, unitid, 0); if (check_ignored_ctl(map)) return 0; @@ -2612,20 +2138,11 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, cval->res = 1; cval->initialized = 1; - switch (state->mixer->protocol) { - case UAC_VERSION_1: - default: + if (state->mixer->protocol == UAC_VERSION_1) cval->control = 0; - break; - case UAC_VERSION_2: - case UAC_VERSION_3: - if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR || - desc->bDescriptorSubtype == UAC3_CLOCK_SELECTOR) - cval->control = UAC2_CX_CLOCK_SELECTOR; - else /* UAC2/3_SELECTOR_UNIT */ - cval->control = UAC2_SU_SELECTOR; - break; - } + else /* UAC_VERSION_2 */ + cval->control = (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR) ? + UAC2_CX_CLOCK_SELECTOR : UAC2_SU_SELECTOR; namelist = kmalloc(sizeof(char *) * desc->bNrInPins, GFP_KERNEL); if (!namelist) { @@ -2647,8 +2164,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, len = check_mapped_selector_name(state, unitid, i, namelist[i], MAX_ITEM_NAME_LEN); if (! len && check_input_term(state, desc->baSourceID[i], &iterm) >= 0) - len = get_term_name(state->chip, &iterm, namelist[i], - MAX_ITEM_NAME_LEN, 0); + len = get_term_name(state, &iterm, namelist[i], MAX_ITEM_NAME_LEN, 0); if (! len) sprintf(namelist[i], "Input %u", i); } @@ -2667,33 +2183,22 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)); if (!len) { /* no mapping ? */ - switch (state->mixer->protocol) { - case UAC_VERSION_1: - case UAC_VERSION_2: - default: /* if iSelector is given, use it */ - nameid = uac_selector_unit_iSelector(desc); - if (nameid) - len = snd_usb_copy_string_desc(state->chip, - nameid, kctl->id.name, - sizeof(kctl->id.name)); - break; - case UAC_VERSION_3: - /* TODO: Class-Specific strings not yet supported */ - break; - } - + nameid = uac_selector_unit_iSelector(desc); + if (nameid) + len = snd_usb_copy_string_desc(state, nameid, + kctl->id.name, + sizeof(kctl->id.name)); /* ... or pick up the terminal name at next */ if (!len) - len = get_term_name(state->chip, &state->oterm, + len = get_term_name(state, &state->oterm, kctl->id.name, sizeof(kctl->id.name), 0); /* ... or use the fixed string "USB" as the last resort */ if (!len) strlcpy(kctl->id.name, "USB", sizeof(kctl->id.name)); /* and add the proper suffix */ - if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR || - desc->bDescriptorSubtype == UAC3_CLOCK_SELECTOR) + if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR) append_ctl_name(kctl, " Clock Source"); else if ((state->oterm.type & 0xff00) == 0x0100) append_ctl_name(kctl, " Capture Source"); @@ -2713,7 +2218,6 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, static int parse_audio_unit(struct mixer_build *state, int unitid) { unsigned char *p1; - int protocol = state->mixer->protocol; if (test_and_set_bit(unitid, state->unitbitmap)) return 0; /* the unit already visited */ @@ -2724,62 +2228,36 @@ static int parse_audio_unit(struct mixer_build *state, int unitid) return -EINVAL; } - if (protocol == UAC_VERSION_1 || protocol == UAC_VERSION_2) { - switch (p1[2]) { - case UAC_INPUT_TERMINAL: - return parse_audio_input_terminal(state, unitid, p1); - case UAC_MIXER_UNIT: - return parse_audio_mixer_unit(state, unitid, p1); - case UAC2_CLOCK_SOURCE: - return parse_clock_source_unit(state, unitid, p1); - case UAC_SELECTOR_UNIT: - case UAC2_CLOCK_SELECTOR: - return parse_audio_selector_unit(state, unitid, p1); - case UAC_FEATURE_UNIT: - return parse_audio_feature_unit(state, unitid, p1); - case UAC1_PROCESSING_UNIT: - /* UAC2_EFFECT_UNIT has the same value */ - if (protocol == UAC_VERSION_1) - return parse_audio_processing_unit(state, unitid, p1); - else - return 0; /* FIXME - effect units not implemented yet */ - case UAC1_EXTENSION_UNIT: - /* UAC2_PROCESSING_UNIT_V2 has the same value */ - if (protocol == UAC_VERSION_1) - return parse_audio_extension_unit(state, unitid, p1); - else /* UAC_VERSION_2 */ - return parse_audio_processing_unit(state, unitid, p1); - case UAC2_EXTENSION_UNIT_V2: - return parse_audio_extension_unit(state, unitid, p1); - default: - usb_audio_err(state->chip, - "unit %u: unexpected type 0x%02x\n", unitid, p1[2]); - return -EINVAL; - } - } else { /* UAC_VERSION_3 */ - switch (p1[2]) { - case UAC_INPUT_TERMINAL: - return parse_audio_input_terminal(state, unitid, p1); - case UAC3_MIXER_UNIT: - return parse_audio_mixer_unit(state, unitid, p1); - case UAC3_CLOCK_SOURCE: - return parse_clock_source_unit(state, unitid, p1); - case UAC3_SELECTOR_UNIT: - case UAC3_CLOCK_SELECTOR: - return parse_audio_selector_unit(state, unitid, p1); - case UAC3_FEATURE_UNIT: - return parse_audio_feature_unit(state, unitid, p1); - case UAC3_EFFECT_UNIT: - return 0; /* FIXME - effect units not implemented yet */ - case UAC3_PROCESSING_UNIT: + switch (p1[2]) { + case UAC_INPUT_TERMINAL: + return 0; /* NOP */ + case UAC_MIXER_UNIT: + return parse_audio_mixer_unit(state, unitid, p1); + case UAC2_CLOCK_SOURCE: + return parse_clock_source_unit(state, unitid, p1); + case UAC_SELECTOR_UNIT: + case UAC2_CLOCK_SELECTOR: + return parse_audio_selector_unit(state, unitid, p1); + case UAC_FEATURE_UNIT: + return parse_audio_feature_unit(state, unitid, p1); + case UAC1_PROCESSING_UNIT: + /* UAC2_EFFECT_UNIT has the same value */ + if (state->mixer->protocol == UAC_VERSION_1) return parse_audio_processing_unit(state, unitid, p1); - case UAC3_EXTENSION_UNIT: + else + return 0; /* FIXME - effect units not implemented yet */ + case UAC1_EXTENSION_UNIT: + /* UAC2_PROCESSING_UNIT_V2 has the same value */ + if (state->mixer->protocol == UAC_VERSION_1) return parse_audio_extension_unit(state, unitid, p1); - default: - usb_audio_err(state->chip, - "unit %u: unexpected type 0x%02x\n", unitid, p1[2]); - return -EINVAL; - } + else /* UAC_VERSION_2 */ + return parse_audio_processing_unit(state, unitid, p1); + case UAC2_EXTENSION_UNIT_V2: + return parse_audio_extension_unit(state, unitid, p1); + default: + usb_audio_err(state->chip, + "unit %u: unexpected type 0x%02x\n", unitid, p1[2]); + return -EINVAL; } } @@ -2805,263 +2283,6 @@ static int snd_usb_mixer_dev_free(struct snd_device *device) return 0; } -/* UAC3 predefined channels configuration */ -struct uac3_badd_profile { - int subclass; - const char *name; - int c_chmask; /* capture channels mask */ - int p_chmask; /* playback channels mask */ - int st_chmask; /* side tone mixing channel mask */ -}; - -static struct uac3_badd_profile uac3_badd_profiles[] = { - { - /* - * BAIF, BAOF or combination of both - * IN: Mono or Stereo cfg, Mono alt possible - * OUT: Mono or Stereo cfg, Mono alt possible - */ - .subclass = UAC3_FUNCTION_SUBCLASS_GENERIC_IO, - .name = "GENERIC IO", - .c_chmask = -1, /* dynamic channels */ - .p_chmask = -1, /* dynamic channels */ - }, - { - /* BAOF; Stereo only cfg, Mono alt possible */ - .subclass = UAC3_FUNCTION_SUBCLASS_HEADPHONE, - .name = "HEADPHONE", - .p_chmask = 3, - }, - { - /* BAOF; Mono or Stereo cfg, Mono alt possible */ - .subclass = UAC3_FUNCTION_SUBCLASS_SPEAKER, - .name = "SPEAKER", - .p_chmask = -1, /* dynamic channels */ - }, - { - /* BAIF; Mono or Stereo cfg, Mono alt possible */ - .subclass = UAC3_FUNCTION_SUBCLASS_MICROPHONE, - .name = "MICROPHONE", - .c_chmask = -1, /* dynamic channels */ - }, - { - /* - * BAIOF topology - * IN: Mono only - * OUT: Mono or Stereo cfg, Mono alt possible - */ - .subclass = UAC3_FUNCTION_SUBCLASS_HEADSET, - .name = "HEADSET", - .c_chmask = 1, - .p_chmask = -1, /* dynamic channels */ - .st_chmask = 1, - }, - { - /* BAIOF; IN: Mono only; OUT: Stereo only, Mono alt possible */ - .subclass = UAC3_FUNCTION_SUBCLASS_HEADSET_ADAPTER, - .name = "HEADSET ADAPTER", - .c_chmask = 1, - .p_chmask = 3, - .st_chmask = 1, - }, - { - /* BAIF + BAOF; IN: Mono only; OUT: Mono only */ - .subclass = UAC3_FUNCTION_SUBCLASS_SPEAKERPHONE, - .name = "SPEAKERPHONE", - .c_chmask = 1, - .p_chmask = 1, - }, - { 0 } /* terminator */ -}; - -static bool uac3_badd_func_has_valid_channels(struct usb_mixer_interface *mixer, - struct uac3_badd_profile *f, - int c_chmask, int p_chmask) -{ - /* - * If both playback/capture channels are dynamic, make sure - * at least one channel is present - */ - if (f->c_chmask < 0 && f->p_chmask < 0) { - if (!c_chmask && !p_chmask) { - usb_audio_warn(mixer->chip, "BAAD %s: no channels?", - f->name); - return false; - } - return true; - } - - if ((f->c_chmask < 0 && !c_chmask) || - (f->c_chmask >= 0 && f->c_chmask != c_chmask)) { - usb_audio_warn(mixer->chip, "BAAD %s c_chmask mismatch", - f->name); - return false; - } - if ((f->p_chmask < 0 && !p_chmask) || - (f->p_chmask >= 0 && f->p_chmask != p_chmask)) { - usb_audio_warn(mixer->chip, "BAAD %s p_chmask mismatch", - f->name); - return false; - } - return true; -} - -/* - * create mixer controls for UAC3 BADD profiles - * - * UAC3 BADD device doesn't contain CS descriptors thus we will guess everything - * - * BADD device may contain Mixer Unit, which doesn't have any controls, skip it - */ -static int snd_usb_mixer_controls_badd(struct usb_mixer_interface *mixer, - int ctrlif) -{ - struct usb_device *dev = mixer->chip->dev; - struct usb_interface_assoc_descriptor *assoc; - int badd_profile = mixer->chip->badd_profile; - struct uac3_badd_profile *f; - const struct usbmix_ctl_map *map; - int p_chmask = 0, c_chmask = 0, st_chmask = 0; - int i; - - assoc = usb_ifnum_to_if(dev, ctrlif)->intf_assoc; - - /* Detect BADD capture/playback channels from AS EP descriptors */ - for (i = 0; i < assoc->bInterfaceCount; i++) { - int intf = assoc->bFirstInterface + i; - - struct usb_interface *iface; - struct usb_host_interface *alts; - struct usb_interface_descriptor *altsd; - unsigned int maxpacksize; - char dir_in; - int chmask, num; - - if (intf == ctrlif) - continue; - - iface = usb_ifnum_to_if(dev, intf); - num = iface->num_altsetting; - - if (num < 2) - return -EINVAL; - - /* - * The number of Channels in an AudioStreaming interface - * and the audio sample bit resolution (16 bits or 24 - * bits) can be derived from the wMaxPacketSize field in - * the Standard AS Audio Data Endpoint descriptor in - * Alternate Setting 1 - */ - alts = &iface->altsetting[1]; - altsd = get_iface_desc(alts); - - if (altsd->bNumEndpoints < 1) - return -EINVAL; - - /* check direction */ - dir_in = (get_endpoint(alts, 0)->bEndpointAddress & USB_DIR_IN); - maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); - - switch (maxpacksize) { - default: - usb_audio_err(mixer->chip, - "incorrect wMaxPacketSize 0x%x for BADD profile\n", - maxpacksize); - return -EINVAL; - case UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_16: - case UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_16: - case UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_24: - case UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_24: - chmask = 1; - break; - case UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_16: - case UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_16: - case UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_24: - case UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_24: - chmask = 3; - break; - } - - if (dir_in) - c_chmask = chmask; - else - p_chmask = chmask; - } - - usb_audio_dbg(mixer->chip, - "UAC3 BADD profile 0x%x: detected c_chmask=%d p_chmask=%d\n", - badd_profile, c_chmask, p_chmask); - - /* check the mapping table */ - for (map = uac3_badd_usbmix_ctl_maps; map->id; map++) { - if (map->id == badd_profile) - break; - } - - if (!map->id) - return -EINVAL; - - for (f = uac3_badd_profiles; f->name; f++) { - if (badd_profile == f->subclass) - break; - } - if (!f->name) - return -EINVAL; - if (!uac3_badd_func_has_valid_channels(mixer, f, c_chmask, p_chmask)) - return -EINVAL; - st_chmask = f->st_chmask; - - /* Playback */ - if (p_chmask) { - /* Master channel, always writable */ - build_feature_ctl_badd(mixer, 0, UAC_FU_MUTE, - UAC3_BADD_FU_ID2, map->map); - /* Mono/Stereo volume channels, always writable */ - build_feature_ctl_badd(mixer, p_chmask, UAC_FU_VOLUME, - UAC3_BADD_FU_ID2, map->map); - } - - /* Capture */ - if (c_chmask) { - /* Master channel, always writable */ - build_feature_ctl_badd(mixer, 0, UAC_FU_MUTE, - UAC3_BADD_FU_ID5, map->map); - /* Mono/Stereo volume channels, always writable */ - build_feature_ctl_badd(mixer, c_chmask, UAC_FU_VOLUME, - UAC3_BADD_FU_ID5, map->map); - } - - /* Side tone-mixing */ - if (st_chmask) { - /* Master channel, always writable */ - build_feature_ctl_badd(mixer, 0, UAC_FU_MUTE, - UAC3_BADD_FU_ID7, map->map); - /* Mono volume channel, always writable */ - build_feature_ctl_badd(mixer, 1, UAC_FU_VOLUME, - UAC3_BADD_FU_ID7, map->map); - } - - /* Insertion Control */ - if (f->subclass == UAC3_FUNCTION_SUBCLASS_HEADSET_ADAPTER) { - struct usb_audio_term iterm, oterm; - - /* Input Term - Insertion control */ - memset(&iterm, 0, sizeof(iterm)); - iterm.id = UAC3_BADD_IT_ID4; - iterm.type = UAC_BIDIR_TERMINAL_HEADSET; - build_connector_control(mixer, &iterm, true); - - /* Output Term - Insertion control */ - memset(&oterm, 0, sizeof(oterm)); - oterm.id = UAC3_BADD_OT_ID3; - oterm.type = UAC_BIDIR_TERMINAL_HEADSET; - build_connector_control(mixer, &oterm, false); - } - - return 0; -} - /* * create mixer controls * @@ -3107,7 +2328,7 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) err = parse_audio_unit(&state, desc->bSourceID); if (err < 0 && err != -EINVAL) return err; - } else if (mixer->protocol == UAC_VERSION_2) { + } else { /* UAC_VERSION_2 */ struct uac2_output_terminal_descriptor *desc = p; if (desc->bLength < sizeof(*desc)) @@ -3128,39 +2349,6 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) err = parse_audio_unit(&state, desc->bCSourceID); if (err < 0 && err != -EINVAL) return err; - - if (uac_v2v3_control_is_readable(le16_to_cpu(desc->bmControls), - UAC2_TE_CONNECTOR)) { - build_connector_control(state.mixer, &state.oterm, - false); - } - } else { /* UAC_VERSION_3 */ - struct uac3_output_terminal_descriptor *desc = p; - - if (desc->bLength < sizeof(*desc)) - continue; /* invalid descriptor? */ - /* mark terminal ID as visited */ - set_bit(desc->bTerminalID, state.unitbitmap); - state.oterm.id = desc->bTerminalID; - state.oterm.type = le16_to_cpu(desc->wTerminalType); - state.oterm.name = le16_to_cpu(desc->wTerminalDescrStr); - err = parse_audio_unit(&state, desc->bSourceID); - if (err < 0 && err != -EINVAL) - return err; - - /* - * For UAC3, use the same approach to also add the - * clock selectors - */ - err = parse_audio_unit(&state, desc->bCSourceID); - if (err < 0 && err != -EINVAL) - return err; - - if (uac_v2v3_control_is_readable(le32_to_cpu(desc->bmControls), - UAC3_TE_INSERTION)) { - build_connector_control(state.mixer, &state.oterm, - false); - } } } @@ -3171,9 +2359,9 @@ void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid) { struct usb_mixer_elem_list *list; - for_each_mixer_elem(list, mixer, unitid) { + for (list = mixer->id_elems[unitid]; list; list = list->next_id_elem) { struct usb_mixer_elem_info *info = - mixer_elem_list_to_info(list); + (struct usb_mixer_elem_info *)list; /* invalidate cache, so the value is read from the device */ info->cached = 0; snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE, @@ -3184,7 +2372,7 @@ void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid) static void snd_usb_mixer_dump_cval(struct snd_info_buffer *buffer, struct usb_mixer_elem_list *list) { - struct usb_mixer_elem_info *cval = mixer_elem_list_to_info(list); + struct usb_mixer_elem_info *cval = (struct usb_mixer_elem_info *)list; static char *val_types[] = {"BOOLEAN", "INV_BOOLEAN", "S8", "U8", "S16", "U16"}; snd_iprintf(buffer, " Info: id=%i, control=%i, cmask=0x%x, " @@ -3210,7 +2398,8 @@ static void snd_usb_mixer_proc_read(struct snd_info_entry *entry, mixer->ignore_ctl_error); snd_iprintf(buffer, "Card: %s\n", chip->card->longname); for (unitid = 0; unitid < MAX_ID_ELEMS; unitid++) { - for_each_mixer_elem(list, mixer, unitid) { + for (list = mixer->id_elems[unitid]; list; + list = list->next_id_elem) { snd_iprintf(buffer, " Unit: %i\n", list->id); if (list->kctl) snd_iprintf(buffer, @@ -3240,19 +2429,19 @@ static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer, return; } - for_each_mixer_elem(list, mixer, unitid) + for (list = mixer->id_elems[unitid]; list; list = list->next_id_elem) count++; if (count == 0) return; - for_each_mixer_elem(list, mixer, unitid) { + for (list = mixer->id_elems[unitid]; list; list = list->next_id_elem) { struct usb_mixer_elem_info *info; if (!list->kctl) continue; - info = mixer_elem_list_to_info(list); + info = (struct usb_mixer_elem_info *)list; if (count > 1 && info->control != control) continue; @@ -3448,26 +2637,11 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, case UAC_VERSION_2: mixer->protocol = UAC_VERSION_2; break; - case UAC_VERSION_3: - mixer->protocol = UAC_VERSION_3; - break; } - if (mixer->protocol == UAC_VERSION_3 && - chip->badd_profile >= UAC3_FUNCTION_SUBCLASS_GENERIC_IO) { - err = snd_usb_mixer_controls_badd(mixer, ctrlif); - if (err < 0) - goto _error; - } else { - err = snd_usb_mixer_controls(mixer); - if (err < 0) - goto _error; - } - - err = snd_usb_mixer_status_create(mixer); - if (err < 0) + if ((err = snd_usb_mixer_controls(mixer)) < 0 || + (err = snd_usb_mixer_status_create(mixer)) < 0) goto _error; - err = create_keep_iface_ctl(mixer); if (err < 0) goto _error; @@ -3530,7 +2704,7 @@ int snd_usb_mixer_suspend(struct usb_mixer_interface *mixer) static int restore_mixer_value(struct usb_mixer_elem_list *list) { - struct usb_mixer_elem_info *cval = mixer_elem_list_to_info(list); + struct usb_mixer_elem_info *cval = (struct usb_mixer_elem_info *)list; int c, err, idx; if (cval->cmask) { @@ -3566,7 +2740,8 @@ int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume) if (reset_resume) { /* restore cached mixer values */ for (id = 0; id < MAX_ID_ELEMS; id++) { - for_each_mixer_elem(list, mixer, id) { + for (list = mixer->id_elems[id]; list; + list = list->next_id_elem) { if (list->resume) { err = list->resume(list); if (err < 0) diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h index 1ebaaac2ab90..545d99b09706 100644 --- a/sound/usb/mixer.h +++ b/sound/usb/mixer.h @@ -52,12 +52,6 @@ struct usb_mixer_elem_list { usb_mixer_elem_resume_func_t resume; }; -/* iterate over mixer element list of the given unit id */ -#define for_each_mixer_elem(list, mixer, id) \ - for ((list) = (mixer)->id_elems[id]; (list); (list) = (list)->next_id_elem) -#define mixer_elem_list_to_info(list) \ - container_of(list, struct usb_mixer_elem_info, head) - struct usb_mixer_elem_info { struct usb_mixer_elem_list head; unsigned int control; /* CS or ICN (high byte) */ @@ -108,6 +102,4 @@ int snd_usb_get_cur_mix_value(struct usb_mixer_elem_info *cval, extern void snd_usb_mixer_elem_free(struct snd_kcontrol *kctl); -extern struct snd_kcontrol_new *snd_usb_feature_unit_ctl; - #endif /* __USBMIXER_H */ diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c index 71069e110897..eaa03acd4686 100644 --- a/sound/usb/mixer_maps.c +++ b/sound/usb/mixer_maps.c @@ -485,68 +485,3 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = { { 0 } /* terminator */ }; -/* - * Control map entries for UAC3 BADD profiles - */ - -static struct usbmix_name_map uac3_badd_generic_io_map[] = { - { UAC3_BADD_FU_ID2, "Generic Out Playback" }, - { UAC3_BADD_FU_ID5, "Generic In Capture" }, - { 0 } /* terminator */ -}; -static struct usbmix_name_map uac3_badd_headphone_map[] = { - { UAC3_BADD_FU_ID2, "Headphone Playback" }, - { 0 } /* terminator */ -}; -static struct usbmix_name_map uac3_badd_speaker_map[] = { - { UAC3_BADD_FU_ID2, "Speaker Playback" }, - { 0 } /* terminator */ -}; -static struct usbmix_name_map uac3_badd_microphone_map[] = { - { UAC3_BADD_FU_ID5, "Mic Capture" }, - { 0 } /* terminator */ -}; -/* Covers also 'headset adapter' profile */ -static struct usbmix_name_map uac3_badd_headset_map[] = { - { UAC3_BADD_FU_ID2, "Headset Playback" }, - { UAC3_BADD_FU_ID5, "Headset Capture" }, - { UAC3_BADD_FU_ID7, "Sidetone Mixing" }, - { 0 } /* terminator */ -}; -static struct usbmix_name_map uac3_badd_speakerphone_map[] = { - { UAC3_BADD_FU_ID2, "Speaker Playback" }, - { UAC3_BADD_FU_ID5, "Mic Capture" }, - { 0 } /* terminator */ -}; - -static struct usbmix_ctl_map uac3_badd_usbmix_ctl_maps[] = { - { - .id = UAC3_FUNCTION_SUBCLASS_GENERIC_IO, - .map = uac3_badd_generic_io_map, - }, - { - .id = UAC3_FUNCTION_SUBCLASS_HEADPHONE, - .map = uac3_badd_headphone_map, - }, - { - .id = UAC3_FUNCTION_SUBCLASS_SPEAKER, - .map = uac3_badd_speaker_map, - }, - { - .id = UAC3_FUNCTION_SUBCLASS_MICROPHONE, - .map = uac3_badd_microphone_map, - }, - { - .id = UAC3_FUNCTION_SUBCLASS_HEADSET, - .map = uac3_badd_headset_map, - }, - { - .id = UAC3_FUNCTION_SUBCLASS_HEADSET_ADAPTER, - .map = uac3_badd_headset_map, - }, - { - .id = UAC3_FUNCTION_SUBCLASS_SPEAKERPHONE, - .map = uac3_badd_speakerphone_map, - }, - { 0 } /* terminator */ -}; diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index f02bf158022a..4ba21e9ca2d1 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -29,7 +29,6 @@ #include <linux/hid.h> #include <linux/init.h> -#include <linux/math64.h> #include <linux/slab.h> #include <linux/usb.h> #include <linux/usb/audio.h> @@ -48,6 +47,8 @@ #include "mixer_us16x08.h" #include "helper.h" +extern struct snd_kcontrol_new *snd_usb_feature_unit_ctl; + struct std_mono_table { unsigned int unitid, control, cmask; int val_type; @@ -362,7 +363,7 @@ static int snd_audigy2nx_led_resume(struct usb_mixer_elem_list *list) } /* name and private_value are set dynamically */ -static const struct snd_kcontrol_new snd_audigy2nx_control = { +static struct snd_kcontrol_new snd_audigy2nx_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .info = snd_audigy2nx_led_info, .get = snd_audigy2nx_led_get, @@ -1171,7 +1172,7 @@ void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, int unitid = 12; /* SamleRate ExtensionUnit ID */ list_for_each_entry(mixer, &chip->mixer_list, list) { - cval = mixer_elem_list_to_info(mixer->id_elems[unitid]); + cval = (struct usb_mixer_elem_info *)mixer->id_elems[unitid]; if (cval) { snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, cval->control << 8, @@ -1818,387 +1819,12 @@ static int dell_dock_mixer_init(struct usb_mixer_interface *mixer) return 0; } -/* RME Class Compliant device quirks */ - -#define SND_RME_GET_STATUS1 23 -#define SND_RME_GET_CURRENT_FREQ 17 -#define SND_RME_CLK_SYSTEM_SHIFT 16 -#define SND_RME_CLK_SYSTEM_MASK 0x1f -#define SND_RME_CLK_AES_SHIFT 8 -#define SND_RME_CLK_SPDIF_SHIFT 12 -#define SND_RME_CLK_AES_SPDIF_MASK 0xf -#define SND_RME_CLK_SYNC_SHIFT 6 -#define SND_RME_CLK_SYNC_MASK 0x3 -#define SND_RME_CLK_FREQMUL_SHIFT 18 -#define SND_RME_CLK_FREQMUL_MASK 0x7 -#define SND_RME_CLK_SYSTEM(x) \ - ((x >> SND_RME_CLK_SYSTEM_SHIFT) & SND_RME_CLK_SYSTEM_MASK) -#define SND_RME_CLK_AES(x) \ - ((x >> SND_RME_CLK_AES_SHIFT) & SND_RME_CLK_AES_SPDIF_MASK) -#define SND_RME_CLK_SPDIF(x) \ - ((x >> SND_RME_CLK_SPDIF_SHIFT) & SND_RME_CLK_AES_SPDIF_MASK) -#define SND_RME_CLK_SYNC(x) \ - ((x >> SND_RME_CLK_SYNC_SHIFT) & SND_RME_CLK_SYNC_MASK) -#define SND_RME_CLK_FREQMUL(x) \ - ((x >> SND_RME_CLK_FREQMUL_SHIFT) & SND_RME_CLK_FREQMUL_MASK) -#define SND_RME_CLK_AES_LOCK 0x1 -#define SND_RME_CLK_AES_SYNC 0x4 -#define SND_RME_CLK_SPDIF_LOCK 0x2 -#define SND_RME_CLK_SPDIF_SYNC 0x8 -#define SND_RME_SPDIF_IF_SHIFT 4 -#define SND_RME_SPDIF_FORMAT_SHIFT 5 -#define SND_RME_BINARY_MASK 0x1 -#define SND_RME_SPDIF_IF(x) \ - ((x >> SND_RME_SPDIF_IF_SHIFT) & SND_RME_BINARY_MASK) -#define SND_RME_SPDIF_FORMAT(x) \ - ((x >> SND_RME_SPDIF_FORMAT_SHIFT) & SND_RME_BINARY_MASK) - -static const u32 snd_rme_rate_table[] = { - 32000, 44100, 48000, 50000, - 64000, 88200, 96000, 100000, - 128000, 176400, 192000, 200000, - 256000, 352800, 384000, 400000, - 512000, 705600, 768000, 800000 -}; -/* maximum number of items for AES and S/PDIF rates for above table */ -#define SND_RME_RATE_IDX_AES_SPDIF_NUM 12 - -enum snd_rme_domain { - SND_RME_DOMAIN_SYSTEM, - SND_RME_DOMAIN_AES, - SND_RME_DOMAIN_SPDIF -}; - -enum snd_rme_clock_status { - SND_RME_CLOCK_NOLOCK, - SND_RME_CLOCK_LOCK, - SND_RME_CLOCK_SYNC -}; - -static int snd_rme_read_value(struct snd_usb_audio *chip, - unsigned int item, - u32 *value) -{ - struct usb_device *dev = chip->dev; - int err; - - err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), - item, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, 0, - value, sizeof(*value)); - if (err < 0) - dev_err(&dev->dev, - "unable to issue vendor read request %d (ret = %d)", - item, err); - return err; -} - -static int snd_rme_get_status1(struct snd_kcontrol *kcontrol, - u32 *status1) -{ - struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); - struct snd_usb_audio *chip = list->mixer->chip; - int err; - - err = snd_usb_lock_shutdown(chip); - if (err < 0) - return err; - err = snd_rme_read_value(chip, SND_RME_GET_STATUS1, status1); - snd_usb_unlock_shutdown(chip); - return err; -} - -static int snd_rme_rate_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - u32 status1; - u32 rate = 0; - int idx; - int err; - - err = snd_rme_get_status1(kcontrol, &status1); - if (err < 0) - return err; - switch (kcontrol->private_value) { - case SND_RME_DOMAIN_SYSTEM: - idx = SND_RME_CLK_SYSTEM(status1); - if (idx < ARRAY_SIZE(snd_rme_rate_table)) - rate = snd_rme_rate_table[idx]; - break; - case SND_RME_DOMAIN_AES: - idx = SND_RME_CLK_AES(status1); - if (idx < SND_RME_RATE_IDX_AES_SPDIF_NUM) - rate = snd_rme_rate_table[idx]; - break; - case SND_RME_DOMAIN_SPDIF: - idx = SND_RME_CLK_SPDIF(status1); - if (idx < SND_RME_RATE_IDX_AES_SPDIF_NUM) - rate = snd_rme_rate_table[idx]; - break; - default: - return -EINVAL; - } - ucontrol->value.integer.value[0] = rate; - return 0; -} - -static int snd_rme_sync_state_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - u32 status1; - int idx = SND_RME_CLOCK_NOLOCK; - int err; - - err = snd_rme_get_status1(kcontrol, &status1); - if (err < 0) - return err; - switch (kcontrol->private_value) { - case SND_RME_DOMAIN_AES: /* AES */ - if (status1 & SND_RME_CLK_AES_SYNC) - idx = SND_RME_CLOCK_SYNC; - else if (status1 & SND_RME_CLK_AES_LOCK) - idx = SND_RME_CLOCK_LOCK; - break; - case SND_RME_DOMAIN_SPDIF: /* SPDIF */ - if (status1 & SND_RME_CLK_SPDIF_SYNC) - idx = SND_RME_CLOCK_SYNC; - else if (status1 & SND_RME_CLK_SPDIF_LOCK) - idx = SND_RME_CLOCK_LOCK; - break; - default: - return -EINVAL; - } - ucontrol->value.enumerated.item[0] = idx; - return 0; -} - -static int snd_rme_spdif_if_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - u32 status1; - int err; - - err = snd_rme_get_status1(kcontrol, &status1); - if (err < 0) - return err; - ucontrol->value.enumerated.item[0] = SND_RME_SPDIF_IF(status1); - return 0; -} - -static int snd_rme_spdif_format_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - u32 status1; - int err; - - err = snd_rme_get_status1(kcontrol, &status1); - if (err < 0) - return err; - ucontrol->value.enumerated.item[0] = SND_RME_SPDIF_FORMAT(status1); - return 0; -} - -static int snd_rme_sync_source_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - u32 status1; - int err; - - err = snd_rme_get_status1(kcontrol, &status1); - if (err < 0) - return err; - ucontrol->value.enumerated.item[0] = SND_RME_CLK_SYNC(status1); - return 0; -} - -static int snd_rme_current_freq_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol); - struct snd_usb_audio *chip = list->mixer->chip; - u32 status1; - const u64 num = 104857600000000ULL; - u32 den; - unsigned int freq; - int err; - - err = snd_usb_lock_shutdown(chip); - if (err < 0) - return err; - err = snd_rme_read_value(chip, SND_RME_GET_STATUS1, &status1); - if (err < 0) - goto end; - err = snd_rme_read_value(chip, SND_RME_GET_CURRENT_FREQ, &den); - if (err < 0) - goto end; - freq = (den == 0) ? 0 : div64_u64(num, den); - freq <<= SND_RME_CLK_FREQMUL(status1); - ucontrol->value.integer.value[0] = freq; - -end: - snd_usb_unlock_shutdown(chip); - return err; -} - -static int snd_rme_rate_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - switch (kcontrol->private_value) { - case SND_RME_DOMAIN_SYSTEM: - uinfo->value.integer.min = 32000; - uinfo->value.integer.max = 800000; - break; - case SND_RME_DOMAIN_AES: - case SND_RME_DOMAIN_SPDIF: - default: - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 200000; - } - uinfo->value.integer.step = 0; - return 0; -} - -static int snd_rme_sync_state_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static const char *const sync_states[] = { - "No Lock", "Lock", "Sync" - }; - - return snd_ctl_enum_info(uinfo, 1, - ARRAY_SIZE(sync_states), sync_states); -} - -static int snd_rme_spdif_if_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static const char *const spdif_if[] = { - "Coaxial", "Optical" - }; - - return snd_ctl_enum_info(uinfo, 1, - ARRAY_SIZE(spdif_if), spdif_if); -} - -static int snd_rme_spdif_format_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static const char *const optical_type[] = { - "Consumer", "Professional" - }; - - return snd_ctl_enum_info(uinfo, 1, - ARRAY_SIZE(optical_type), optical_type); -} - -static int snd_rme_sync_source_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static const char *const sync_sources[] = { - "Internal", "AES", "SPDIF", "Internal" - }; - - return snd_ctl_enum_info(uinfo, 1, - ARRAY_SIZE(sync_sources), sync_sources); -} - -static struct snd_kcontrol_new snd_rme_controls[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "AES Rate", - .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, - .info = snd_rme_rate_info, - .get = snd_rme_rate_get, - .private_value = SND_RME_DOMAIN_AES - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "AES Sync", - .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, - .info = snd_rme_sync_state_info, - .get = snd_rme_sync_state_get, - .private_value = SND_RME_DOMAIN_AES - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "SPDIF Rate", - .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, - .info = snd_rme_rate_info, - .get = snd_rme_rate_get, - .private_value = SND_RME_DOMAIN_SPDIF - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "SPDIF Sync", - .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, - .info = snd_rme_sync_state_info, - .get = snd_rme_sync_state_get, - .private_value = SND_RME_DOMAIN_SPDIF - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "SPDIF Interface", - .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, - .info = snd_rme_spdif_if_info, - .get = snd_rme_spdif_if_get, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "SPDIF Format", - .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, - .info = snd_rme_spdif_format_info, - .get = snd_rme_spdif_format_get, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Sync Source", - .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, - .info = snd_rme_sync_source_info, - .get = snd_rme_sync_source_get - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "System Rate", - .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, - .info = snd_rme_rate_info, - .get = snd_rme_rate_get, - .private_value = SND_RME_DOMAIN_SYSTEM - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Current Frequency", - .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, - .info = snd_rme_rate_info, - .get = snd_rme_current_freq_get - } -}; - -static int snd_rme_controls_create(struct usb_mixer_interface *mixer) -{ - int err, i; - - for (i = 0; i < ARRAY_SIZE(snd_rme_controls); ++i) { - err = add_single_ctl_with_resume(mixer, 0, - NULL, - &snd_rme_controls[i], - NULL); - if (err < 0) - return err; - } - - return 0; -} - int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) { int err = 0; struct snd_info_entry *entry; - err = snd_usb_soundblaster_remote_init(mixer); - if (err < 0) + if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0) return err; switch (mixer->chip->usb_id) { @@ -2222,6 +1848,8 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) /* EMU0204 */ case USB_ID(0x041e, 0x3f19): err = snd_emu0204_controls_create(mixer); + if (err < 0) + break; break; case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */ @@ -2279,12 +1907,6 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) case USB_ID(0x0bda, 0x4014): /* Dell WD15 dock */ err = dell_dock_mixer_init(mixer); break; - - case USB_ID(0x2a39, 0x3fd2): /* RME ADI-2 Pro */ - case USB_ID(0x2a39, 0x3fd3): /* RME ADI-2 DAC */ - case USB_ID(0x2a39, 0x3fd4): /* RME */ - err = snd_rme_controls_create(mixer); - break; } return err; diff --git a/sound/usb/mixer_scarlett.c b/sound/usb/mixer_scarlett.c index 4aeb9488a0c9..c33e2378089d 100644 --- a/sound/usb/mixer_scarlett.c +++ b/sound/usb/mixer_scarlett.c @@ -287,7 +287,8 @@ static int scarlett_ctl_switch_put(struct snd_kcontrol *kctl, static int scarlett_ctl_resume(struct usb_mixer_elem_list *list) { - struct usb_mixer_elem_info *elem = mixer_elem_list_to_info(list); + struct usb_mixer_elem_info *elem = + container_of(list, struct usb_mixer_elem_info, head); int i; for (i = 0; i < elem->channels; i++) @@ -446,7 +447,8 @@ static int scarlett_ctl_enum_put(struct snd_kcontrol *kctl, static int scarlett_ctl_enum_resume(struct usb_mixer_elem_list *list) { - struct usb_mixer_elem_info *elem = mixer_elem_list_to_info(list); + struct usb_mixer_elem_info *elem = + container_of(list, struct usb_mixer_elem_info, head); if (elem->cached) snd_usb_set_cur_mix_value(elem, 0, 0, *elem->cache_val); diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 6c15a474b10b..ca26f1dfa52f 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -76,9 +76,10 @@ snd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs, */ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream) { - struct snd_usb_substream *subs = substream->runtime->private_data; + struct snd_usb_substream *subs; unsigned int hwptr_done; + subs = (struct snd_usb_substream *)substream->runtime->private_data; if (atomic_read(&subs->stream->chip->shutdown)) return SNDRV_PCM_POS_XRUN; spin_lock(&subs->lock); @@ -163,11 +164,10 @@ static int init_pitch_v1(struct snd_usb_audio *chip, int iface, ep = get_endpoint(alts, 0)->bEndpointAddress; data[0] = 1; - err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, - USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, - UAC_EP_CS_ATTR_PITCH_CONTROL << 8, ep, - data, sizeof(data)); - if (err < 0) { + if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, + USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, + UAC_EP_CS_ATTR_PITCH_CONTROL << 8, ep, + data, sizeof(data))) < 0) { usb_audio_err(chip, "%d:%d: cannot set enable PITCH\n", iface, ep); return err; @@ -185,11 +185,10 @@ static int init_pitch_v2(struct snd_usb_audio *chip, int iface, int err; data[0] = 1; - err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR, - USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT, - UAC2_EP_CS_PITCH << 8, 0, - data, sizeof(data)); - if (err < 0) { + if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR, + USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT, + UAC2_EP_CS_PITCH << 8, 0, + data, sizeof(data))) < 0) { usb_audio_err(chip, "%d:%d: cannot set enable PITCH (v2)\n", iface, fmt->altsetting); return err; @@ -343,10 +342,6 @@ static int set_sync_ep_implicit_fb_quirk(struct snd_usb_substream *subs, ep = 0x86; ifnum = 2; goto add_sync_ep_from_ifnum; - case USB_ID(0x2466, 0x8010): /* Fractal Audio Axe-Fx III */ - ep = 0x81; - ifnum = 2; - goto add_sync_ep_from_ifnum; case USB_ID(0x1397, 0x0002): /* Behringer UFX1204 */ ep = 0x81; ifnum = 1; @@ -711,54 +706,6 @@ static int configure_endpoint(struct snd_usb_substream *subs) return ret; } -static int snd_usb_pcm_change_state(struct snd_usb_substream *subs, int state) -{ - int ret; - - if (!subs->str_pd) - return 0; - - ret = snd_usb_power_domain_set(subs->stream->chip, subs->str_pd, state); - if (ret < 0) { - dev_err(&subs->dev->dev, - "Cannot change Power Domain ID: %d to state: %d. Err: %d\n", - subs->str_pd->pd_id, state, ret); - return ret; - } - - return 0; -} - -int snd_usb_pcm_suspend(struct snd_usb_stream *as) -{ - int ret; - - ret = snd_usb_pcm_change_state(&as->substream[0], UAC3_PD_STATE_D2); - if (ret < 0) - return ret; - - ret = snd_usb_pcm_change_state(&as->substream[1], UAC3_PD_STATE_D2); - if (ret < 0) - return ret; - - return 0; -} - -int snd_usb_pcm_resume(struct snd_usb_stream *as) -{ - int ret; - - ret = snd_usb_pcm_change_state(&as->substream[0], UAC3_PD_STATE_D1); - if (ret < 0) - return ret; - - ret = snd_usb_pcm_change_state(&as->substream[1], UAC3_PD_STATE_D1); - if (ret < 0) - return ret; - - return 0; -} - /* * hw_params callback * @@ -776,11 +723,7 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, struct audioformat *fmt; int ret; - if (snd_usb_use_vmalloc) - ret = snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); - else - ret = snd_pcm_lib_malloc_pages(substream, + ret = snd_pcm_lib_alloc_vmalloc_buffer(substream, params_buffer_bytes(hw_params)); if (ret < 0) return ret; @@ -803,22 +746,16 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, ret = snd_usb_lock_shutdown(subs->stream->chip); if (ret < 0) return ret; - - ret = snd_usb_pcm_change_state(subs, UAC3_PD_STATE_D0); - if (ret < 0) - goto unlock; - ret = set_format(subs, fmt); + snd_usb_unlock_shutdown(subs->stream->chip); if (ret < 0) - goto unlock; + return ret; subs->interface = fmt->iface; subs->altset_idx = fmt->altset_idx; subs->need_setup_ep = true; - unlock: - snd_usb_unlock_shutdown(subs->stream->chip); - return ret; + return 0; } /* @@ -839,11 +776,7 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream) snd_usb_endpoint_deactivate(subs->data_endpoint); snd_usb_unlock_shutdown(subs->stream->chip); } - - if (snd_usb_use_vmalloc) - return snd_pcm_lib_free_vmalloc_buffer(substream); - else - return snd_pcm_lib_free_pages(substream); + return snd_pcm_lib_free_vmalloc_buffer(substream); } /* @@ -875,10 +808,6 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) snd_usb_endpoint_sync_pending_stop(subs->sync_endpoint); snd_usb_endpoint_sync_pending_stop(subs->data_endpoint); - ret = snd_usb_pcm_change_state(subs, UAC3_PD_STATE_D0); - if (ret < 0) - goto unlock; - ret = set_format(subs, subs->cur_audiofmt); if (ret < 0) goto unlock; @@ -1239,6 +1168,9 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre pt = 125 * (1 << fp->datainterval); ptmin = min(ptmin, pt); } + err = snd_usb_autoresume(subs->stream->chip); + if (err < 0) + return err; param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME; if (subs->speed == USB_SPEED_FULL) @@ -1247,37 +1179,30 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre if (ptmin == 1000) /* if period time doesn't go below 1 ms, no rules needed */ param_period_time_if_needed = -1; - - err = snd_pcm_hw_constraint_minmax(runtime, - SNDRV_PCM_HW_PARAM_PERIOD_TIME, - ptmin, UINT_MAX); - if (err < 0) - return err; - - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - hw_rule_rate, subs, - SNDRV_PCM_HW_PARAM_FORMAT, - SNDRV_PCM_HW_PARAM_CHANNELS, - param_period_time_if_needed, - -1); - if (err < 0) - return err; - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - hw_rule_channels, subs, - SNDRV_PCM_HW_PARAM_FORMAT, - SNDRV_PCM_HW_PARAM_RATE, - param_period_time_if_needed, - -1); - if (err < 0) - return err; - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, - hw_rule_format, subs, - SNDRV_PCM_HW_PARAM_RATE, - SNDRV_PCM_HW_PARAM_CHANNELS, - param_period_time_if_needed, - -1); - if (err < 0) - return err; + snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, + ptmin, UINT_MAX); + + if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + hw_rule_rate, subs, + SNDRV_PCM_HW_PARAM_FORMAT, + SNDRV_PCM_HW_PARAM_CHANNELS, + param_period_time_if_needed, + -1)) < 0) + goto rep_err; + if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + hw_rule_channels, subs, + SNDRV_PCM_HW_PARAM_FORMAT, + SNDRV_PCM_HW_PARAM_RATE, + param_period_time_if_needed, + -1)) < 0) + goto rep_err; + if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, + hw_rule_format, subs, + SNDRV_PCM_HW_PARAM_RATE, + SNDRV_PCM_HW_PARAM_CHANNELS, + param_period_time_if_needed, + -1)) < 0) + goto rep_err; if (param_period_time_if_needed >= 0) { err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_TIME, @@ -1287,18 +1212,19 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre SNDRV_PCM_HW_PARAM_RATE, -1); if (err < 0) - return err; + goto rep_err; } - err = snd_usb_pcm_check_knot(runtime, subs); - if (err < 0) - return err; + if ((err = snd_usb_pcm_check_knot(runtime, subs)) < 0) + goto rep_err; + return 0; - return snd_usb_autoresume(subs->stream->chip); +rep_err: + snd_usb_autosuspend(subs->stream->chip); + return err; } -static int snd_usb_pcm_open(struct snd_pcm_substream *substream) +static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction) { - int direction = substream->stream; struct snd_usb_stream *as = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct snd_usb_substream *subs = &as->substream[direction]; @@ -1318,12 +1244,10 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream) return setup_hw_info(runtime, subs); } -static int snd_usb_pcm_close(struct snd_pcm_substream *substream) +static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction) { - int direction = substream->stream; struct snd_usb_stream *as = snd_pcm_substream_chip(substream); struct snd_usb_substream *subs = &as->substream[direction]; - int ret; stop_endpoints(subs, true); @@ -1332,10 +1256,7 @@ static int snd_usb_pcm_close(struct snd_pcm_substream *substream) !snd_usb_lock_shutdown(subs->stream->chip)) { usb_set_interface(subs->dev, subs->interface, 0); subs->interface = -1; - ret = snd_usb_pcm_change_state(subs, UAC3_PD_STATE_D1); snd_usb_unlock_shutdown(subs->stream->chip); - if (ret < 0) - return ret; } subs->pcm_substream = NULL; @@ -1686,6 +1607,26 @@ static void retire_playback_urb(struct snd_usb_substream *subs, spin_unlock_irqrestore(&subs->lock, flags); } +static int snd_usb_playback_open(struct snd_pcm_substream *substream) +{ + return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_PLAYBACK); +} + +static int snd_usb_playback_close(struct snd_pcm_substream *substream) +{ + return snd_usb_pcm_close(substream, SNDRV_PCM_STREAM_PLAYBACK); +} + +static int snd_usb_capture_open(struct snd_pcm_substream *substream) +{ + return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_CAPTURE); +} + +static int snd_usb_capture_close(struct snd_pcm_substream *substream) +{ + return snd_usb_pcm_close(substream, SNDRV_PCM_STREAM_CAPTURE); +} + static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, int cmd) { @@ -1694,7 +1635,6 @@ static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substrea switch (cmd) { case SNDRV_PCM_TRIGGER_START: subs->trigger_tstamp_pending_update = true; - /* fall through */ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: subs->data_endpoint->prepare_data_urb = prepare_playback_urb; subs->data_endpoint->retire_data_urb = retire_playback_urb; @@ -1747,9 +1687,9 @@ static int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream return -EINVAL; } -static const struct snd_pcm_ops snd_usb_playback_ops = { - .open = snd_usb_pcm_open, - .close = snd_usb_pcm_close, +static struct snd_pcm_ops snd_usb_playback_ops = { + .open = snd_usb_playback_open, + .close = snd_usb_playback_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_usb_hw_params, .hw_free = snd_usb_hw_free, @@ -1760,9 +1700,9 @@ static const struct snd_pcm_ops snd_usb_playback_ops = { .mmap = snd_pcm_lib_mmap_vmalloc, }; -static const struct snd_pcm_ops snd_usb_capture_ops = { - .open = snd_usb_pcm_open, - .close = snd_usb_pcm_close, +static struct snd_pcm_ops snd_usb_capture_ops = { + .open = snd_usb_capture_open, + .close = snd_usb_capture_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_usb_hw_params, .hw_free = snd_usb_hw_free, @@ -1773,50 +1713,9 @@ static const struct snd_pcm_ops snd_usb_capture_ops = { .mmap = snd_pcm_lib_mmap_vmalloc, }; -static const struct snd_pcm_ops snd_usb_playback_dev_ops = { - .open = snd_usb_pcm_open, - .close = snd_usb_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_usb_hw_params, - .hw_free = snd_usb_hw_free, - .prepare = snd_usb_pcm_prepare, - .trigger = snd_usb_substream_playback_trigger, - .pointer = snd_usb_pcm_pointer, - .page = snd_pcm_sgbuf_ops_page, -}; - -static const struct snd_pcm_ops snd_usb_capture_dev_ops = { - .open = snd_usb_pcm_open, - .close = snd_usb_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_usb_hw_params, - .hw_free = snd_usb_hw_free, - .prepare = snd_usb_pcm_prepare, - .trigger = snd_usb_substream_capture_trigger, - .pointer = snd_usb_pcm_pointer, - .page = snd_pcm_sgbuf_ops_page, -}; - void snd_usb_set_pcm_ops(struct snd_pcm *pcm, int stream) { - const struct snd_pcm_ops *ops; - - if (snd_usb_use_vmalloc) - ops = stream == SNDRV_PCM_STREAM_PLAYBACK ? - &snd_usb_playback_ops : &snd_usb_capture_ops; - else - ops = stream == SNDRV_PCM_STREAM_PLAYBACK ? - &snd_usb_playback_dev_ops : &snd_usb_capture_dev_ops; - snd_pcm_set_ops(pcm, stream, ops); -} - -void snd_usb_preallocate_buffer(struct snd_usb_substream *subs) -{ - struct snd_pcm *pcm = subs->stream->pcm; - struct snd_pcm_substream *s = pcm->streams[subs->direction].substream; - struct device *dev = subs->dev->bus->controller; - - if (!snd_usb_use_vmalloc) - snd_pcm_lib_preallocate_pages(s, SNDRV_DMA_TYPE_DEV_SG, - dev, 64*1024, 512*1024); + snd_pcm_set_ops(pcm, stream, + stream == SNDRV_PCM_STREAM_PLAYBACK ? + &snd_usb_playback_ops : &snd_usb_capture_ops); } diff --git a/sound/usb/pcm.h b/sound/usb/pcm.h index ec89a93ab1f9..df7a003682ad 100644 --- a/sound/usb/pcm.h +++ b/sound/usb/pcm.h @@ -5,13 +5,10 @@ snd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs, unsigned int rate); void snd_usb_set_pcm_ops(struct snd_pcm *pcm, int stream); -int snd_usb_pcm_suspend(struct snd_usb_stream *as); -int snd_usb_pcm_resume(struct snd_usb_stream *as); int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface, struct usb_host_interface *alts, struct audioformat *fmt); -void snd_usb_preallocate_buffer(struct snd_usb_substream *subs); #endif /* __USBAUDIO_PCM_H */ diff --git a/sound/usb/power.c b/sound/usb/power.c deleted file mode 100644 index bd303a1ba1b7..000000000000 --- a/sound/usb/power.c +++ /dev/null @@ -1,104 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * UAC3 Power Domain state management functions - */ - -#include <linux/slab.h> -#include <linux/usb.h> -#include <linux/usb/audio.h> -#include <linux/usb/audio-v2.h> -#include <linux/usb/audio-v3.h> - -#include "usbaudio.h" -#include "helper.h" -#include "power.h" - -struct snd_usb_power_domain * -snd_usb_find_power_domain(struct usb_host_interface *ctrl_iface, - unsigned char id) -{ - struct snd_usb_power_domain *pd; - void *p; - - pd = kzalloc(sizeof(*pd), GFP_KERNEL); - if (!pd) - return NULL; - - p = NULL; - while ((p = snd_usb_find_csint_desc(ctrl_iface->extra, - ctrl_iface->extralen, - p, UAC3_POWER_DOMAIN)) != NULL) { - struct uac3_power_domain_descriptor *pd_desc = p; - int i; - - for (i = 0; i < pd_desc->bNrEntities; i++) { - if (pd_desc->baEntityID[i] == id) { - pd->pd_id = pd_desc->bPowerDomainID; - pd->pd_d1d0_rec = - le16_to_cpu(pd_desc->waRecoveryTime1); - pd->pd_d2d0_rec = - le16_to_cpu(pd_desc->waRecoveryTime2); - return pd; - } - } - } - - kfree(pd); - return NULL; -} - -int snd_usb_power_domain_set(struct snd_usb_audio *chip, - struct snd_usb_power_domain *pd, - unsigned char state) -{ - struct usb_device *dev = chip->dev; - unsigned char current_state; - int err, idx; - - idx = snd_usb_ctrl_intf(chip) | (pd->pd_id << 8); - - err = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), - UAC2_CS_CUR, - USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - UAC3_AC_POWER_DOMAIN_CONTROL << 8, idx, - ¤t_state, sizeof(current_state)); - if (err < 0) { - dev_err(&dev->dev, "Can't get UAC3 power state for id %d\n", - pd->pd_id); - return err; - } - - if (current_state == state) { - dev_dbg(&dev->dev, "UAC3 power domain id %d already in state %d\n", - pd->pd_id, state); - return 0; - } - - err = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), UAC2_CS_CUR, - USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, - UAC3_AC_POWER_DOMAIN_CONTROL << 8, idx, - &state, sizeof(state)); - if (err < 0) { - dev_err(&dev->dev, "Can't set UAC3 power state to %d for id %d\n", - state, pd->pd_id); - return err; - } - - if (state == UAC3_PD_STATE_D0) { - switch (current_state) { - case UAC3_PD_STATE_D2: - udelay(pd->pd_d2d0_rec * 50); - break; - case UAC3_PD_STATE_D1: - udelay(pd->pd_d1d0_rec * 50); - break; - default: - return -EINVAL; - } - } - - dev_dbg(&dev->dev, "UAC3 power domain id %d change to state %d\n", - pd->pd_id, state); - - return 0; -} diff --git a/sound/usb/power.h b/sound/usb/power.h index bbd549691e69..48ee51dcb71e 100644 --- a/sound/usb/power.h +++ b/sound/usb/power.h @@ -1,25 +1,6 @@ #ifndef __USBAUDIO_POWER_H #define __USBAUDIO_POWER_H -struct snd_usb_power_domain { - int pd_id; /* UAC3 Power Domain ID */ - int pd_d1d0_rec; /* D1 to D0 recovery time */ - int pd_d2d0_rec; /* D2 to D0 recovery time */ -}; - -enum { - UAC3_PD_STATE_D0, - UAC3_PD_STATE_D1, - UAC3_PD_STATE_D2, -}; - -int snd_usb_power_domain_set(struct snd_usb_audio *chip, - struct snd_usb_power_domain *pd, - unsigned char state); -struct snd_usb_power_domain * -snd_usb_find_power_domain(struct usb_host_interface *ctrl_iface, - unsigned char id); - #ifdef CONFIG_PM int snd_usb_autoresume(struct snd_usb_audio *chip); void snd_usb_autosuspend(struct snd_usb_audio *chip); diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index c50e86fe9bcc..fffd7cccce2c 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -19,7 +19,6 @@ #include <linux/usb.h> #include <linux/usb/audio.h> #include <linux/usb/midi.h> -#include <linux/bits.h> #include <sound/control.h> #include <sound/core.h> @@ -670,133 +669,15 @@ static int snd_usb_cm106_boot_quirk(struct usb_device *dev) } /* - * CM6206 registers from the CM6206 datasheet rev 2.1 + * C-Media CM6206 is based on CM106 with two additional + * registers that are not documented in the data sheet. + * Values here are chosen based on sniffing USB traffic + * under Windows. */ -#define CM6206_REG0_DMA_MASTER BIT(15) -#define CM6206_REG0_SPDIFO_RATE_48K (2 << 12) -#define CM6206_REG0_SPDIFO_RATE_96K (7 << 12) -/* Bit 4 thru 11 is the S/PDIF category code */ -#define CM6206_REG0_SPDIFO_CAT_CODE_GENERAL (0 << 4) -#define CM6206_REG0_SPDIFO_EMPHASIS_CD BIT(3) -#define CM6206_REG0_SPDIFO_COPYRIGHT_NA BIT(2) -#define CM6206_REG0_SPDIFO_NON_AUDIO BIT(1) -#define CM6206_REG0_SPDIFO_PRO_FORMAT BIT(0) - -#define CM6206_REG1_TEST_SEL_CLK BIT(14) -#define CM6206_REG1_PLLBIN_EN BIT(13) -#define CM6206_REG1_SOFT_MUTE_EN BIT(12) -#define CM6206_REG1_GPIO4_OUT BIT(11) -#define CM6206_REG1_GPIO4_OE BIT(10) -#define CM6206_REG1_GPIO3_OUT BIT(9) -#define CM6206_REG1_GPIO3_OE BIT(8) -#define CM6206_REG1_GPIO2_OUT BIT(7) -#define CM6206_REG1_GPIO2_OE BIT(6) -#define CM6206_REG1_GPIO1_OUT BIT(5) -#define CM6206_REG1_GPIO1_OE BIT(4) -#define CM6206_REG1_SPDIFO_INVALID BIT(3) -#define CM6206_REG1_SPDIF_LOOP_EN BIT(2) -#define CM6206_REG1_SPDIFO_DIS BIT(1) -#define CM6206_REG1_SPDIFI_MIX BIT(0) - -#define CM6206_REG2_DRIVER_ON BIT(15) -#define CM6206_REG2_HEADP_SEL_SIDE_CHANNELS (0 << 13) -#define CM6206_REG2_HEADP_SEL_SURROUND_CHANNELS (1 << 13) -#define CM6206_REG2_HEADP_SEL_CENTER_SUBW (2 << 13) -#define CM6206_REG2_HEADP_SEL_FRONT_CHANNELS (3 << 13) -#define CM6206_REG2_MUTE_HEADPHONE_RIGHT BIT(12) -#define CM6206_REG2_MUTE_HEADPHONE_LEFT BIT(11) -#define CM6206_REG2_MUTE_REAR_SURROUND_RIGHT BIT(10) -#define CM6206_REG2_MUTE_REAR_SURROUND_LEFT BIT(9) -#define CM6206_REG2_MUTE_SIDE_SURROUND_RIGHT BIT(8) -#define CM6206_REG2_MUTE_SIDE_SURROUND_LEFT BIT(7) -#define CM6206_REG2_MUTE_SUBWOOFER BIT(6) -#define CM6206_REG2_MUTE_CENTER BIT(5) -#define CM6206_REG2_MUTE_RIGHT_FRONT BIT(3) -#define CM6206_REG2_MUTE_LEFT_FRONT BIT(3) -#define CM6206_REG2_EN_BTL BIT(2) -#define CM6206_REG2_MCUCLKSEL_1_5_MHZ (0) -#define CM6206_REG2_MCUCLKSEL_3_MHZ (1) -#define CM6206_REG2_MCUCLKSEL_6_MHZ (2) -#define CM6206_REG2_MCUCLKSEL_12_MHZ (3) - -/* Bit 11..13 sets the sensitivity to FLY tuner volume control VP/VD signal */ -#define CM6206_REG3_FLYSPEED_DEFAULT (2 << 11) -#define CM6206_REG3_VRAP25EN BIT(10) -#define CM6206_REG3_MSEL1 BIT(9) -#define CM6206_REG3_SPDIFI_RATE_44_1K BIT(0 << 7) -#define CM6206_REG3_SPDIFI_RATE_48K BIT(2 << 7) -#define CM6206_REG3_SPDIFI_RATE_32K BIT(3 << 7) -#define CM6206_REG3_PINSEL BIT(6) -#define CM6206_REG3_FOE BIT(5) -#define CM6206_REG3_ROE BIT(4) -#define CM6206_REG3_CBOE BIT(3) -#define CM6206_REG3_LOSE BIT(2) -#define CM6206_REG3_HPOE BIT(1) -#define CM6206_REG3_SPDIFI_CANREC BIT(0) - -#define CM6206_REG5_DA_RSTN BIT(13) -#define CM6206_REG5_AD_RSTN BIT(12) -#define CM6206_REG5_SPDIFO_AD2SPDO BIT(12) -#define CM6206_REG5_SPDIFO_SEL_FRONT (0 << 9) -#define CM6206_REG5_SPDIFO_SEL_SIDE_SUR (1 << 9) -#define CM6206_REG5_SPDIFO_SEL_CEN_LFE (2 << 9) -#define CM6206_REG5_SPDIFO_SEL_REAR_SUR (3 << 9) -#define CM6206_REG5_CODECM BIT(8) -#define CM6206_REG5_EN_HPF BIT(7) -#define CM6206_REG5_T_SEL_DSDA4 BIT(6) -#define CM6206_REG5_T_SEL_DSDA3 BIT(5) -#define CM6206_REG5_T_SEL_DSDA2 BIT(4) -#define CM6206_REG5_T_SEL_DSDA1 BIT(3) -#define CM6206_REG5_T_SEL_DSDAD_NORMAL 0 -#define CM6206_REG5_T_SEL_DSDAD_FRONT 4 -#define CM6206_REG5_T_SEL_DSDAD_S_SURROUND 5 -#define CM6206_REG5_T_SEL_DSDAD_CEN_LFE 6 -#define CM6206_REG5_T_SEL_DSDAD_R_SURROUND 7 - static int snd_usb_cm6206_boot_quirk(struct usb_device *dev) { int err = 0, reg; - int val[] = { - /* - * Values here are chosen based on sniffing USB traffic - * under Windows. - * - * REG0: DAC is master, sample rate 48kHz, no copyright - */ - CM6206_REG0_SPDIFO_RATE_48K | - CM6206_REG0_SPDIFO_COPYRIGHT_NA, - /* - * REG1: PLL binary search enable, soft mute enable. - */ - CM6206_REG1_PLLBIN_EN | - CM6206_REG1_SOFT_MUTE_EN | - /* - * REG2: enable output drivers, - * select front channels to the headphone output, - * then mute the headphone channels, run the MCU - * at 1.5 MHz. - */ - CM6206_REG2_DRIVER_ON | - CM6206_REG2_HEADP_SEL_FRONT_CHANNELS | - CM6206_REG2_MUTE_HEADPHONE_RIGHT | - CM6206_REG2_MUTE_HEADPHONE_LEFT, - /* - * REG3: default flyspeed, set 2.5V mic bias - * enable all line out ports and enable SPDIF - */ - CM6206_REG3_FLYSPEED_DEFAULT | - CM6206_REG3_VRAP25EN | - CM6206_REG3_FOE | - CM6206_REG3_ROE | - CM6206_REG3_CBOE | - CM6206_REG3_LOSE | - CM6206_REG3_HPOE | - CM6206_REG3_SPDIFI_CANREC, - /* REG4 is just a bunch of GPIO lines */ - 0x0000, - /* REG5: de-assert AD/DA reset signals */ - CM6206_REG5_DA_RSTN | - CM6206_REG5_AD_RSTN }; + int val[] = {0x2004, 0x3000, 0xf800, 0x143f, 0x0000, 0x3000}; for (reg = 0; reg < ARRAY_SIZE(val); reg++) { err = snd_usb_cm106_write_int_reg(dev, reg, val[reg]); @@ -1333,7 +1214,7 @@ int snd_usb_select_mode_quirk(struct snd_usb_substream *subs, if (err < 0) return err; - msleep(20); /* Delay needed after setting the interface */ + mdelay(20); /* Delay needed after setting the interface */ /* Vendor mode switch cmd is required. */ if (fmt->formats & SNDRV_PCM_FMTBIT_DSD_U32_BE) { @@ -1354,7 +1235,7 @@ int snd_usb_select_mode_quirk(struct snd_usb_substream *subs, return err; } - msleep(20); + mdelay(20); } return 0; } @@ -1401,7 +1282,7 @@ void snd_usb_set_interface_quirk(struct usb_device *dev) switch (USB_ID_VENDOR(chip->usb_id)) { case 0x23ba: /* Playback Design */ case 0x0644: /* TEAC Corp. */ - msleep(50); + mdelay(50); break; } } @@ -1421,7 +1302,7 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, */ if (USB_ID_VENDOR(chip->usb_id) == 0x23ba && (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) - msleep(20); + mdelay(20); /* * "TEAC Corp." products need a 20ms delay after each @@ -1429,14 +1310,14 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, */ if (USB_ID_VENDOR(chip->usb_id) == 0x0644 && (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) - msleep(20); + mdelay(20); /* ITF-USB DSD based DACs functionality need a delay * after each class compliant request */ if (is_itf_usb_dsd_dac(chip->usb_id) && (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) - msleep(20); + mdelay(20); /* Zoom R16/24, Logitech H650e, Jabra 550a needs a tiny delay here, * otherwise requests like get/set frequency return as failed despite @@ -1446,7 +1327,7 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, chip->usb_id == USB_ID(0x046d, 0x0a46) || chip->usb_id == USB_ID(0x0b0e, 0x0349)) && (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) - usleep_range(1000, 2000); + mdelay(1); } /* @@ -1565,7 +1446,6 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, */ switch (USB_ID_VENDOR(chip->usb_id)) { case 0x20b1: /* XMOS based devices */ - case 0x152a: /* Thesycon devices */ case 0x25ce: /* Mytek devices */ if (fp->dsd_raw) return SNDRV_PCM_FMTBIT_DSD_U32_BE; @@ -1577,37 +1457,3 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, return 0; } - -void snd_usb_audioformat_attributes_quirk(struct snd_usb_audio *chip, - struct audioformat *fp, - int stream) -{ - switch (chip->usb_id) { - case USB_ID(0x0a92, 0x0053): /* AudioTrak Optoplay */ - /* Optoplay sets the sample rate attribute although - * it seems not supporting it in fact. - */ - fp->attributes &= ~UAC_EP_CS_ATTR_SAMPLE_RATE; - break; - case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */ - case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ - /* doesn't set the sample rate attribute, but supports it */ - fp->attributes |= UAC_EP_CS_ATTR_SAMPLE_RATE; - break; - case USB_ID(0x0763, 0x2001): /* M-Audio Quattro USB */ - case USB_ID(0x0763, 0x2012): /* M-Audio Fast Track Pro USB */ - case USB_ID(0x047f, 0x0ca1): /* plantronics headset */ - case USB_ID(0x077d, 0x07af): /* Griffin iMic (note that there is - an older model 77d:223) */ - /* - * plantronics headset and Griffin iMic have set adaptive-in - * although it's really not... - */ - fp->ep_attr &= ~USB_ENDPOINT_SYNCTYPE; - if (stream == SNDRV_PCM_STREAM_PLAYBACK) - fp->ep_attr |= USB_ENDPOINT_SYNC_ADAPTIVE; - else - fp->ep_attr |= USB_ENDPOINT_SYNC_SYNC; - break; - } -} diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h index 283ee46ff43c..192ff5ce9452 100644 --- a/sound/usb/quirks.h +++ b/sound/usb/quirks.h @@ -41,8 +41,4 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, struct audioformat *fp, unsigned int sample_bytes); -void snd_usb_audioformat_attributes_quirk(struct snd_usb_audio *chip, - struct audioformat *fp, - int stream); - #endif /* __USBAUDIO_QUIRKS_H */ diff --git a/sound/usb/stream.c b/sound/usb/stream.c index 67cf849aa16b..8e9548bc1f1a 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -20,7 +20,6 @@ #include <linux/usb.h> #include <linux/usb/audio.h> #include <linux/usb/audio-v2.h> -#include <linux/usb/audio-v3.h> #include <sound/core.h> #include <sound/pcm.h> @@ -37,7 +36,6 @@ #include "format.h" #include "clock.h" #include "stream.h" -#include "power.h" /* * free a substream @@ -54,7 +52,6 @@ static void free_substream(struct snd_usb_substream *subs) kfree(fp); } kfree(subs->rate_list.list); - kfree(subs->str_pd); } @@ -84,8 +81,7 @@ static void snd_usb_audio_pcm_free(struct snd_pcm *pcm) static void snd_usb_init_substream(struct snd_usb_stream *as, int stream, - struct audioformat *fp, - struct snd_usb_power_domain *pd) + struct audioformat *fp) { struct snd_usb_substream *subs = &as->substream[stream]; @@ -109,15 +105,6 @@ static void snd_usb_init_substream(struct snd_usb_stream *as, subs->ep_num = fp->endpoint; if (fp->channels > subs->channels_max) subs->channels_max = fp->channels; - - if (pd) { - subs->str_pd = pd; - /* Initialize Power Domain to idle status D1 */ - snd_usb_power_domain_set(subs->stream->chip, pd, - UAC3_PD_STATE_D1); - } - - snd_usb_preallocate_buffer(subs); } /* kctl callbacks for usb-audio channel maps */ @@ -324,153 +311,6 @@ static struct snd_pcm_chmap_elem *convert_chmap(int channels, unsigned int bits, return chmap; } -/* UAC3 device stores channels information in Cluster Descriptors */ -static struct -snd_pcm_chmap_elem *convert_chmap_v3(struct uac3_cluster_header_descriptor - *cluster) -{ - unsigned int channels = cluster->bNrChannels; - struct snd_pcm_chmap_elem *chmap; - void *p = cluster; - int len, c; - - if (channels > ARRAY_SIZE(chmap->map)) - return NULL; - - chmap = kzalloc(sizeof(*chmap), GFP_KERNEL); - if (!chmap) - return NULL; - - len = le16_to_cpu(cluster->wLength); - c = 0; - p += sizeof(struct uac3_cluster_header_descriptor); - - while (((p - (void *)cluster) < len) && (c < channels)) { - struct uac3_cluster_segment_descriptor *cs_desc = p; - u16 cs_len; - u8 cs_type; - - cs_len = le16_to_cpu(cs_desc->wLength); - cs_type = cs_desc->bSegmentType; - - if (cs_type == UAC3_CHANNEL_INFORMATION) { - struct uac3_cluster_information_segment_descriptor *is = p; - unsigned char map; - - /* - * TODO: this conversion is not complete, update it - * after adding UAC3 values to asound.h - */ - switch (is->bChRelationship) { - case UAC3_CH_MONO: - map = SNDRV_CHMAP_MONO; - break; - case UAC3_CH_LEFT: - case UAC3_CH_FRONT_LEFT: - case UAC3_CH_HEADPHONE_LEFT: - map = SNDRV_CHMAP_FL; - break; - case UAC3_CH_RIGHT: - case UAC3_CH_FRONT_RIGHT: - case UAC3_CH_HEADPHONE_RIGHT: - map = SNDRV_CHMAP_FR; - break; - case UAC3_CH_FRONT_CENTER: - map = SNDRV_CHMAP_FC; - break; - case UAC3_CH_FRONT_LEFT_OF_CENTER: - map = SNDRV_CHMAP_FLC; - break; - case UAC3_CH_FRONT_RIGHT_OF_CENTER: - map = SNDRV_CHMAP_FRC; - break; - case UAC3_CH_SIDE_LEFT: - map = SNDRV_CHMAP_SL; - break; - case UAC3_CH_SIDE_RIGHT: - map = SNDRV_CHMAP_SR; - break; - case UAC3_CH_BACK_LEFT: - map = SNDRV_CHMAP_RL; - break; - case UAC3_CH_BACK_RIGHT: - map = SNDRV_CHMAP_RR; - break; - case UAC3_CH_BACK_CENTER: - map = SNDRV_CHMAP_RC; - break; - case UAC3_CH_BACK_LEFT_OF_CENTER: - map = SNDRV_CHMAP_RLC; - break; - case UAC3_CH_BACK_RIGHT_OF_CENTER: - map = SNDRV_CHMAP_RRC; - break; - case UAC3_CH_TOP_CENTER: - map = SNDRV_CHMAP_TC; - break; - case UAC3_CH_TOP_FRONT_LEFT: - map = SNDRV_CHMAP_TFL; - break; - case UAC3_CH_TOP_FRONT_RIGHT: - map = SNDRV_CHMAP_TFR; - break; - case UAC3_CH_TOP_FRONT_CENTER: - map = SNDRV_CHMAP_TFC; - break; - case UAC3_CH_TOP_FRONT_LOC: - map = SNDRV_CHMAP_TFLC; - break; - case UAC3_CH_TOP_FRONT_ROC: - map = SNDRV_CHMAP_TFRC; - break; - case UAC3_CH_TOP_SIDE_LEFT: - map = SNDRV_CHMAP_TSL; - break; - case UAC3_CH_TOP_SIDE_RIGHT: - map = SNDRV_CHMAP_TSR; - break; - case UAC3_CH_TOP_BACK_LEFT: - map = SNDRV_CHMAP_TRL; - break; - case UAC3_CH_TOP_BACK_RIGHT: - map = SNDRV_CHMAP_TRR; - break; - case UAC3_CH_TOP_BACK_CENTER: - map = SNDRV_CHMAP_TRC; - break; - case UAC3_CH_BOTTOM_CENTER: - map = SNDRV_CHMAP_BC; - break; - case UAC3_CH_LOW_FREQUENCY_EFFECTS: - map = SNDRV_CHMAP_LFE; - break; - case UAC3_CH_LFE_LEFT: - map = SNDRV_CHMAP_LLFE; - break; - case UAC3_CH_LFE_RIGHT: - map = SNDRV_CHMAP_RLFE; - break; - case UAC3_CH_RELATIONSHIP_UNDEFINED: - default: - map = SNDRV_CHMAP_UNKNOWN; - break; - } - chmap->map[c++] = map; - } - p += cs_len; - } - - if (channels < c) - pr_err("%s: channel number mismatch\n", __func__); - - chmap->channels = channels; - - for (; c < channels; c++) - chmap->map[c] = SNDRV_CHMAP_UNKNOWN; - - return chmap; -} - /* * add this endpoint to the chip instance. * if a stream with the same endpoint already exists, append to it. @@ -478,11 +318,9 @@ snd_pcm_chmap_elem *convert_chmap_v3(struct uac3_cluster_header_descriptor * fmt_list and will be freed on the chip instance release. do not free * fp or do remove it from the substream fmt_list to avoid double-free. */ -static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, - int stream, - struct audioformat *fp, - struct snd_usb_power_domain *pd) - +int snd_usb_add_audio_stream(struct snd_usb_audio *chip, + int stream, + struct audioformat *fp) { struct snd_usb_stream *as; struct snd_usb_substream *subs; @@ -510,7 +348,7 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, err = snd_pcm_new_stream(as->pcm, stream, 1); if (err < 0) return err; - snd_usb_init_substream(as, stream, fp, pd); + snd_usb_init_substream(as, stream, fp); return add_chmap(as->pcm, stream, subs); } @@ -538,7 +376,7 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, else strcpy(pcm->name, "USB Audio"); - snd_usb_init_substream(as, stream, fp, pd); + snd_usb_init_substream(as, stream, fp); /* * Keep using head insertion for M-Audio Audiophile USB (tm) which has a @@ -556,21 +394,6 @@ static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip, return add_chmap(pcm, stream, &as->substream[stream]); } -int snd_usb_add_audio_stream(struct snd_usb_audio *chip, - int stream, - struct audioformat *fp) -{ - return __snd_usb_add_audio_stream(chip, stream, fp, NULL); -} - -static int snd_usb_add_audio_stream_v3(struct snd_usb_audio *chip, - int stream, - struct audioformat *fp, - struct snd_usb_power_domain *pd) -{ - return __snd_usb_add_audio_stream(chip, stream, fp, pd); -} - static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip, struct usb_host_interface *alts, int protocol, int iface_no) @@ -605,7 +428,7 @@ static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip, if (protocol == UAC_VERSION_1) { attributes = csep->bmAttributes; - } else if (protocol == UAC_VERSION_2) { + } else { struct uac2_iso_endpoint_descriptor *csep2 = (struct uac2_iso_endpoint_descriptor *) csep; @@ -614,13 +437,6 @@ static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip, /* emulate the endpoint attributes of a v1 device */ if (csep2->bmControls & UAC2_CONTROL_PITCH) attributes |= UAC_EP_CS_ATTR_PITCH_CONTROL; - } else { /* UAC_VERSION_3 */ - struct uac3_iso_endpoint_descriptor *csep3 = - (struct uac3_iso_endpoint_descriptor *) csep; - - /* emulate the endpoint attributes of a v1 device */ - if (le32_to_cpu(csep3->bmControls) & UAC2_CONTROL_PITCH) - attributes |= UAC_EP_CS_ATTR_PITCH_CONTROL; } return attributes; @@ -645,11 +461,10 @@ snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface, return NULL; } -static void * -snd_usb_find_output_terminal_descriptor(struct usb_host_interface *ctrl_iface, - int terminal_id) +static struct uac2_output_terminal_descriptor * + snd_usb_find_output_terminal_descriptor(struct usb_host_interface *ctrl_iface, + int terminal_id) { - /* OK to use with both UAC2 and UAC3 */ struct uac2_output_terminal_descriptor *term = NULL; while ((term = snd_usb_find_csint_desc(ctrl_iface->extra, @@ -662,416 +477,6 @@ snd_usb_find_output_terminal_descriptor(struct usb_host_interface *ctrl_iface, return NULL; } -static struct audioformat * -audio_format_alloc_init(struct snd_usb_audio *chip, - struct usb_host_interface *alts, - int protocol, int iface_no, int altset_idx, - int altno, int num_channels, int clock) -{ - struct audioformat *fp; - - fp = kzalloc(sizeof(*fp), GFP_KERNEL); - if (!fp) - return NULL; - - fp->iface = iface_no; - fp->altsetting = altno; - fp->altset_idx = altset_idx; - fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress; - fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; - fp->datainterval = snd_usb_parse_datainterval(chip, alts); - fp->protocol = protocol; - fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); - fp->channels = num_channels; - if (snd_usb_get_speed(chip->dev) == USB_SPEED_HIGH) - fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1) - * (fp->maxpacksize & 0x7ff); - fp->clock = clock; - INIT_LIST_HEAD(&fp->list); - - return fp; -} - -static struct audioformat * -snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip, - struct usb_host_interface *alts, - int protocol, int iface_no, int altset_idx, - int altno, int stream, int bm_quirk) -{ - struct usb_device *dev = chip->dev; - struct uac_format_type_i_continuous_descriptor *fmt; - unsigned int num_channels = 0, chconfig = 0; - struct audioformat *fp; - int clock = 0; - u64 format; - - /* get audio formats */ - if (protocol == UAC_VERSION_1) { - struct uac1_as_header_descriptor *as = - snd_usb_find_csint_desc(alts->extra, alts->extralen, - NULL, UAC_AS_GENERAL); - struct uac_input_terminal_descriptor *iterm; - - if (!as) { - dev_err(&dev->dev, - "%u:%d : UAC_AS_GENERAL descriptor not found\n", - iface_no, altno); - return NULL; - } - - if (as->bLength < sizeof(*as)) { - dev_err(&dev->dev, - "%u:%d : invalid UAC_AS_GENERAL desc\n", - iface_no, altno); - return NULL; - } - - format = le16_to_cpu(as->wFormatTag); /* remember the format value */ - - iterm = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, - as->bTerminalLink); - if (iterm) { - num_channels = iterm->bNrChannels; - chconfig = le16_to_cpu(iterm->wChannelConfig); - } - } else { /* UAC_VERSION_2 */ - struct uac2_input_terminal_descriptor *input_term; - struct uac2_output_terminal_descriptor *output_term; - struct uac2_as_header_descriptor *as = - snd_usb_find_csint_desc(alts->extra, alts->extralen, - NULL, UAC_AS_GENERAL); - - if (!as) { - dev_err(&dev->dev, - "%u:%d : UAC_AS_GENERAL descriptor not found\n", - iface_no, altno); - return NULL; - } - - if (as->bLength < sizeof(*as)) { - dev_err(&dev->dev, - "%u:%d : invalid UAC_AS_GENERAL desc\n", - iface_no, altno); - return NULL; - } - - num_channels = as->bNrChannels; - format = le32_to_cpu(as->bmFormats); - chconfig = le32_to_cpu(as->bmChannelConfig); - - /* - * lookup the terminal associated to this interface - * to extract the clock - */ - input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, - as->bTerminalLink); - if (input_term) { - clock = input_term->bCSourceID; - if (!chconfig && (num_channels == input_term->bNrChannels)) - chconfig = le32_to_cpu(input_term->bmChannelConfig); - goto found_clock; - } - - output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, - as->bTerminalLink); - if (output_term) { - clock = output_term->bCSourceID; - goto found_clock; - } - - dev_err(&dev->dev, - "%u:%d : bogus bTerminalLink %d\n", - iface_no, altno, as->bTerminalLink); - return NULL; - } - -found_clock: - /* get format type */ - fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, - NULL, UAC_FORMAT_TYPE); - if (!fmt) { - dev_err(&dev->dev, - "%u:%d : no UAC_FORMAT_TYPE desc\n", - iface_no, altno); - return NULL; - } - if (((protocol == UAC_VERSION_1) && (fmt->bLength < 8)) - || ((protocol == UAC_VERSION_2) && - (fmt->bLength < 6))) { - dev_err(&dev->dev, - "%u:%d : invalid UAC_FORMAT_TYPE desc\n", - iface_no, altno); - return NULL; - } - - /* - * Blue Microphones workaround: The last altsetting is - * identical with the previous one, except for a larger - * packet size, but is actually a mislabeled two-channel - * setting; ignore it. - * - * Part 2: analyze quirk flag and format - */ - if (bm_quirk && fmt->bNrChannels == 1 && fmt->bSubframeSize == 2) - return NULL; - - fp = audio_format_alloc_init(chip, alts, protocol, iface_no, - altset_idx, altno, num_channels, clock); - if (!fp) - return ERR_PTR(-ENOMEM); - - fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, - iface_no); - - /* some quirks for attributes here */ - snd_usb_audioformat_attributes_quirk(chip, fp, stream); - - /* ok, let's parse further... */ - if (snd_usb_parse_audio_format(chip, fp, format, - fmt, stream) < 0) { - kfree(fp->rate_table); - kfree(fp); - return NULL; - } - - /* Create chmap */ - if (fp->channels != num_channels) - chconfig = 0; - - fp->chmap = convert_chmap(fp->channels, chconfig, protocol); - - return fp; -} - -static struct audioformat * -snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, - struct usb_host_interface *alts, - struct snd_usb_power_domain **pd_out, - int iface_no, int altset_idx, - int altno, int stream) -{ - struct usb_device *dev = chip->dev; - struct uac3_input_terminal_descriptor *input_term; - struct uac3_output_terminal_descriptor *output_term; - struct uac3_cluster_header_descriptor *cluster; - struct uac3_as_header_descriptor *as = NULL; - struct uac3_hc_descriptor_header hc_header; - struct snd_pcm_chmap_elem *chmap; - struct snd_usb_power_domain *pd; - unsigned char badd_profile; - u64 badd_formats = 0; - unsigned int num_channels; - struct audioformat *fp; - u16 cluster_id, wLength; - int clock = 0; - int err; - - badd_profile = chip->badd_profile; - - if (badd_profile >= UAC3_FUNCTION_SUBCLASS_GENERIC_IO) { - unsigned int maxpacksize = - le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); - - switch (maxpacksize) { - default: - dev_err(&dev->dev, - "%u:%d : incorrect wMaxPacketSize for BADD profile\n", - iface_no, altno); - return NULL; - case UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_16: - case UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_16: - badd_formats = SNDRV_PCM_FMTBIT_S16_LE; - num_channels = 1; - break; - case UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_24: - case UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_24: - badd_formats = SNDRV_PCM_FMTBIT_S24_3LE; - num_channels = 1; - break; - case UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_16: - case UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_16: - badd_formats = SNDRV_PCM_FMTBIT_S16_LE; - num_channels = 2; - break; - case UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_24: - case UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_24: - badd_formats = SNDRV_PCM_FMTBIT_S24_3LE; - num_channels = 2; - break; - } - - chmap = kzalloc(sizeof(*chmap), GFP_KERNEL); - if (!chmap) - return ERR_PTR(-ENOMEM); - - if (num_channels == 1) { - chmap->map[0] = SNDRV_CHMAP_MONO; - } else { - chmap->map[0] = SNDRV_CHMAP_FL; - chmap->map[1] = SNDRV_CHMAP_FR; - } - - chmap->channels = num_channels; - clock = UAC3_BADD_CS_ID9; - goto found_clock; - } - - as = snd_usb_find_csint_desc(alts->extra, alts->extralen, - NULL, UAC_AS_GENERAL); - if (!as) { - dev_err(&dev->dev, - "%u:%d : UAC_AS_GENERAL descriptor not found\n", - iface_no, altno); - return NULL; - } - - if (as->bLength < sizeof(*as)) { - dev_err(&dev->dev, - "%u:%d : invalid UAC_AS_GENERAL desc\n", - iface_no, altno); - return NULL; - } - - cluster_id = le16_to_cpu(as->wClusterDescrID); - if (!cluster_id) { - dev_err(&dev->dev, - "%u:%d : no cluster descriptor\n", - iface_no, altno); - return NULL; - } - - /* - * Get number of channels and channel map through - * High Capability Cluster Descriptor - * - * First step: get High Capability header and - * read size of Cluster Descriptor - */ - err = snd_usb_ctl_msg(chip->dev, - usb_rcvctrlpipe(chip->dev, 0), - UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR, - USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - cluster_id, - snd_usb_ctrl_intf(chip), - &hc_header, sizeof(hc_header)); - if (err < 0) - return ERR_PTR(err); - else if (err != sizeof(hc_header)) { - dev_err(&dev->dev, - "%u:%d : can't get High Capability descriptor\n", - iface_no, altno); - return ERR_PTR(-EIO); - } - - /* - * Second step: allocate needed amount of memory - * and request Cluster Descriptor - */ - wLength = le16_to_cpu(hc_header.wLength); - cluster = kzalloc(wLength, GFP_KERNEL); - if (!cluster) - return ERR_PTR(-ENOMEM); - err = snd_usb_ctl_msg(chip->dev, - usb_rcvctrlpipe(chip->dev, 0), - UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR, - USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - cluster_id, - snd_usb_ctrl_intf(chip), - cluster, wLength); - if (err < 0) { - kfree(cluster); - return ERR_PTR(err); - } else if (err != wLength) { - dev_err(&dev->dev, - "%u:%d : can't get Cluster Descriptor\n", - iface_no, altno); - kfree(cluster); - return ERR_PTR(-EIO); - } - - num_channels = cluster->bNrChannels; - chmap = convert_chmap_v3(cluster); - kfree(cluster); - - /* - * lookup the terminal associated to this interface - * to extract the clock - */ - input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, - as->bTerminalLink); - if (input_term) { - clock = input_term->bCSourceID; - goto found_clock; - } - - output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, - as->bTerminalLink); - if (output_term) { - clock = output_term->bCSourceID; - goto found_clock; - } - - dev_err(&dev->dev, "%u:%d : bogus bTerminalLink %d\n", - iface_no, altno, as->bTerminalLink); - kfree(chmap); - return NULL; - -found_clock: - fp = audio_format_alloc_init(chip, alts, UAC_VERSION_3, iface_no, - altset_idx, altno, num_channels, clock); - if (!fp) { - kfree(chmap); - return ERR_PTR(-ENOMEM); - } - - fp->chmap = chmap; - - if (badd_profile >= UAC3_FUNCTION_SUBCLASS_GENERIC_IO) { - fp->attributes = 0; /* No attributes */ - - fp->fmt_type = UAC_FORMAT_TYPE_I; - fp->formats = badd_formats; - - fp->nr_rates = 0; /* SNDRV_PCM_RATE_CONTINUOUS */ - fp->rate_min = UAC3_BADD_SAMPLING_RATE; - fp->rate_max = UAC3_BADD_SAMPLING_RATE; - fp->rates = SNDRV_PCM_RATE_CONTINUOUS; - - pd = kzalloc(sizeof(*pd), GFP_KERNEL); - if (!pd) { - kfree(fp->rate_table); - kfree(fp); - return NULL; - } - pd->pd_id = (stream == SNDRV_PCM_STREAM_PLAYBACK) ? - UAC3_BADD_PD_ID10 : UAC3_BADD_PD_ID11; - pd->pd_d1d0_rec = UAC3_BADD_PD_RECOVER_D1D0; - pd->pd_d2d0_rec = UAC3_BADD_PD_RECOVER_D2D0; - - } else { - fp->attributes = parse_uac_endpoint_attributes(chip, alts, - UAC_VERSION_3, - iface_no); - - pd = snd_usb_find_power_domain(chip->ctrl_intf, - as->bTerminalLink); - - /* ok, let's parse further... */ - if (snd_usb_parse_audio_format_v3(chip, fp, as, stream) < 0) { - kfree(pd); - kfree(fp->chmap); - kfree(fp->rate_table); - kfree(fp); - return NULL; - } - } - - if (pd) - *pd_out = pd; - - return fp; -} - int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) { struct usb_device *dev; @@ -1079,9 +484,11 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) struct usb_host_interface *alts; struct usb_interface_descriptor *altsd; int i, altno, err, stream; + unsigned int format = 0, num_channels = 0; struct audioformat *fp = NULL; - struct snd_usb_power_domain *pd = NULL; - int num, protocol; + int num, protocol, clock = 0; + struct uac_format_type_i_continuous_descriptor *fmt; + unsigned int chconfig; dev = chip->dev; @@ -1130,58 +537,196 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) protocol <= 2) protocol = UAC_VERSION_1; + chconfig = 0; + /* get audio formats */ switch (protocol) { default: dev_dbg(&dev->dev, "%u:%d: unknown interface protocol %#02x, assuming v1\n", iface_no, altno, protocol); protocol = UAC_VERSION_1; /* fall through */ - case UAC_VERSION_1: - /* fall through */ + + case UAC_VERSION_1: { + struct uac1_as_header_descriptor *as = + snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); + struct uac_input_terminal_descriptor *iterm; + + if (!as) { + dev_err(&dev->dev, + "%u:%d : UAC_AS_GENERAL descriptor not found\n", + iface_no, altno); + continue; + } + + if (as->bLength < sizeof(*as)) { + dev_err(&dev->dev, + "%u:%d : invalid UAC_AS_GENERAL desc\n", + iface_no, altno); + continue; + } + + format = le16_to_cpu(as->wFormatTag); /* remember the format value */ + + iterm = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, + as->bTerminalLink); + if (iterm) { + num_channels = iterm->bNrChannels; + chconfig = le16_to_cpu(iterm->wChannelConfig); + } + + break; + } + case UAC_VERSION_2: { - int bm_quirk = 0; - - /* - * Blue Microphones workaround: The last altsetting is - * identical with the previous one, except for a larger - * packet size, but is actually a mislabeled two-channel - * setting; ignore it. - * - * Part 1: prepare quirk flag - */ - if (altno == 2 && num == 3 && - fp && fp->altsetting == 1 && fp->channels == 1 && - fp->formats == SNDRV_PCM_FMTBIT_S16_LE && - protocol == UAC_VERSION_1 && - le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == + struct uac2_input_terminal_descriptor *input_term; + struct uac2_output_terminal_descriptor *output_term; + struct uac2_as_header_descriptor *as = + snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); + + if (!as) { + dev_err(&dev->dev, + "%u:%d : UAC_AS_GENERAL descriptor not found\n", + iface_no, altno); + continue; + } + + if (as->bLength < sizeof(*as)) { + dev_err(&dev->dev, + "%u:%d : invalid UAC_AS_GENERAL desc\n", + iface_no, altno); + continue; + } + + num_channels = as->bNrChannels; + format = le32_to_cpu(as->bmFormats); + chconfig = le32_to_cpu(as->bmChannelConfig); + + /* lookup the terminal associated to this interface + * to extract the clock */ + input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, + as->bTerminalLink); + if (input_term) { + clock = input_term->bCSourceID; + if (!chconfig && (num_channels == input_term->bNrChannels)) + chconfig = le32_to_cpu(input_term->bmChannelConfig); + break; + } + + output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, + as->bTerminalLink); + if (output_term) { + clock = output_term->bCSourceID; + break; + } + + dev_err(&dev->dev, + "%u:%d : bogus bTerminalLink %d\n", + iface_no, altno, as->bTerminalLink); + continue; + } + } + + /* get format type */ + fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_FORMAT_TYPE); + if (!fmt) { + dev_err(&dev->dev, + "%u:%d : no UAC_FORMAT_TYPE desc\n", + iface_no, altno); + continue; + } + if (((protocol == UAC_VERSION_1) && (fmt->bLength < 8)) || + ((protocol == UAC_VERSION_2) && (fmt->bLength < 6))) { + dev_err(&dev->dev, + "%u:%d : invalid UAC_FORMAT_TYPE desc\n", + iface_no, altno); + continue; + } + + /* + * Blue Microphones workaround: The last altsetting is identical + * with the previous one, except for a larger packet size, but + * is actually a mislabeled two-channel setting; ignore it. + */ + if (fmt->bNrChannels == 1 && + fmt->bSubframeSize == 2 && + altno == 2 && num == 3 && + fp && fp->altsetting == 1 && fp->channels == 1 && + fp->formats == SNDRV_PCM_FMTBIT_S16_LE && + protocol == UAC_VERSION_1 && + le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == fp->maxpacksize * 2) - bm_quirk = 1; + continue; - fp = snd_usb_get_audioformat_uac12(chip, alts, protocol, - iface_no, i, altno, - stream, bm_quirk); - break; + fp = kzalloc(sizeof(*fp), GFP_KERNEL); + if (! fp) { + dev_err(&dev->dev, "cannot malloc\n"); + return -ENOMEM; } - case UAC_VERSION_3: - fp = snd_usb_get_audioformat_uac3(chip, alts, &pd, - iface_no, i, altno, stream); + + fp->iface = iface_no; + fp->altsetting = altno; + fp->altset_idx = i; + fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress; + fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; + fp->datainterval = snd_usb_parse_datainterval(chip, alts); + fp->protocol = protocol; + fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); + fp->channels = num_channels; + if (snd_usb_get_speed(dev) == USB_SPEED_HIGH) + fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1) + * (fp->maxpacksize & 0x7ff); + fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no); + fp->clock = clock; + INIT_LIST_HEAD(&fp->list); + + /* some quirks for attributes here */ + + switch (chip->usb_id) { + case USB_ID(0x0a92, 0x0053): /* AudioTrak Optoplay */ + /* Optoplay sets the sample rate attribute although + * it seems not supporting it in fact. + */ + fp->attributes &= ~UAC_EP_CS_ATTR_SAMPLE_RATE; + break; + case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */ + case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ + /* doesn't set the sample rate attribute, but supports it */ + fp->attributes |= UAC_EP_CS_ATTR_SAMPLE_RATE; + break; + case USB_ID(0x0763, 0x2001): /* M-Audio Quattro USB */ + case USB_ID(0x0763, 0x2012): /* M-Audio Fast Track Pro USB */ + case USB_ID(0x047f, 0x0ca1): /* plantronics headset */ + case USB_ID(0x077d, 0x07af): /* Griffin iMic (note that there is + an older model 77d:223) */ + /* + * plantronics headset and Griffin iMic have set adaptive-in + * although it's really not... + */ + fp->ep_attr &= ~USB_ENDPOINT_SYNCTYPE; + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + fp->ep_attr |= USB_ENDPOINT_SYNC_ADAPTIVE; + else + fp->ep_attr |= USB_ENDPOINT_SYNC_SYNC; break; } - if (!fp) + /* ok, let's parse further... */ + if (snd_usb_parse_audio_format(chip, fp, format, fmt, stream) < 0) { + kfree(fp->rate_table); + kfree(fp); + fp = NULL; continue; - else if (IS_ERR(fp)) - return PTR_ERR(fp); + } - dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint); - if (protocol == UAC_VERSION_3) - err = snd_usb_add_audio_stream_v3(chip, stream, fp, pd); - else - err = snd_usb_add_audio_stream(chip, stream, fp); + /* Create chmap */ + if (fp->channels != num_channels) + chconfig = 0; + fp->chmap = convert_chmap(fp->channels, chconfig, protocol); + dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint); + err = snd_usb_add_audio_stream(chip, stream, fp); if (err < 0) { list_del(&fp->list); /* unlink for avoiding double-free */ - kfree(pd); kfree(fp->rate_table); kfree(fp->chmap); kfree(fp); diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index b9faeca645fd..1cb6b3e9483c 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -49,8 +49,6 @@ struct snd_usb_audio { int num_suspended_intf; int sample_rate_read_error; - int badd_profile; /* UAC3 BADD profile */ - struct list_head pcm_list; /* list of pcm streams */ struct list_head ep_list; /* list of audio-related endpoints */ int pcm_devs; @@ -127,6 +125,4 @@ struct snd_usb_audio_quirk { int snd_usb_lock_shutdown(struct snd_usb_audio *chip); void snd_usb_unlock_shutdown(struct snd_usb_audio *chip); -extern bool snd_usb_use_vmalloc; - #endif /* __USBAUDIO_H */ diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c index 8c394178a385..e118bdca983d 100644 --- a/sound/usb/usx2y/us122l.c +++ b/sound/usb/usx2y/us122l.c @@ -46,11 +46,9 @@ MODULE_PARM_DESC(id, "ID string for "NAME_ALLCAPS"."); module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable "NAME_ALLCAPS"."); -/* driver_info flags */ -#define US122L_FLAG_US144 BIT(0) - static int snd_us122l_card_used[SNDRV_CARDS]; + static int us122l_create_usbmidi(struct snd_card *card) { static struct snd_usb_midi_endpoint_info quirk_data = { @@ -200,7 +198,8 @@ static int usb_stream_hwdep_open(struct snd_hwdep *hw, struct file *file) if (!us122l->first) us122l->first = file; - if (us122l->is_us144) { + if (us122l->dev->descriptor.idProduct == USB_ID_US144 || + us122l->dev->descriptor.idProduct == USB_ID_US144MKII) { iface = usb_ifnum_to_if(us122l->dev, 0); usb_autopm_get_interface(iface); } @@ -215,7 +214,8 @@ static int usb_stream_hwdep_release(struct snd_hwdep *hw, struct file *file) struct usb_interface *iface; snd_printdd(KERN_DEBUG "%p %p\n", hw, file); - if (us122l->is_us144) { + if (us122l->dev->descriptor.idProduct == USB_ID_US144 || + us122l->dev->descriptor.idProduct == USB_ID_US144MKII) { iface = usb_ifnum_to_if(us122l->dev, 0); usb_autopm_put_interface(iface); } @@ -378,7 +378,7 @@ out: static int usb_stream_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigned cmd, unsigned long arg) { - struct usb_stream_config cfg; + struct usb_stream_config *cfg; struct us122l *us122l = hw->private_data; struct usb_stream *s; unsigned min_period_frames; @@ -388,21 +388,24 @@ static int usb_stream_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, if (cmd != SNDRV_USB_STREAM_IOCTL_SET_PARAMS) return -ENOTTY; - if (copy_from_user(&cfg, (void __user *)arg, sizeof(cfg))) - return -EFAULT; - - if (cfg.version != USB_STREAM_INTERFACE_VERSION) - return -ENXIO; + cfg = memdup_user((void *)arg, sizeof(*cfg)); + if (IS_ERR(cfg)) + return PTR_ERR(cfg); + if (cfg->version != USB_STREAM_INTERFACE_VERSION) { + err = -ENXIO; + goto free; + } high_speed = us122l->dev->speed == USB_SPEED_HIGH; - if ((cfg.sample_rate != 44100 && cfg.sample_rate != 48000 && + if ((cfg->sample_rate != 44100 && cfg->sample_rate != 48000 && (!high_speed || - (cfg.sample_rate != 88200 && cfg.sample_rate != 96000))) || - cfg.frame_size != 6 || - cfg.period_frames > 0x3000) - return -EINVAL; - - switch (cfg.sample_rate) { + (cfg->sample_rate != 88200 && cfg->sample_rate != 96000))) || + cfg->frame_size != 6 || + cfg->period_frames > 0x3000) { + err = -EINVAL; + goto free; + } + switch (cfg->sample_rate) { case 44100: min_period_frames = 48; break; @@ -415,8 +418,10 @@ static int usb_stream_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, } if (!high_speed) min_period_frames <<= 1; - if (cfg.period_frames < min_period_frames) - return -EINVAL; + if (cfg->period_frames < min_period_frames) { + err = -EINVAL; + goto free; + } snd_power_wait(hw->card, SNDRV_CTL_POWER_D0); @@ -425,22 +430,24 @@ static int usb_stream_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, if (!us122l->master) us122l->master = file; else if (us122l->master != file) { - if (!s || memcmp(&cfg, &s->cfg, sizeof(cfg))) { + if (!s || memcmp(cfg, &s->cfg, sizeof(*cfg))) { err = -EIO; goto unlock; } us122l->slave = file; } - if (!s || memcmp(&cfg, &s->cfg, sizeof(cfg)) || + if (!s || memcmp(cfg, &s->cfg, sizeof(*cfg)) || s->state == usb_stream_xrun) { us122l_stop(us122l); - if (!us122l_start(us122l, cfg.sample_rate, cfg.period_frames)) + if (!us122l_start(us122l, cfg->sample_rate, cfg->period_frames)) err = -EIO; else err = 1; } unlock: mutex_unlock(&us122l->mutex); +free: + kfree(cfg); wake_up_all(&us122l->sk.sleep); return err; } @@ -476,7 +483,8 @@ static bool us122l_create_card(struct snd_card *card) int err; struct us122l *us122l = US122L(card); - if (us122l->is_us144) { + if (us122l->dev->descriptor.idProduct == USB_ID_US144 || + us122l->dev->descriptor.idProduct == USB_ID_US144MKII) { err = usb_set_interface(us122l->dev, 0, 1); if (err) { snd_printk(KERN_ERR "usb_set_interface error \n"); @@ -495,13 +503,15 @@ static bool us122l_create_card(struct snd_card *card) if (!us122l_start(us122l, 44100, 256)) return false; - if (us122l->is_us144) + if (us122l->dev->descriptor.idProduct == USB_ID_US144 || + us122l->dev->descriptor.idProduct == USB_ID_US144MKII) err = us144_create_usbmidi(card); else err = us122l_create_usbmidi(card); if (err < 0) { snd_printk(KERN_ERR "us122l_create_usbmidi error %i \n", err); - goto stop; + us122l_stop(us122l); + return false; } err = usb_stream_hwdep_new(card); if (err < 0) { @@ -510,13 +520,10 @@ static bool us122l_create_card(struct snd_card *card) list_for_each(p, &us122l->midi_list) snd_usbmidi_disconnect(p); - goto stop; + us122l_stop(us122l); + return false; } return true; - -stop: - us122l_stop(us122l); - return false; } static void snd_us122l_free(struct snd_card *card) @@ -529,8 +536,7 @@ static void snd_us122l_free(struct snd_card *card) static int usx2y_create_card(struct usb_device *device, struct usb_interface *intf, - struct snd_card **cardp, - unsigned long flags) + struct snd_card **cardp) { int dev; struct snd_card *card; @@ -550,7 +556,6 @@ static int usx2y_create_card(struct usb_device *device, US122L(card)->dev = device; mutex_init(&US122L(card)->mutex); init_waitqueue_head(&US122L(card)->sk.sleep); - US122L(card)->is_us144 = flags & US122L_FLAG_US144; INIT_LIST_HEAD(&US122L(card)->midi_list); strcpy(card->driver, "USB "NAME_ALLCAPS""); sprintf(card->shortname, "TASCAM "NAME_ALLCAPS""); @@ -574,7 +579,7 @@ static int us122l_usb_probe(struct usb_interface *intf, struct snd_card *card; int err; - err = usx2y_create_card(device, intf, &card, device_id->driver_info); + err = usx2y_create_card(device, intf, &card); if (err < 0) return err; @@ -602,8 +607,9 @@ static int snd_us122l_probe(struct usb_interface *intf, struct snd_card *card; int err; - if (id->driver_info & US122L_FLAG_US144 && - device->speed == USB_SPEED_HIGH) { + if ((device->descriptor.idProduct == USB_ID_US144 || + device->descriptor.idProduct == USB_ID_US144MKII) + && device->speed == USB_SPEED_HIGH) { snd_printk(KERN_ERR "disable ehci-hcd to run US-144 \n"); return -ENODEV; } @@ -697,7 +703,8 @@ static int snd_us122l_resume(struct usb_interface *intf) mutex_lock(&us122l->mutex); /* needed, doesn't restart without: */ - if (us122l->is_us144) { + if (us122l->dev->descriptor.idProduct == USB_ID_US144 || + us122l->dev->descriptor.idProduct == USB_ID_US144MKII) { err = usb_set_interface(us122l->dev, 0, 1); if (err) { snd_printk(KERN_ERR "usb_set_interface error \n"); @@ -731,7 +738,7 @@ unlock: return err; } -static const struct usb_device_id snd_us122l_usb_id_table[] = { +static struct usb_device_id snd_us122l_usb_id_table[] = { { .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = 0x0644, @@ -740,8 +747,7 @@ static const struct usb_device_id snd_us122l_usb_id_table[] = { { /* US-144 only works at USB1.1! Disable module ehci-hcd. */ .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = 0x0644, - .idProduct = USB_ID_US144, - .driver_info = US122L_FLAG_US144 + .idProduct = USB_ID_US144 }, { .match_flags = USB_DEVICE_ID_MATCH_DEVICE, @@ -751,8 +757,7 @@ static const struct usb_device_id snd_us122l_usb_id_table[] = { { .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = 0x0644, - .idProduct = USB_ID_US144MKII, - .driver_info = US122L_FLAG_US144 + .idProduct = USB_ID_US144MKII }, { /* terminator */ } }; diff --git a/sound/usb/usx2y/us122l.h b/sound/usb/usx2y/us122l.h index 3e2a2d0041ee..f263b3f96c86 100644 --- a/sound/usb/usx2y/us122l.h +++ b/sound/usb/usx2y/us122l.h @@ -16,8 +16,6 @@ struct us122l { struct list_head midi_list; atomic_t mmap_count; - - bool is_us144; }; diff --git a/sound/usb/usx2y/usX2Yhwdep.c b/sound/usb/usx2y/usX2Yhwdep.c index 2bbcf4af06dd..f4b3cda412fc 100644 --- a/sound/usb/usx2y/usX2Yhwdep.c +++ b/sound/usb/usx2y/usX2Yhwdep.c @@ -198,22 +198,24 @@ static int snd_usX2Y_hwdep_dsp_load(struct snd_hwdep *hw, struct snd_hwdep_dsp_image *dsp) { struct usX2Ydev *priv = hw->private_data; - struct usb_device* dev = priv->dev; - int lret, err; - char *buf; - + int lret, err = -EINVAL; snd_printdd( "dsp_load %s\n", dsp->name); - buf = memdup_user(dsp->image, dsp->length); - if (IS_ERR(buf)) - return PTR_ERR(buf); + if (access_ok(VERIFY_READ, dsp->image, dsp->length)) { + struct usb_device* dev = priv->dev; + char *buf; - err = usb_set_interface(dev, 0, 1); - if (err) - snd_printk(KERN_ERR "usb_set_interface error \n"); - else - err = usb_bulk_msg(dev, usb_sndbulkpipe(dev, 2), buf, dsp->length, &lret, 6000); - kfree(buf); + buf = memdup_user(dsp->image, dsp->length); + if (IS_ERR(buf)) + return PTR_ERR(buf); + + err = usb_set_interface(dev, 0, 1); + if (err) + snd_printk(KERN_ERR "usb_set_interface error \n"); + else + err = usb_bulk_msg(dev, usb_sndbulkpipe(dev, 2), buf, dsp->length, &lret, 6000); + kfree(buf); + } if (err) return err; if (dsp->index == 1) { diff --git a/sound/usb/usx2y/usb_stream.c b/sound/usb/usx2y/usb_stream.c index 56d06566b30c..36812f77ee92 100644 --- a/sound/usb/usx2y/usb_stream.c +++ b/sound/usb/usx2y/usb_stream.c @@ -365,22 +365,20 @@ static int submit_urbs(struct usb_stream_kernel *sk, int err; prepare_inurb(sk->idle_outurb->number_of_packets, sk->idle_inurb); err = usb_submit_urb(sk->idle_inurb, GFP_ATOMIC); - if (err < 0) - goto report_failure; - + if (err < 0) { + snd_printk(KERN_ERR "%i\n", err); + return err; + } sk->idle_inurb = sk->completed_inurb; sk->completed_inurb = inurb; err = usb_submit_urb(sk->idle_outurb, GFP_ATOMIC); - if (err < 0) - goto report_failure; - + if (err < 0) { + snd_printk(KERN_ERR "%i\n", err); + return err; + } sk->idle_outurb = sk->completed_outurb; sk->completed_outurb = outurb; return 0; - -report_failure: - snd_printk(KERN_ERR "%i\n", err); - return err; } #ifdef DEBUG_LOOP_BACK |