Commit 9727b490e543de956b8ba356e2d5499097d0b7a2

Authored by Jeeja KP
Committed by Takashi Iwai
1 parent 8be69efacd

ALSA: compress: add support for gapless playback

this add new API for sound compress to support gapless playback.
As noted in Documentation change, we add API to send metadata of encoder and
padding delay to DSP. Also add API for indicating EOF and switching to
subsequent track

Also bump the compress API version

Signed-off-by: Jeeja KP <jeeja.kp@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>

Showing 4 changed files with 180 additions and 1 deletions Inline Diff

Documentation/sound/alsa/compress_offload.txt
1 compress_offload.txt 1 compress_offload.txt
2 ===================== 2 =====================
3 Pierre-Louis.Bossart <pierre-louis.bossart@linux.intel.com> 3 Pierre-Louis.Bossart <pierre-louis.bossart@linux.intel.com>
4 Vinod Koul <vinod.koul@linux.intel.com> 4 Vinod Koul <vinod.koul@linux.intel.com>
5 5
6 Overview 6 Overview
7 7
8 Since its early days, the ALSA API was defined with PCM support or 8 Since its early days, the ALSA API was defined with PCM support or
9 constant bitrates payloads such as IEC61937 in mind. Arguments and 9 constant bitrates payloads such as IEC61937 in mind. Arguments and
10 returned values in frames are the norm, making it a challenge to 10 returned values in frames are the norm, making it a challenge to
11 extend the existing API to compressed data streams. 11 extend the existing API to compressed data streams.
12 12
13 In recent years, audio digital signal processors (DSP) were integrated 13 In recent years, audio digital signal processors (DSP) were integrated
14 in system-on-chip designs, and DSPs are also integrated in audio 14 in system-on-chip designs, and DSPs are also integrated in audio
15 codecs. Processing compressed data on such DSPs results in a dramatic 15 codecs. Processing compressed data on such DSPs results in a dramatic
16 reduction of power consumption compared to host-based 16 reduction of power consumption compared to host-based
17 processing. Support for such hardware has not been very good in Linux, 17 processing. Support for such hardware has not been very good in Linux,
18 mostly because of a lack of a generic API available in the mainline 18 mostly because of a lack of a generic API available in the mainline
19 kernel. 19 kernel.
20 20
21 Rather than requiring a compatibility break with an API change of the 21 Rather than requiring a compatibility break with an API change of the
22 ALSA PCM interface, a new 'Compressed Data' API is introduced to 22 ALSA PCM interface, a new 'Compressed Data' API is introduced to
23 provide a control and data-streaming interface for audio DSPs. 23 provide a control and data-streaming interface for audio DSPs.
24 24
25 The design of this API was inspired by the 2-year experience with the 25 The design of this API was inspired by the 2-year experience with the
26 Intel Moorestown SOC, with many corrections required to upstream the 26 Intel Moorestown SOC, with many corrections required to upstream the
27 API in the mainline kernel instead of the staging tree and make it 27 API in the mainline kernel instead of the staging tree and make it
28 usable by others. 28 usable by others.
29 29
30 Requirements 30 Requirements
31 31
32 The main requirements are: 32 The main requirements are:
33 33
34 - separation between byte counts and time. Compressed formats may have 34 - separation between byte counts and time. Compressed formats may have
35 a header per file, per frame, or no header at all. The payload size 35 a header per file, per frame, or no header at all. The payload size
36 may vary from frame-to-frame. As a result, it is not possible to 36 may vary from frame-to-frame. As a result, it is not possible to
37 estimate reliably the duration of audio buffers when handling 37 estimate reliably the duration of audio buffers when handling
38 compressed data. Dedicated mechanisms are required to allow for 38 compressed data. Dedicated mechanisms are required to allow for
39 reliable audio-video synchronization, which requires precise 39 reliable audio-video synchronization, which requires precise
40 reporting of the number of samples rendered at any given time. 40 reporting of the number of samples rendered at any given time.
41 41
42 - Handling of multiple formats. PCM data only requires a specification 42 - Handling of multiple formats. PCM data only requires a specification
43 of the sampling rate, number of channels and bits per sample. In 43 of the sampling rate, number of channels and bits per sample. In
44 contrast, compressed data comes in a variety of formats. Audio DSPs 44 contrast, compressed data comes in a variety of formats. Audio DSPs
45 may also provide support for a limited number of audio encoders and 45 may also provide support for a limited number of audio encoders and
46 decoders embedded in firmware, or may support more choices through 46 decoders embedded in firmware, or may support more choices through
47 dynamic download of libraries. 47 dynamic download of libraries.
48 48
49 - Focus on main formats. This API provides support for the most 49 - Focus on main formats. This API provides support for the most
50 popular formats used for audio and video capture and playback. It is 50 popular formats used for audio and video capture and playback. It is
51 likely that as audio compression technology advances, new formats 51 likely that as audio compression technology advances, new formats
52 will be added. 52 will be added.
53 53
54 - Handling of multiple configurations. Even for a given format like 54 - Handling of multiple configurations. Even for a given format like
55 AAC, some implementations may support AAC multichannel but HE-AAC 55 AAC, some implementations may support AAC multichannel but HE-AAC
56 stereo. Likewise WMA10 level M3 may require too much memory and cpu 56 stereo. Likewise WMA10 level M3 may require too much memory and cpu
57 cycles. The new API needs to provide a generic way of listing these 57 cycles. The new API needs to provide a generic way of listing these
58 formats. 58 formats.
59 59
60 - Rendering/Grabbing only. This API does not provide any means of 60 - Rendering/Grabbing only. This API does not provide any means of
61 hardware acceleration, where PCM samples are provided back to 61 hardware acceleration, where PCM samples are provided back to
62 user-space for additional processing. This API focuses instead on 62 user-space for additional processing. This API focuses instead on
63 streaming compressed data to a DSP, with the assumption that the 63 streaming compressed data to a DSP, with the assumption that the
64 decoded samples are routed to a physical output or logical back-end. 64 decoded samples are routed to a physical output or logical back-end.
65 65
66 - Complexity hiding. Existing user-space multimedia frameworks all 66 - Complexity hiding. Existing user-space multimedia frameworks all
67 have existing enums/structures for each compressed format. This new 67 have existing enums/structures for each compressed format. This new
68 API assumes the existence of a platform-specific compatibility layer 68 API assumes the existence of a platform-specific compatibility layer
69 to expose, translate and make use of the capabilities of the audio 69 to expose, translate and make use of the capabilities of the audio
70 DSP, eg. Android HAL or PulseAudio sinks. By construction, regular 70 DSP, eg. Android HAL or PulseAudio sinks. By construction, regular
71 applications are not supposed to make use of this API. 71 applications are not supposed to make use of this API.
72 72
73 73
74 Design 74 Design
75 75
76 The new API shares a number of concepts with with the PCM API for flow 76 The new API shares a number of concepts with with the PCM API for flow
77 control. Start, pause, resume, drain and stop commands have the same 77 control. Start, pause, resume, drain and stop commands have the same
78 semantics no matter what the content is. 78 semantics no matter what the content is.
79 79
80 The concept of memory ring buffer divided in a set of fragments is 80 The concept of memory ring buffer divided in a set of fragments is
81 borrowed from the ALSA PCM API. However, only sizes in bytes can be 81 borrowed from the ALSA PCM API. However, only sizes in bytes can be
82 specified. 82 specified.
83 83
84 Seeks/trick modes are assumed to be handled by the host. 84 Seeks/trick modes are assumed to be handled by the host.
85 85
86 The notion of rewinds/forwards is not supported. Data committed to the 86 The notion of rewinds/forwards is not supported. Data committed to the
87 ring buffer cannot be invalidated, except when dropping all buffers. 87 ring buffer cannot be invalidated, except when dropping all buffers.
88 88
89 The Compressed Data API does not make any assumptions on how the data 89 The Compressed Data API does not make any assumptions on how the data
90 is transmitted to the audio DSP. DMA transfers from main memory to an 90 is transmitted to the audio DSP. DMA transfers from main memory to an
91 embedded audio cluster or to a SPI interface for external DSPs are 91 embedded audio cluster or to a SPI interface for external DSPs are
92 possible. As in the ALSA PCM case, a core set of routines is exposed; 92 possible. As in the ALSA PCM case, a core set of routines is exposed;
93 each driver implementer will have to write support for a set of 93 each driver implementer will have to write support for a set of
94 mandatory routines and possibly make use of optional ones. 94 mandatory routines and possibly make use of optional ones.
95 95
96 The main additions are 96 The main additions are
97 97
98 - get_caps 98 - get_caps
99 This routine returns the list of audio formats supported. Querying the 99 This routine returns the list of audio formats supported. Querying the
100 codecs on a capture stream will return encoders, decoders will be 100 codecs on a capture stream will return encoders, decoders will be
101 listed for playback streams. 101 listed for playback streams.
102 102
103 - get_codec_caps For each codec, this routine returns a list of 103 - get_codec_caps For each codec, this routine returns a list of
104 capabilities. The intent is to make sure all the capabilities 104 capabilities. The intent is to make sure all the capabilities
105 correspond to valid settings, and to minimize the risks of 105 correspond to valid settings, and to minimize the risks of
106 configuration failures. For example, for a complex codec such as AAC, 106 configuration failures. For example, for a complex codec such as AAC,
107 the number of channels supported may depend on a specific profile. If 107 the number of channels supported may depend on a specific profile. If
108 the capabilities were exposed with a single descriptor, it may happen 108 the capabilities were exposed with a single descriptor, it may happen
109 that a specific combination of profiles/channels/formats may not be 109 that a specific combination of profiles/channels/formats may not be
110 supported. Likewise, embedded DSPs have limited memory and cpu cycles, 110 supported. Likewise, embedded DSPs have limited memory and cpu cycles,
111 it is likely that some implementations make the list of capabilities 111 it is likely that some implementations make the list of capabilities
112 dynamic and dependent on existing workloads. In addition to codec 112 dynamic and dependent on existing workloads. In addition to codec
113 settings, this routine returns the minimum buffer size handled by the 113 settings, this routine returns the minimum buffer size handled by the
114 implementation. This information can be a function of the DMA buffer 114 implementation. This information can be a function of the DMA buffer
115 sizes, the number of bytes required to synchronize, etc, and can be 115 sizes, the number of bytes required to synchronize, etc, and can be
116 used by userspace to define how much needs to be written in the ring 116 used by userspace to define how much needs to be written in the ring
117 buffer before playback can start. 117 buffer before playback can start.
118 118
119 - set_params 119 - set_params
120 This routine sets the configuration chosen for a specific codec. The 120 This routine sets the configuration chosen for a specific codec. The
121 most important field in the parameters is the codec type; in most 121 most important field in the parameters is the codec type; in most
122 cases decoders will ignore other fields, while encoders will strictly 122 cases decoders will ignore other fields, while encoders will strictly
123 comply to the settings 123 comply to the settings
124 124
125 - get_params 125 - get_params
126 This routines returns the actual settings used by the DSP. Changes to 126 This routines returns the actual settings used by the DSP. Changes to
127 the settings should remain the exception. 127 the settings should remain the exception.
128 128
129 - get_timestamp 129 - get_timestamp
130 The timestamp becomes a multiple field structure. It lists the number 130 The timestamp becomes a multiple field structure. It lists the number
131 of bytes transferred, the number of samples processed and the number 131 of bytes transferred, the number of samples processed and the number
132 of samples rendered/grabbed. All these values can be used to determine 132 of samples rendered/grabbed. All these values can be used to determine
133 the avarage bitrate, figure out if the ring buffer needs to be 133 the avarage bitrate, figure out if the ring buffer needs to be
134 refilled or the delay due to decoding/encoding/io on the DSP. 134 refilled or the delay due to decoding/encoding/io on the DSP.
135 135
136 Note that the list of codecs/profiles/modes was derived from the 136 Note that the list of codecs/profiles/modes was derived from the
137 OpenMAX AL specification instead of reinventing the wheel. 137 OpenMAX AL specification instead of reinventing the wheel.
138 Modifications include: 138 Modifications include:
139 - Addition of FLAC and IEC formats 139 - Addition of FLAC and IEC formats
140 - Merge of encoder/decoder capabilities 140 - Merge of encoder/decoder capabilities
141 - Profiles/modes listed as bitmasks to make descriptors more compact 141 - Profiles/modes listed as bitmasks to make descriptors more compact
142 - Addition of set_params for decoders (missing in OpenMAX AL) 142 - Addition of set_params for decoders (missing in OpenMAX AL)
143 - Addition of AMR/AMR-WB encoding modes (missing in OpenMAX AL) 143 - Addition of AMR/AMR-WB encoding modes (missing in OpenMAX AL)
144 - Addition of format information for WMA 144 - Addition of format information for WMA
145 - Addition of encoding options when required (derived from OpenMAX IL) 145 - Addition of encoding options when required (derived from OpenMAX IL)
146 - Addition of rateControlSupported (missing in OpenMAX AL) 146 - Addition of rateControlSupported (missing in OpenMAX AL)
147 147
148 Gapless Playback
149 ================
150 When playing thru an album, the decoders have the ability to skip the encoder
151 delay and padding and directly move from one track content to another. The end
152 user can perceive this as gapless playback as we dont have silence while
153 switching from one track to another
154
155 Also, there might be low-intensity noises due to encoding. Perfect gapless is
156 difficult to reach with all types of compressed data, but works fine with most
157 music content. The decoder needs to know the encoder delay and encoder padding.
158 So we need to pass this to DSP. This metadata is extracted from ID3/MP4 headers
159 and are not present by default in the bitstream, hence the need for a new
160 interface to pass this information to the DSP. Also DSP and userspace needs to
161 switch from one track to another and start using data for second track.
162
163 The main additions are:
164
165 - set_metadata
166 This routine sets the encoder delay and encoder padding. This can be used by
167 decoder to strip the silence. This needs to be set before the data in the track
168 is written.
169
170 - set_next_track
171 This routine tells DSP that metadata and write operation sent after this would
172 correspond to subsequent track
173
174 - partial drain
175 This is called when end of file is reached. The userspace can inform DSP that
176 EOF is reached and now DSP can start skipping padding delay. Also next write
177 data would belong to next track
178
179 Sequence flow for gapless would be:
180 - Open
181 - Get caps / codec caps
182 - Set params
183 - Set metadata of the first track
184 - Fill data of the first track
185 - Trigger start
186 - User-space finished sending all,
187 - Indicaite next track data by sending set_next_track
188 - Set metadata of the next track
189 - then call partial_drain to flush most of buffer in DSP
190 - Fill data of the next track
191 - DSP switches to second track
192 (note: order for partial_drain and write for next track can be reversed as well)
193
148 Not supported: 194 Not supported:
149 195
150 - Support for VoIP/circuit-switched calls is not the target of this 196 - Support for VoIP/circuit-switched calls is not the target of this
151 API. Support for dynamic bit-rate changes would require a tight 197 API. Support for dynamic bit-rate changes would require a tight
152 coupling between the DSP and the host stack, limiting power savings. 198 coupling between the DSP and the host stack, limiting power savings.
153 199
154 - Packet-loss concealment is not supported. This would require an 200 - Packet-loss concealment is not supported. This would require an
155 additional interface to let the decoder synthesize data when frames 201 additional interface to let the decoder synthesize data when frames
156 are lost during transmission. This may be added in the future. 202 are lost during transmission. This may be added in the future.
157 203
158 - Volume control/routing is not handled by this API. Devices exposing a 204 - Volume control/routing is not handled by this API. Devices exposing a
159 compressed data interface will be considered as regular ALSA devices; 205 compressed data interface will be considered as regular ALSA devices;
160 volume changes and routing information will be provided with regular 206 volume changes and routing information will be provided with regular
161 ALSA kcontrols. 207 ALSA kcontrols.
162 208
163 - Embedded audio effects. Such effects should be enabled in the same 209 - Embedded audio effects. Such effects should be enabled in the same
164 manner, no matter if the input was PCM or compressed. 210 manner, no matter if the input was PCM or compressed.
165 211
166 - multichannel IEC encoding. Unclear if this is required. 212 - multichannel IEC encoding. Unclear if this is required.
167 213
168 - Encoding/decoding acceleration is not supported as mentioned 214 - Encoding/decoding acceleration is not supported as mentioned
169 above. It is possible to route the output of a decoder to a capture 215 above. It is possible to route the output of a decoder to a capture
170 stream, or even implement transcoding capabilities. This routing 216 stream, or even implement transcoding capabilities. This routing
171 would be enabled with ALSA kcontrols. 217 would be enabled with ALSA kcontrols.
172 218
173 - Audio policy/resource management. This API does not provide any 219 - Audio policy/resource management. This API does not provide any
174 hooks to query the utilization of the audio DSP, nor any premption 220 hooks to query the utilization of the audio DSP, nor any premption
175 mechanisms. 221 mechanisms.
176 222
177 - No notion of underun/overrun. Since the bytes written are compressed 223 - No notion of underun/overrun. Since the bytes written are compressed
178 in nature and data written/read doesn't translate directly to 224 in nature and data written/read doesn't translate directly to
179 rendered output in time, this does not deal with underrun/overun and 225 rendered output in time, this does not deal with underrun/overun and
180 maybe dealt in user-library 226 maybe dealt in user-library
181 227
182 Credits: 228 Credits:
183 - Mark Brown and Liam Girdwood for discussions on the need for this API 229 - Mark Brown and Liam Girdwood for discussions on the need for this API
184 - Harsha Priya for her work on intel_sst compressed API 230 - Harsha Priya for her work on intel_sst compressed API
185 - Rakesh Ughreja for valuable feedback 231 - Rakesh Ughreja for valuable feedback
186 - Sing Nallasellan, Sikkandar Madar and Prasanna Samaga for 232 - Sing Nallasellan, Sikkandar Madar and Prasanna Samaga for
187 demonstrating and quantifying the benefits of audio offload on a 233 demonstrating and quantifying the benefits of audio offload on a
188 real platform. 234 real platform.
189 235
include/sound/compress_driver.h
1 /* 1 /*
2 * compress_driver.h - compress offload driver definations 2 * compress_driver.h - compress offload driver definations
3 * 3 *
4 * Copyright (C) 2011 Intel Corporation 4 * Copyright (C) 2011 Intel Corporation
5 * Authors: Vinod Koul <vinod.koul@linux.intel.com> 5 * Authors: Vinod Koul <vinod.koul@linux.intel.com>
6 * Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> 6 * Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8 * 8 *
9 * This program is free software; you can redistribute it and/or modify 9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2 of the License. 11 * the Free Software Foundation; version 2 of the License.
12 * 12 *
13 * This program is distributed in the hope that it will be useful, but 13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details. 16 * General Public License for more details.
17 * 17 *
18 * You should have received a copy of the GNU General Public License along 18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc., 19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 20 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
21 * 21 *
22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23 * 23 *
24 */ 24 */
25 #ifndef __COMPRESS_DRIVER_H 25 #ifndef __COMPRESS_DRIVER_H
26 #define __COMPRESS_DRIVER_H 26 #define __COMPRESS_DRIVER_H
27 27
28 #include <linux/types.h> 28 #include <linux/types.h>
29 #include <linux/sched.h> 29 #include <linux/sched.h>
30 #include <sound/compress_offload.h> 30 #include <sound/compress_offload.h>
31 #include <sound/asound.h> 31 #include <sound/asound.h>
32 #include <sound/pcm.h> 32 #include <sound/pcm.h>
33 33
34 struct snd_compr_ops; 34 struct snd_compr_ops;
35 35
36 /** 36 /**
37 * struct snd_compr_runtime: runtime stream description 37 * struct snd_compr_runtime: runtime stream description
38 * @state: stream state 38 * @state: stream state
39 * @ops: pointer to DSP callbacks 39 * @ops: pointer to DSP callbacks
40 * @buffer: pointer to kernel buffer, valid only when not in mmap mode or 40 * @buffer: pointer to kernel buffer, valid only when not in mmap mode or
41 * DSP doesn't implement copy 41 * DSP doesn't implement copy
42 * @buffer_size: size of the above buffer 42 * @buffer_size: size of the above buffer
43 * @fragment_size: size of buffer fragment in bytes 43 * @fragment_size: size of buffer fragment in bytes
44 * @fragments: number of such fragments 44 * @fragments: number of such fragments
45 * @hw_pointer: offset of last location in buffer where DSP copied data 45 * @hw_pointer: offset of last location in buffer where DSP copied data
46 * @app_pointer: offset of last location in buffer where app wrote data 46 * @app_pointer: offset of last location in buffer where app wrote data
47 * @total_bytes_available: cumulative number of bytes made available in 47 * @total_bytes_available: cumulative number of bytes made available in
48 * the ring buffer 48 * the ring buffer
49 * @total_bytes_transferred: cumulative bytes transferred by offload DSP 49 * @total_bytes_transferred: cumulative bytes transferred by offload DSP
50 * @sleep: poll sleep 50 * @sleep: poll sleep
51 */ 51 */
52 struct snd_compr_runtime { 52 struct snd_compr_runtime {
53 snd_pcm_state_t state; 53 snd_pcm_state_t state;
54 struct snd_compr_ops *ops; 54 struct snd_compr_ops *ops;
55 void *buffer; 55 void *buffer;
56 u64 buffer_size; 56 u64 buffer_size;
57 u32 fragment_size; 57 u32 fragment_size;
58 u32 fragments; 58 u32 fragments;
59 u64 hw_pointer; 59 u64 hw_pointer;
60 u64 app_pointer; 60 u64 app_pointer;
61 u64 total_bytes_available; 61 u64 total_bytes_available;
62 u64 total_bytes_transferred; 62 u64 total_bytes_transferred;
63 wait_queue_head_t sleep; 63 wait_queue_head_t sleep;
64 void *private_data; 64 void *private_data;
65 }; 65 };
66 66
67 /** 67 /**
68 * struct snd_compr_stream: compressed stream 68 * struct snd_compr_stream: compressed stream
69 * @name: device name 69 * @name: device name
70 * @ops: pointer to DSP callbacks 70 * @ops: pointer to DSP callbacks
71 * @runtime: pointer to runtime structure 71 * @runtime: pointer to runtime structure
72 * @device: device pointer 72 * @device: device pointer
73 * @direction: stream direction, playback/recording 73 * @direction: stream direction, playback/recording
74 * @metadata_set: metadata set flag, true when set
75 * @next_track: has userspace signall next track transistion, true when set
74 * @private_data: pointer to DSP private data 76 * @private_data: pointer to DSP private data
75 */ 77 */
76 struct snd_compr_stream { 78 struct snd_compr_stream {
77 const char *name; 79 const char *name;
78 struct snd_compr_ops *ops; 80 struct snd_compr_ops *ops;
79 struct snd_compr_runtime *runtime; 81 struct snd_compr_runtime *runtime;
80 struct snd_compr *device; 82 struct snd_compr *device;
81 enum snd_compr_direction direction; 83 enum snd_compr_direction direction;
84 bool metadata_set;
85 bool next_track;
82 void *private_data; 86 void *private_data;
83 }; 87 };
84 88
85 /** 89 /**
86 * struct snd_compr_ops: compressed path DSP operations 90 * struct snd_compr_ops: compressed path DSP operations
87 * @open: Open the compressed stream 91 * @open: Open the compressed stream
88 * This callback is mandatory and shall keep dsp ready to receive the stream 92 * This callback is mandatory and shall keep dsp ready to receive the stream
89 * parameter 93 * parameter
90 * @free: Close the compressed stream, mandatory 94 * @free: Close the compressed stream, mandatory
91 * @set_params: Sets the compressed stream parameters, mandatory 95 * @set_params: Sets the compressed stream parameters, mandatory
92 * This can be called in during stream creation only to set codec params 96 * This can be called in during stream creation only to set codec params
93 * and the stream properties 97 * and the stream properties
94 * @get_params: retrieve the codec parameters, mandatory 98 * @get_params: retrieve the codec parameters, mandatory
95 * @trigger: Trigger operations like start, pause, resume, drain, stop. 99 * @trigger: Trigger operations like start, pause, resume, drain, stop.
96 * This callback is mandatory 100 * This callback is mandatory
97 * @pointer: Retrieve current h/w pointer information. Mandatory 101 * @pointer: Retrieve current h/w pointer information. Mandatory
98 * @copy: Copy the compressed data to/from userspace, Optional 102 * @copy: Copy the compressed data to/from userspace, Optional
99 * Can't be implemented if DSP supports mmap 103 * Can't be implemented if DSP supports mmap
100 * @mmap: DSP mmap method to mmap DSP memory 104 * @mmap: DSP mmap method to mmap DSP memory
101 * @ack: Ack for DSP when data is written to audio buffer, Optional 105 * @ack: Ack for DSP when data is written to audio buffer, Optional
102 * Not valid if copy is implemented 106 * Not valid if copy is implemented
103 * @get_caps: Retrieve DSP capabilities, mandatory 107 * @get_caps: Retrieve DSP capabilities, mandatory
104 * @get_codec_caps: Retrieve capabilities for a specific codec, mandatory 108 * @get_codec_caps: Retrieve capabilities for a specific codec, mandatory
105 */ 109 */
106 struct snd_compr_ops { 110 struct snd_compr_ops {
107 int (*open)(struct snd_compr_stream *stream); 111 int (*open)(struct snd_compr_stream *stream);
108 int (*free)(struct snd_compr_stream *stream); 112 int (*free)(struct snd_compr_stream *stream);
109 int (*set_params)(struct snd_compr_stream *stream, 113 int (*set_params)(struct snd_compr_stream *stream,
110 struct snd_compr_params *params); 114 struct snd_compr_params *params);
111 int (*get_params)(struct snd_compr_stream *stream, 115 int (*get_params)(struct snd_compr_stream *stream,
112 struct snd_codec *params); 116 struct snd_codec *params);
117 int (*set_metadata)(struct snd_compr_stream *stream,
118 struct snd_compr_metadata *metadata);
119 int (*get_metadata)(struct snd_compr_stream *stream,
120 struct snd_compr_metadata *metadata);
113 int (*trigger)(struct snd_compr_stream *stream, int cmd); 121 int (*trigger)(struct snd_compr_stream *stream, int cmd);
114 int (*pointer)(struct snd_compr_stream *stream, 122 int (*pointer)(struct snd_compr_stream *stream,
115 struct snd_compr_tstamp *tstamp); 123 struct snd_compr_tstamp *tstamp);
116 int (*copy)(struct snd_compr_stream *stream, const char __user *buf, 124 int (*copy)(struct snd_compr_stream *stream, const char __user *buf,
117 size_t count); 125 size_t count);
118 int (*mmap)(struct snd_compr_stream *stream, 126 int (*mmap)(struct snd_compr_stream *stream,
119 struct vm_area_struct *vma); 127 struct vm_area_struct *vma);
120 int (*ack)(struct snd_compr_stream *stream, size_t bytes); 128 int (*ack)(struct snd_compr_stream *stream, size_t bytes);
121 int (*get_caps) (struct snd_compr_stream *stream, 129 int (*get_caps) (struct snd_compr_stream *stream,
122 struct snd_compr_caps *caps); 130 struct snd_compr_caps *caps);
123 int (*get_codec_caps) (struct snd_compr_stream *stream, 131 int (*get_codec_caps) (struct snd_compr_stream *stream,
124 struct snd_compr_codec_caps *codec); 132 struct snd_compr_codec_caps *codec);
125 }; 133 };
126 134
127 /** 135 /**
128 * struct snd_compr: Compressed device 136 * struct snd_compr: Compressed device
129 * @name: DSP device name 137 * @name: DSP device name
130 * @dev: Device pointer 138 * @dev: Device pointer
131 * @ops: pointer to DSP callbacks 139 * @ops: pointer to DSP callbacks
132 * @private_data: pointer to DSP pvt data 140 * @private_data: pointer to DSP pvt data
133 * @card: sound card pointer 141 * @card: sound card pointer
134 * @direction: Playback or capture direction 142 * @direction: Playback or capture direction
135 * @lock: device lock 143 * @lock: device lock
136 * @device: device id 144 * @device: device id
137 */ 145 */
138 struct snd_compr { 146 struct snd_compr {
139 const char *name; 147 const char *name;
140 struct device *dev; 148 struct device *dev;
141 struct snd_compr_ops *ops; 149 struct snd_compr_ops *ops;
142 void *private_data; 150 void *private_data;
143 struct snd_card *card; 151 struct snd_card *card;
144 unsigned int direction; 152 unsigned int direction;
145 struct mutex lock; 153 struct mutex lock;
146 int device; 154 int device;
147 }; 155 };
148 156
149 /* compress device register APIs */ 157 /* compress device register APIs */
150 int snd_compress_register(struct snd_compr *device); 158 int snd_compress_register(struct snd_compr *device);
151 int snd_compress_deregister(struct snd_compr *device); 159 int snd_compress_deregister(struct snd_compr *device);
152 int snd_compress_new(struct snd_card *card, int device, 160 int snd_compress_new(struct snd_card *card, int device,
153 int type, struct snd_compr *compr); 161 int type, struct snd_compr *compr);
154 162
155 /* dsp driver callback apis 163 /* dsp driver callback apis
156 * For playback: driver should call snd_compress_fragment_elapsed() to let the 164 * For playback: driver should call snd_compress_fragment_elapsed() to let the
157 * framework know that a fragment has been consumed from the ring buffer 165 * framework know that a fragment has been consumed from the ring buffer
158 * 166 *
159 * For recording: we want to know when a frame is available or when 167 * For recording: we want to know when a frame is available or when
160 * at least one frame is available so snd_compress_frame_elapsed() 168 * at least one frame is available so snd_compress_frame_elapsed()
161 * callback should be called when a encodeded frame is available 169 * callback should be called when a encodeded frame is available
162 */ 170 */
163 static inline void snd_compr_fragment_elapsed(struct snd_compr_stream *stream) 171 static inline void snd_compr_fragment_elapsed(struct snd_compr_stream *stream)
164 { 172 {
165 wake_up(&stream->runtime->sleep); 173 wake_up(&stream->runtime->sleep);
166 } 174 }
167 175
168 #endif 176 #endif
169 177
include/uapi/sound/compress_offload.h
1 /* 1 /*
2 * compress_offload.h - compress offload header definations 2 * compress_offload.h - compress offload header definations
3 * 3 *
4 * Copyright (C) 2011 Intel Corporation 4 * Copyright (C) 2011 Intel Corporation
5 * Authors: Vinod Koul <vinod.koul@linux.intel.com> 5 * Authors: Vinod Koul <vinod.koul@linux.intel.com>
6 * Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> 6 * Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8 * 8 *
9 * This program is free software; you can redistribute it and/or modify 9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2 of the License. 11 * the Free Software Foundation; version 2 of the License.
12 * 12 *
13 * This program is distributed in the hope that it will be useful, but 13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details. 16 * General Public License for more details.
17 * 17 *
18 * You should have received a copy of the GNU General Public License along 18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc., 19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 20 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
21 * 21 *
22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23 * 23 *
24 */ 24 */
25 #ifndef __COMPRESS_OFFLOAD_H 25 #ifndef __COMPRESS_OFFLOAD_H
26 #define __COMPRESS_OFFLOAD_H 26 #define __COMPRESS_OFFLOAD_H
27 27
28 #include <linux/types.h> 28 #include <linux/types.h>
29 #include <sound/asound.h> 29 #include <sound/asound.h>
30 #include <sound/compress_params.h> 30 #include <sound/compress_params.h>
31 31
32 32
33 #define SNDRV_COMPRESS_VERSION SNDRV_PROTOCOL_VERSION(0, 1, 0) 33 #define SNDRV_COMPRESS_VERSION SNDRV_PROTOCOL_VERSION(0, 1, 1)
34 /** 34 /**
35 * struct snd_compressed_buffer: compressed buffer 35 * struct snd_compressed_buffer: compressed buffer
36 * @fragment_size: size of buffer fragment in bytes 36 * @fragment_size: size of buffer fragment in bytes
37 * @fragments: number of such fragments 37 * @fragments: number of such fragments
38 */ 38 */
39 struct snd_compressed_buffer { 39 struct snd_compressed_buffer {
40 __u32 fragment_size; 40 __u32 fragment_size;
41 __u32 fragments; 41 __u32 fragments;
42 }; 42 };
43 43
44 /** 44 /**
45 * struct snd_compr_params: compressed stream params 45 * struct snd_compr_params: compressed stream params
46 * @buffer: buffer description 46 * @buffer: buffer description
47 * @codec: codec parameters 47 * @codec: codec parameters
48 * @no_wake_mode: dont wake on fragment elapsed 48 * @no_wake_mode: dont wake on fragment elapsed
49 */ 49 */
50 struct snd_compr_params { 50 struct snd_compr_params {
51 struct snd_compressed_buffer buffer; 51 struct snd_compressed_buffer buffer;
52 struct snd_codec codec; 52 struct snd_codec codec;
53 __u8 no_wake_mode; 53 __u8 no_wake_mode;
54 }; 54 };
55 55
56 /** 56 /**
57 * struct snd_compr_tstamp: timestamp descriptor 57 * struct snd_compr_tstamp: timestamp descriptor
58 * @byte_offset: Byte offset in ring buffer to DSP 58 * @byte_offset: Byte offset in ring buffer to DSP
59 * @copied_total: Total number of bytes copied from/to ring buffer to/by DSP 59 * @copied_total: Total number of bytes copied from/to ring buffer to/by DSP
60 * @pcm_frames: Frames decoded or encoded by DSP. This field will evolve by 60 * @pcm_frames: Frames decoded or encoded by DSP. This field will evolve by
61 * large steps and should only be used to monitor encoding/decoding 61 * large steps and should only be used to monitor encoding/decoding
62 * progress. It shall not be used for timing estimates. 62 * progress. It shall not be used for timing estimates.
63 * @pcm_io_frames: Frames rendered or received by DSP into a mixer or an audio 63 * @pcm_io_frames: Frames rendered or received by DSP into a mixer or an audio
64 * output/input. This field should be used for A/V sync or time estimates. 64 * output/input. This field should be used for A/V sync or time estimates.
65 * @sampling_rate: sampling rate of audio 65 * @sampling_rate: sampling rate of audio
66 */ 66 */
67 struct snd_compr_tstamp { 67 struct snd_compr_tstamp {
68 __u32 byte_offset; 68 __u32 byte_offset;
69 __u32 copied_total; 69 __u32 copied_total;
70 snd_pcm_uframes_t pcm_frames; 70 snd_pcm_uframes_t pcm_frames;
71 snd_pcm_uframes_t pcm_io_frames; 71 snd_pcm_uframes_t pcm_io_frames;
72 __u32 sampling_rate; 72 __u32 sampling_rate;
73 }; 73 };
74 74
75 /** 75 /**
76 * struct snd_compr_avail: avail descriptor 76 * struct snd_compr_avail: avail descriptor
77 * @avail: Number of bytes available in ring buffer for writing/reading 77 * @avail: Number of bytes available in ring buffer for writing/reading
78 * @tstamp: timestamp infomation 78 * @tstamp: timestamp infomation
79 */ 79 */
80 struct snd_compr_avail { 80 struct snd_compr_avail {
81 __u64 avail; 81 __u64 avail;
82 struct snd_compr_tstamp tstamp; 82 struct snd_compr_tstamp tstamp;
83 }; 83 };
84 84
85 enum snd_compr_direction { 85 enum snd_compr_direction {
86 SND_COMPRESS_PLAYBACK = 0, 86 SND_COMPRESS_PLAYBACK = 0,
87 SND_COMPRESS_CAPTURE 87 SND_COMPRESS_CAPTURE
88 }; 88 };
89 89
90 /** 90 /**
91 * struct snd_compr_caps: caps descriptor 91 * struct snd_compr_caps: caps descriptor
92 * @codecs: pointer to array of codecs 92 * @codecs: pointer to array of codecs
93 * @direction: direction supported. Of type snd_compr_direction 93 * @direction: direction supported. Of type snd_compr_direction
94 * @min_fragment_size: minimum fragment supported by DSP 94 * @min_fragment_size: minimum fragment supported by DSP
95 * @max_fragment_size: maximum fragment supported by DSP 95 * @max_fragment_size: maximum fragment supported by DSP
96 * @min_fragments: min fragments supported by DSP 96 * @min_fragments: min fragments supported by DSP
97 * @max_fragments: max fragments supported by DSP 97 * @max_fragments: max fragments supported by DSP
98 * @num_codecs: number of codecs supported 98 * @num_codecs: number of codecs supported
99 * @reserved: reserved field 99 * @reserved: reserved field
100 */ 100 */
101 struct snd_compr_caps { 101 struct snd_compr_caps {
102 __u32 num_codecs; 102 __u32 num_codecs;
103 __u32 direction; 103 __u32 direction;
104 __u32 min_fragment_size; 104 __u32 min_fragment_size;
105 __u32 max_fragment_size; 105 __u32 max_fragment_size;
106 __u32 min_fragments; 106 __u32 min_fragments;
107 __u32 max_fragments; 107 __u32 max_fragments;
108 __u32 codecs[MAX_NUM_CODECS]; 108 __u32 codecs[MAX_NUM_CODECS];
109 __u32 reserved[11]; 109 __u32 reserved[11];
110 }; 110 };
111 111
112 /** 112 /**
113 * struct snd_compr_codec_caps: query capability of codec 113 * struct snd_compr_codec_caps: query capability of codec
114 * @codec: codec for which capability is queried 114 * @codec: codec for which capability is queried
115 * @num_descriptors: number of codec descriptors 115 * @num_descriptors: number of codec descriptors
116 * @descriptor: array of codec capability descriptor 116 * @descriptor: array of codec capability descriptor
117 */ 117 */
118 struct snd_compr_codec_caps { 118 struct snd_compr_codec_caps {
119 __u32 codec; 119 __u32 codec;
120 __u32 num_descriptors; 120 __u32 num_descriptors;
121 struct snd_codec_desc descriptor[MAX_NUM_CODEC_DESCRIPTORS]; 121 struct snd_codec_desc descriptor[MAX_NUM_CODEC_DESCRIPTORS];
122 }; 122 };
123 123
124 /** 124 /**
125 * @SNDRV_COMPRESS_ENCODER_PADDING: no of samples appended by the encoder at the
126 * end of the track
127 * @SNDRV_COMPRESS_ENCODER_DELAY: no of samples inserted by the encoder at the
128 * beginning of the track
129 */
130 enum {
131 SNDRV_COMPRESS_ENCODER_PADDING = 1,
132 SNDRV_COMPRESS_ENCODER_DELAY = 2,
133 };
134
135 /**
136 * struct snd_compr_metadata: compressed stream metadata
137 * @key: key id
138 * @value: key value
139 */
140 struct snd_compr_metadata {
141 __u32 key;
142 __u32 value[8];
143 };
144
145 /**
125 * compress path ioctl definitions 146 * compress path ioctl definitions
126 * SNDRV_COMPRESS_GET_CAPS: Query capability of DSP 147 * SNDRV_COMPRESS_GET_CAPS: Query capability of DSP
127 * SNDRV_COMPRESS_GET_CODEC_CAPS: Query capability of a codec 148 * SNDRV_COMPRESS_GET_CODEC_CAPS: Query capability of a codec
128 * SNDRV_COMPRESS_SET_PARAMS: Set codec and stream parameters 149 * SNDRV_COMPRESS_SET_PARAMS: Set codec and stream parameters
129 * Note: only codec params can be changed runtime and stream params cant be 150 * Note: only codec params can be changed runtime and stream params cant be
130 * SNDRV_COMPRESS_GET_PARAMS: Query codec params 151 * SNDRV_COMPRESS_GET_PARAMS: Query codec params
131 * SNDRV_COMPRESS_TSTAMP: get the current timestamp value 152 * SNDRV_COMPRESS_TSTAMP: get the current timestamp value
132 * SNDRV_COMPRESS_AVAIL: get the current buffer avail value. 153 * SNDRV_COMPRESS_AVAIL: get the current buffer avail value.
133 * This also queries the tstamp properties 154 * This also queries the tstamp properties
134 * SNDRV_COMPRESS_PAUSE: Pause the running stream 155 * SNDRV_COMPRESS_PAUSE: Pause the running stream
135 * SNDRV_COMPRESS_RESUME: resume a paused stream 156 * SNDRV_COMPRESS_RESUME: resume a paused stream
136 * SNDRV_COMPRESS_START: Start a stream 157 * SNDRV_COMPRESS_START: Start a stream
137 * SNDRV_COMPRESS_STOP: stop a running stream, discarding ring buffer content 158 * SNDRV_COMPRESS_STOP: stop a running stream, discarding ring buffer content
138 * and the buffers currently with DSP 159 * and the buffers currently with DSP
139 * SNDRV_COMPRESS_DRAIN: Play till end of buffers and stop after that 160 * SNDRV_COMPRESS_DRAIN: Play till end of buffers and stop after that
140 * SNDRV_COMPRESS_IOCTL_VERSION: Query the API version 161 * SNDRV_COMPRESS_IOCTL_VERSION: Query the API version
141 */ 162 */
142 #define SNDRV_COMPRESS_IOCTL_VERSION _IOR('C', 0x00, int) 163 #define SNDRV_COMPRESS_IOCTL_VERSION _IOR('C', 0x00, int)
143 #define SNDRV_COMPRESS_GET_CAPS _IOWR('C', 0x10, struct snd_compr_caps) 164 #define SNDRV_COMPRESS_GET_CAPS _IOWR('C', 0x10, struct snd_compr_caps)
144 #define SNDRV_COMPRESS_GET_CODEC_CAPS _IOWR('C', 0x11,\ 165 #define SNDRV_COMPRESS_GET_CODEC_CAPS _IOWR('C', 0x11,\
145 struct snd_compr_codec_caps) 166 struct snd_compr_codec_caps)
146 #define SNDRV_COMPRESS_SET_PARAMS _IOW('C', 0x12, struct snd_compr_params) 167 #define SNDRV_COMPRESS_SET_PARAMS _IOW('C', 0x12, struct snd_compr_params)
147 #define SNDRV_COMPRESS_GET_PARAMS _IOR('C', 0x13, struct snd_codec) 168 #define SNDRV_COMPRESS_GET_PARAMS _IOR('C', 0x13, struct snd_codec)
169 #define SNDRV_COMPRESS_SET_METADATA _IOW('C', 0x14,\
170 struct snd_compr_metadata)
171 #define SNDRV_COMPRESS_GET_METADATA _IOWR('C', 0x15,\
172 struct snd_compr_metadata)
148 #define SNDRV_COMPRESS_TSTAMP _IOR('C', 0x20, struct snd_compr_tstamp) 173 #define SNDRV_COMPRESS_TSTAMP _IOR('C', 0x20, struct snd_compr_tstamp)
149 #define SNDRV_COMPRESS_AVAIL _IOR('C', 0x21, struct snd_compr_avail) 174 #define SNDRV_COMPRESS_AVAIL _IOR('C', 0x21, struct snd_compr_avail)
150 #define SNDRV_COMPRESS_PAUSE _IO('C', 0x30) 175 #define SNDRV_COMPRESS_PAUSE _IO('C', 0x30)
151 #define SNDRV_COMPRESS_RESUME _IO('C', 0x31) 176 #define SNDRV_COMPRESS_RESUME _IO('C', 0x31)
152 #define SNDRV_COMPRESS_START _IO('C', 0x32) 177 #define SNDRV_COMPRESS_START _IO('C', 0x32)
153 #define SNDRV_COMPRESS_STOP _IO('C', 0x33) 178 #define SNDRV_COMPRESS_STOP _IO('C', 0x33)
154 #define SNDRV_COMPRESS_DRAIN _IO('C', 0x34) 179 #define SNDRV_COMPRESS_DRAIN _IO('C', 0x34)
180 #define SNDRV_COMPRESS_NEXT_TRACK _IO('C', 0x35)
181 #define SNDRV_COMPRESS_PARTIAL_DRAIN _IO('C', 0x36)
155 /* 182 /*
156 * TODO 183 * TODO
157 * 1. add mmap support 184 * 1. add mmap support
158 * 185 *
159 */ 186 */
160 #define SND_COMPR_TRIGGER_DRAIN 7 /*FIXME move this to pcm.h */ 187 #define SND_COMPR_TRIGGER_DRAIN 7 /*FIXME move this to pcm.h */
188 #define SND_COMPR_TRIGGER_NEXT_TRACK 8
189 #define SND_COMPR_TRIGGER_PARTIAL_DRAIN 9
161 #endif 190 #endif
162 191
sound/core/compress_offload.c
1 /* 1 /*
2 * compress_core.c - compress offload core 2 * compress_core.c - compress offload core
3 * 3 *
4 * Copyright (C) 2011 Intel Corporation 4 * Copyright (C) 2011 Intel Corporation
5 * Authors: Vinod Koul <vinod.koul@linux.intel.com> 5 * Authors: Vinod Koul <vinod.koul@linux.intel.com>
6 * Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> 6 * Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8 * 8 *
9 * This program is free software; you can redistribute it and/or modify 9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2 of the License. 11 * the Free Software Foundation; version 2 of the License.
12 * 12 *
13 * This program is distributed in the hope that it will be useful, but 13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details. 16 * General Public License for more details.
17 * 17 *
18 * You should have received a copy of the GNU General Public License along 18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc., 19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 20 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
21 * 21 *
22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23 * 23 *
24 */ 24 */
25 #define FORMAT(fmt) "%s: %d: " fmt, __func__, __LINE__ 25 #define FORMAT(fmt) "%s: %d: " fmt, __func__, __LINE__
26 #define pr_fmt(fmt) KBUILD_MODNAME ": " FORMAT(fmt) 26 #define pr_fmt(fmt) KBUILD_MODNAME ": " FORMAT(fmt)
27 27
28 #include <linux/file.h> 28 #include <linux/file.h>
29 #include <linux/fs.h> 29 #include <linux/fs.h>
30 #include <linux/list.h> 30 #include <linux/list.h>
31 #include <linux/mm.h> 31 #include <linux/mm.h>
32 #include <linux/mutex.h> 32 #include <linux/mutex.h>
33 #include <linux/poll.h> 33 #include <linux/poll.h>
34 #include <linux/slab.h> 34 #include <linux/slab.h>
35 #include <linux/sched.h> 35 #include <linux/sched.h>
36 #include <linux/uio.h> 36 #include <linux/uio.h>
37 #include <linux/uaccess.h> 37 #include <linux/uaccess.h>
38 #include <linux/module.h> 38 #include <linux/module.h>
39 #include <sound/core.h> 39 #include <sound/core.h>
40 #include <sound/initval.h> 40 #include <sound/initval.h>
41 #include <sound/compress_params.h> 41 #include <sound/compress_params.h>
42 #include <sound/compress_offload.h> 42 #include <sound/compress_offload.h>
43 #include <sound/compress_driver.h> 43 #include <sound/compress_driver.h>
44 44
45 /* TODO: 45 /* TODO:
46 * - add substream support for multiple devices in case of 46 * - add substream support for multiple devices in case of
47 * SND_DYNAMIC_MINORS is not used 47 * SND_DYNAMIC_MINORS is not used
48 * - Multiple node representation 48 * - Multiple node representation
49 * driver should be able to register multiple nodes 49 * driver should be able to register multiple nodes
50 */ 50 */
51 51
52 static DEFINE_MUTEX(device_mutex); 52 static DEFINE_MUTEX(device_mutex);
53 53
54 struct snd_compr_file { 54 struct snd_compr_file {
55 unsigned long caps; 55 unsigned long caps;
56 struct snd_compr_stream stream; 56 struct snd_compr_stream stream;
57 }; 57 };
58 58
59 /* 59 /*
60 * a note on stream states used: 60 * a note on stream states used:
61 * we use follwing states in the compressed core 61 * we use follwing states in the compressed core
62 * SNDRV_PCM_STATE_OPEN: When stream has been opened. 62 * SNDRV_PCM_STATE_OPEN: When stream has been opened.
63 * SNDRV_PCM_STATE_SETUP: When stream has been initialized. This is done by 63 * SNDRV_PCM_STATE_SETUP: When stream has been initialized. This is done by
64 * calling SNDRV_COMPRESS_SET_PARAMS. running streams will come to this 64 * calling SNDRV_COMPRESS_SET_PARAMS. running streams will come to this
65 * state at stop by calling SNDRV_COMPRESS_STOP, or at end of drain. 65 * state at stop by calling SNDRV_COMPRESS_STOP, or at end of drain.
66 * SNDRV_PCM_STATE_RUNNING: When stream has been started and is 66 * SNDRV_PCM_STATE_RUNNING: When stream has been started and is
67 * decoding/encoding and rendering/capturing data. 67 * decoding/encoding and rendering/capturing data.
68 * SNDRV_PCM_STATE_DRAINING: When stream is draining current data. This is done 68 * SNDRV_PCM_STATE_DRAINING: When stream is draining current data. This is done
69 * by calling SNDRV_COMPRESS_DRAIN. 69 * by calling SNDRV_COMPRESS_DRAIN.
70 * SNDRV_PCM_STATE_PAUSED: When stream is paused. This is done by calling 70 * SNDRV_PCM_STATE_PAUSED: When stream is paused. This is done by calling
71 * SNDRV_COMPRESS_PAUSE. It can be stopped or resumed by calling 71 * SNDRV_COMPRESS_PAUSE. It can be stopped or resumed by calling
72 * SNDRV_COMPRESS_STOP or SNDRV_COMPRESS_RESUME respectively. 72 * SNDRV_COMPRESS_STOP or SNDRV_COMPRESS_RESUME respectively.
73 */ 73 */
74 static int snd_compr_open(struct inode *inode, struct file *f) 74 static int snd_compr_open(struct inode *inode, struct file *f)
75 { 75 {
76 struct snd_compr *compr; 76 struct snd_compr *compr;
77 struct snd_compr_file *data; 77 struct snd_compr_file *data;
78 struct snd_compr_runtime *runtime; 78 struct snd_compr_runtime *runtime;
79 enum snd_compr_direction dirn; 79 enum snd_compr_direction dirn;
80 int maj = imajor(inode); 80 int maj = imajor(inode);
81 int ret; 81 int ret;
82 82
83 if ((f->f_flags & O_ACCMODE) == O_WRONLY) 83 if ((f->f_flags & O_ACCMODE) == O_WRONLY)
84 dirn = SND_COMPRESS_PLAYBACK; 84 dirn = SND_COMPRESS_PLAYBACK;
85 else if ((f->f_flags & O_ACCMODE) == O_RDONLY) 85 else if ((f->f_flags & O_ACCMODE) == O_RDONLY)
86 dirn = SND_COMPRESS_CAPTURE; 86 dirn = SND_COMPRESS_CAPTURE;
87 else 87 else
88 return -EINVAL; 88 return -EINVAL;
89 89
90 if (maj == snd_major) 90 if (maj == snd_major)
91 compr = snd_lookup_minor_data(iminor(inode), 91 compr = snd_lookup_minor_data(iminor(inode),
92 SNDRV_DEVICE_TYPE_COMPRESS); 92 SNDRV_DEVICE_TYPE_COMPRESS);
93 else 93 else
94 return -EBADFD; 94 return -EBADFD;
95 95
96 if (compr == NULL) { 96 if (compr == NULL) {
97 pr_err("no device data!!!\n"); 97 pr_err("no device data!!!\n");
98 return -ENODEV; 98 return -ENODEV;
99 } 99 }
100 100
101 if (dirn != compr->direction) { 101 if (dirn != compr->direction) {
102 pr_err("this device doesn't support this direction\n"); 102 pr_err("this device doesn't support this direction\n");
103 snd_card_unref(compr->card); 103 snd_card_unref(compr->card);
104 return -EINVAL; 104 return -EINVAL;
105 } 105 }
106 106
107 data = kzalloc(sizeof(*data), GFP_KERNEL); 107 data = kzalloc(sizeof(*data), GFP_KERNEL);
108 if (!data) { 108 if (!data) {
109 snd_card_unref(compr->card); 109 snd_card_unref(compr->card);
110 return -ENOMEM; 110 return -ENOMEM;
111 } 111 }
112 data->stream.ops = compr->ops; 112 data->stream.ops = compr->ops;
113 data->stream.direction = dirn; 113 data->stream.direction = dirn;
114 data->stream.private_data = compr->private_data; 114 data->stream.private_data = compr->private_data;
115 data->stream.device = compr; 115 data->stream.device = compr;
116 runtime = kzalloc(sizeof(*runtime), GFP_KERNEL); 116 runtime = kzalloc(sizeof(*runtime), GFP_KERNEL);
117 if (!runtime) { 117 if (!runtime) {
118 kfree(data); 118 kfree(data);
119 snd_card_unref(compr->card); 119 snd_card_unref(compr->card);
120 return -ENOMEM; 120 return -ENOMEM;
121 } 121 }
122 runtime->state = SNDRV_PCM_STATE_OPEN; 122 runtime->state = SNDRV_PCM_STATE_OPEN;
123 init_waitqueue_head(&runtime->sleep); 123 init_waitqueue_head(&runtime->sleep);
124 data->stream.runtime = runtime; 124 data->stream.runtime = runtime;
125 f->private_data = (void *)data; 125 f->private_data = (void *)data;
126 mutex_lock(&compr->lock); 126 mutex_lock(&compr->lock);
127 ret = compr->ops->open(&data->stream); 127 ret = compr->ops->open(&data->stream);
128 mutex_unlock(&compr->lock); 128 mutex_unlock(&compr->lock);
129 if (ret) { 129 if (ret) {
130 kfree(runtime); 130 kfree(runtime);
131 kfree(data); 131 kfree(data);
132 } 132 }
133 snd_card_unref(compr->card); 133 snd_card_unref(compr->card);
134 return 0; 134 return 0;
135 } 135 }
136 136
137 static int snd_compr_free(struct inode *inode, struct file *f) 137 static int snd_compr_free(struct inode *inode, struct file *f)
138 { 138 {
139 struct snd_compr_file *data = f->private_data; 139 struct snd_compr_file *data = f->private_data;
140 data->stream.ops->free(&data->stream); 140 data->stream.ops->free(&data->stream);
141 kfree(data->stream.runtime->buffer); 141 kfree(data->stream.runtime->buffer);
142 kfree(data->stream.runtime); 142 kfree(data->stream.runtime);
143 kfree(data); 143 kfree(data);
144 return 0; 144 return 0;
145 } 145 }
146 146
147 static int snd_compr_update_tstamp(struct snd_compr_stream *stream, 147 static int snd_compr_update_tstamp(struct snd_compr_stream *stream,
148 struct snd_compr_tstamp *tstamp) 148 struct snd_compr_tstamp *tstamp)
149 { 149 {
150 if (!stream->ops->pointer) 150 if (!stream->ops->pointer)
151 return -ENOTSUPP; 151 return -ENOTSUPP;
152 stream->ops->pointer(stream, tstamp); 152 stream->ops->pointer(stream, tstamp);
153 pr_debug("dsp consumed till %d total %d bytes\n", 153 pr_debug("dsp consumed till %d total %d bytes\n",
154 tstamp->byte_offset, tstamp->copied_total); 154 tstamp->byte_offset, tstamp->copied_total);
155 stream->runtime->hw_pointer = tstamp->byte_offset; 155 stream->runtime->hw_pointer = tstamp->byte_offset;
156 stream->runtime->total_bytes_transferred = tstamp->copied_total; 156 stream->runtime->total_bytes_transferred = tstamp->copied_total;
157 return 0; 157 return 0;
158 } 158 }
159 159
160 static size_t snd_compr_calc_avail(struct snd_compr_stream *stream, 160 static size_t snd_compr_calc_avail(struct snd_compr_stream *stream,
161 struct snd_compr_avail *avail) 161 struct snd_compr_avail *avail)
162 { 162 {
163 long avail_calc; /*this needs to be signed variable */ 163 long avail_calc; /*this needs to be signed variable */
164 164
165 memset(avail, 0, sizeof(*avail)); 165 memset(avail, 0, sizeof(*avail));
166 snd_compr_update_tstamp(stream, &avail->tstamp); 166 snd_compr_update_tstamp(stream, &avail->tstamp);
167 /* Still need to return avail even if tstamp can't be filled in */ 167 /* Still need to return avail even if tstamp can't be filled in */
168 168
169 /* FIXME: This needs to be different for capture stream, 169 /* FIXME: This needs to be different for capture stream,
170 available is # of compressed data, for playback it's 170 available is # of compressed data, for playback it's
171 remainder of buffer */ 171 remainder of buffer */
172 172
173 if (stream->runtime->total_bytes_available == 0 && 173 if (stream->runtime->total_bytes_available == 0 &&
174 stream->runtime->state == SNDRV_PCM_STATE_SETUP) { 174 stream->runtime->state == SNDRV_PCM_STATE_SETUP) {
175 pr_debug("detected init and someone forgot to do a write\n"); 175 pr_debug("detected init and someone forgot to do a write\n");
176 return stream->runtime->buffer_size; 176 return stream->runtime->buffer_size;
177 } 177 }
178 pr_debug("app wrote %lld, DSP consumed %lld\n", 178 pr_debug("app wrote %lld, DSP consumed %lld\n",
179 stream->runtime->total_bytes_available, 179 stream->runtime->total_bytes_available,
180 stream->runtime->total_bytes_transferred); 180 stream->runtime->total_bytes_transferred);
181 if (stream->runtime->total_bytes_available == 181 if (stream->runtime->total_bytes_available ==
182 stream->runtime->total_bytes_transferred) { 182 stream->runtime->total_bytes_transferred) {
183 pr_debug("both pointers are same, returning full avail\n"); 183 pr_debug("both pointers are same, returning full avail\n");
184 return stream->runtime->buffer_size; 184 return stream->runtime->buffer_size;
185 } 185 }
186 186
187 /* FIXME: this routine isn't consistent, in one test we use 187 /* FIXME: this routine isn't consistent, in one test we use
188 * cumulative values and in the other byte offsets. Do we 188 * cumulative values and in the other byte offsets. Do we
189 * really need the byte offsets if the cumulative values have 189 * really need the byte offsets if the cumulative values have
190 * been updated? In the PCM interface app_ptr and hw_ptr are 190 * been updated? In the PCM interface app_ptr and hw_ptr are
191 * already cumulative */ 191 * already cumulative */
192 192
193 avail_calc = stream->runtime->buffer_size - 193 avail_calc = stream->runtime->buffer_size -
194 (stream->runtime->app_pointer - stream->runtime->hw_pointer); 194 (stream->runtime->app_pointer - stream->runtime->hw_pointer);
195 pr_debug("calc avail as %ld, app_ptr %lld, hw+ptr %lld\n", avail_calc, 195 pr_debug("calc avail as %ld, app_ptr %lld, hw+ptr %lld\n", avail_calc,
196 stream->runtime->app_pointer, 196 stream->runtime->app_pointer,
197 stream->runtime->hw_pointer); 197 stream->runtime->hw_pointer);
198 if (avail_calc >= stream->runtime->buffer_size) 198 if (avail_calc >= stream->runtime->buffer_size)
199 avail_calc -= stream->runtime->buffer_size; 199 avail_calc -= stream->runtime->buffer_size;
200 pr_debug("ret avail as %ld\n", avail_calc); 200 pr_debug("ret avail as %ld\n", avail_calc);
201 avail->avail = avail_calc; 201 avail->avail = avail_calc;
202 return avail_calc; 202 return avail_calc;
203 } 203 }
204 204
205 static inline size_t snd_compr_get_avail(struct snd_compr_stream *stream) 205 static inline size_t snd_compr_get_avail(struct snd_compr_stream *stream)
206 { 206 {
207 struct snd_compr_avail avail; 207 struct snd_compr_avail avail;
208 208
209 return snd_compr_calc_avail(stream, &avail); 209 return snd_compr_calc_avail(stream, &avail);
210 } 210 }
211 211
212 static int 212 static int
213 snd_compr_ioctl_avail(struct snd_compr_stream *stream, unsigned long arg) 213 snd_compr_ioctl_avail(struct snd_compr_stream *stream, unsigned long arg)
214 { 214 {
215 struct snd_compr_avail ioctl_avail; 215 struct snd_compr_avail ioctl_avail;
216 size_t avail; 216 size_t avail;
217 217
218 avail = snd_compr_calc_avail(stream, &ioctl_avail); 218 avail = snd_compr_calc_avail(stream, &ioctl_avail);
219 ioctl_avail.avail = avail; 219 ioctl_avail.avail = avail;
220 220
221 if (copy_to_user((__u64 __user *)arg, 221 if (copy_to_user((__u64 __user *)arg,
222 &ioctl_avail, sizeof(ioctl_avail))) 222 &ioctl_avail, sizeof(ioctl_avail)))
223 return -EFAULT; 223 return -EFAULT;
224 return 0; 224 return 0;
225 } 225 }
226 226
227 static int snd_compr_write_data(struct snd_compr_stream *stream, 227 static int snd_compr_write_data(struct snd_compr_stream *stream,
228 const char __user *buf, size_t count) 228 const char __user *buf, size_t count)
229 { 229 {
230 void *dstn; 230 void *dstn;
231 size_t copy; 231 size_t copy;
232 struct snd_compr_runtime *runtime = stream->runtime; 232 struct snd_compr_runtime *runtime = stream->runtime;
233 233
234 dstn = runtime->buffer + runtime->app_pointer; 234 dstn = runtime->buffer + runtime->app_pointer;
235 pr_debug("copying %ld at %lld\n", 235 pr_debug("copying %ld at %lld\n",
236 (unsigned long)count, runtime->app_pointer); 236 (unsigned long)count, runtime->app_pointer);
237 if (count < runtime->buffer_size - runtime->app_pointer) { 237 if (count < runtime->buffer_size - runtime->app_pointer) {
238 if (copy_from_user(dstn, buf, count)) 238 if (copy_from_user(dstn, buf, count))
239 return -EFAULT; 239 return -EFAULT;
240 runtime->app_pointer += count; 240 runtime->app_pointer += count;
241 } else { 241 } else {
242 copy = runtime->buffer_size - runtime->app_pointer; 242 copy = runtime->buffer_size - runtime->app_pointer;
243 if (copy_from_user(dstn, buf, copy)) 243 if (copy_from_user(dstn, buf, copy))
244 return -EFAULT; 244 return -EFAULT;
245 if (copy_from_user(runtime->buffer, buf + copy, count - copy)) 245 if (copy_from_user(runtime->buffer, buf + copy, count - copy))
246 return -EFAULT; 246 return -EFAULT;
247 runtime->app_pointer = count - copy; 247 runtime->app_pointer = count - copy;
248 } 248 }
249 /* if DSP cares, let it know data has been written */ 249 /* if DSP cares, let it know data has been written */
250 if (stream->ops->ack) 250 if (stream->ops->ack)
251 stream->ops->ack(stream, count); 251 stream->ops->ack(stream, count);
252 return count; 252 return count;
253 } 253 }
254 254
255 static ssize_t snd_compr_write(struct file *f, const char __user *buf, 255 static ssize_t snd_compr_write(struct file *f, const char __user *buf,
256 size_t count, loff_t *offset) 256 size_t count, loff_t *offset)
257 { 257 {
258 struct snd_compr_file *data = f->private_data; 258 struct snd_compr_file *data = f->private_data;
259 struct snd_compr_stream *stream; 259 struct snd_compr_stream *stream;
260 size_t avail; 260 size_t avail;
261 int retval; 261 int retval;
262 262
263 if (snd_BUG_ON(!data)) 263 if (snd_BUG_ON(!data))
264 return -EFAULT; 264 return -EFAULT;
265 265
266 stream = &data->stream; 266 stream = &data->stream;
267 mutex_lock(&stream->device->lock); 267 mutex_lock(&stream->device->lock);
268 /* write is allowed when stream is running or has been steup */ 268 /* write is allowed when stream is running or has been steup */
269 if (stream->runtime->state != SNDRV_PCM_STATE_SETUP && 269 if (stream->runtime->state != SNDRV_PCM_STATE_SETUP &&
270 stream->runtime->state != SNDRV_PCM_STATE_RUNNING) { 270 stream->runtime->state != SNDRV_PCM_STATE_RUNNING) {
271 mutex_unlock(&stream->device->lock); 271 mutex_unlock(&stream->device->lock);
272 return -EBADFD; 272 return -EBADFD;
273 } 273 }
274 274
275 avail = snd_compr_get_avail(stream); 275 avail = snd_compr_get_avail(stream);
276 pr_debug("avail returned %ld\n", (unsigned long)avail); 276 pr_debug("avail returned %ld\n", (unsigned long)avail);
277 /* calculate how much we can write to buffer */ 277 /* calculate how much we can write to buffer */
278 if (avail > count) 278 if (avail > count)
279 avail = count; 279 avail = count;
280 280
281 if (stream->ops->copy) 281 if (stream->ops->copy)
282 retval = stream->ops->copy(stream, buf, avail); 282 retval = stream->ops->copy(stream, buf, avail);
283 else 283 else
284 retval = snd_compr_write_data(stream, buf, avail); 284 retval = snd_compr_write_data(stream, buf, avail);
285 if (retval > 0) 285 if (retval > 0)
286 stream->runtime->total_bytes_available += retval; 286 stream->runtime->total_bytes_available += retval;
287 287
288 /* while initiating the stream, write should be called before START 288 /* while initiating the stream, write should be called before START
289 * call, so in setup move state */ 289 * call, so in setup move state */
290 if (stream->runtime->state == SNDRV_PCM_STATE_SETUP) { 290 if (stream->runtime->state == SNDRV_PCM_STATE_SETUP) {
291 stream->runtime->state = SNDRV_PCM_STATE_PREPARED; 291 stream->runtime->state = SNDRV_PCM_STATE_PREPARED;
292 pr_debug("stream prepared, Houston we are good to go\n"); 292 pr_debug("stream prepared, Houston we are good to go\n");
293 } 293 }
294 294
295 mutex_unlock(&stream->device->lock); 295 mutex_unlock(&stream->device->lock);
296 return retval; 296 return retval;
297 } 297 }
298 298
299 299
300 static ssize_t snd_compr_read(struct file *f, char __user *buf, 300 static ssize_t snd_compr_read(struct file *f, char __user *buf,
301 size_t count, loff_t *offset) 301 size_t count, loff_t *offset)
302 { 302 {
303 return -ENXIO; 303 return -ENXIO;
304 } 304 }
305 305
306 static int snd_compr_mmap(struct file *f, struct vm_area_struct *vma) 306 static int snd_compr_mmap(struct file *f, struct vm_area_struct *vma)
307 { 307 {
308 return -ENXIO; 308 return -ENXIO;
309 } 309 }
310 310
311 static inline int snd_compr_get_poll(struct snd_compr_stream *stream) 311 static inline int snd_compr_get_poll(struct snd_compr_stream *stream)
312 { 312 {
313 if (stream->direction == SND_COMPRESS_PLAYBACK) 313 if (stream->direction == SND_COMPRESS_PLAYBACK)
314 return POLLOUT | POLLWRNORM; 314 return POLLOUT | POLLWRNORM;
315 else 315 else
316 return POLLIN | POLLRDNORM; 316 return POLLIN | POLLRDNORM;
317 } 317 }
318 318
319 static unsigned int snd_compr_poll(struct file *f, poll_table *wait) 319 static unsigned int snd_compr_poll(struct file *f, poll_table *wait)
320 { 320 {
321 struct snd_compr_file *data = f->private_data; 321 struct snd_compr_file *data = f->private_data;
322 struct snd_compr_stream *stream; 322 struct snd_compr_stream *stream;
323 size_t avail; 323 size_t avail;
324 int retval = 0; 324 int retval = 0;
325 325
326 if (snd_BUG_ON(!data)) 326 if (snd_BUG_ON(!data))
327 return -EFAULT; 327 return -EFAULT;
328 stream = &data->stream; 328 stream = &data->stream;
329 if (snd_BUG_ON(!stream)) 329 if (snd_BUG_ON(!stream))
330 return -EFAULT; 330 return -EFAULT;
331 331
332 mutex_lock(&stream->device->lock); 332 mutex_lock(&stream->device->lock);
333 if (stream->runtime->state == SNDRV_PCM_STATE_PAUSED || 333 if (stream->runtime->state == SNDRV_PCM_STATE_PAUSED ||
334 stream->runtime->state == SNDRV_PCM_STATE_OPEN) { 334 stream->runtime->state == SNDRV_PCM_STATE_OPEN) {
335 retval = -EBADFD; 335 retval = -EBADFD;
336 goto out; 336 goto out;
337 } 337 }
338 poll_wait(f, &stream->runtime->sleep, wait); 338 poll_wait(f, &stream->runtime->sleep, wait);
339 339
340 avail = snd_compr_get_avail(stream); 340 avail = snd_compr_get_avail(stream);
341 pr_debug("avail is %ld\n", (unsigned long)avail); 341 pr_debug("avail is %ld\n", (unsigned long)avail);
342 /* check if we have at least one fragment to fill */ 342 /* check if we have at least one fragment to fill */
343 switch (stream->runtime->state) { 343 switch (stream->runtime->state) {
344 case SNDRV_PCM_STATE_DRAINING: 344 case SNDRV_PCM_STATE_DRAINING:
345 /* stream has been woken up after drain is complete 345 /* stream has been woken up after drain is complete
346 * draining done so set stream state to stopped 346 * draining done so set stream state to stopped
347 */ 347 */
348 retval = snd_compr_get_poll(stream); 348 retval = snd_compr_get_poll(stream);
349 stream->runtime->state = SNDRV_PCM_STATE_SETUP; 349 stream->runtime->state = SNDRV_PCM_STATE_SETUP;
350 break; 350 break;
351 case SNDRV_PCM_STATE_RUNNING: 351 case SNDRV_PCM_STATE_RUNNING:
352 case SNDRV_PCM_STATE_PREPARED: 352 case SNDRV_PCM_STATE_PREPARED:
353 case SNDRV_PCM_STATE_PAUSED: 353 case SNDRV_PCM_STATE_PAUSED:
354 if (avail >= stream->runtime->fragment_size) 354 if (avail >= stream->runtime->fragment_size)
355 retval = snd_compr_get_poll(stream); 355 retval = snd_compr_get_poll(stream);
356 break; 356 break;
357 default: 357 default:
358 if (stream->direction == SND_COMPRESS_PLAYBACK) 358 if (stream->direction == SND_COMPRESS_PLAYBACK)
359 retval = POLLOUT | POLLWRNORM | POLLERR; 359 retval = POLLOUT | POLLWRNORM | POLLERR;
360 else 360 else
361 retval = POLLIN | POLLRDNORM | POLLERR; 361 retval = POLLIN | POLLRDNORM | POLLERR;
362 break; 362 break;
363 } 363 }
364 out: 364 out:
365 mutex_unlock(&stream->device->lock); 365 mutex_unlock(&stream->device->lock);
366 return retval; 366 return retval;
367 } 367 }
368 368
369 static int 369 static int
370 snd_compr_get_caps(struct snd_compr_stream *stream, unsigned long arg) 370 snd_compr_get_caps(struct snd_compr_stream *stream, unsigned long arg)
371 { 371 {
372 int retval; 372 int retval;
373 struct snd_compr_caps caps; 373 struct snd_compr_caps caps;
374 374
375 if (!stream->ops->get_caps) 375 if (!stream->ops->get_caps)
376 return -ENXIO; 376 return -ENXIO;
377 377
378 retval = stream->ops->get_caps(stream, &caps); 378 retval = stream->ops->get_caps(stream, &caps);
379 if (retval) 379 if (retval)
380 goto out; 380 goto out;
381 if (copy_to_user((void __user *)arg, &caps, sizeof(caps))) 381 if (copy_to_user((void __user *)arg, &caps, sizeof(caps)))
382 retval = -EFAULT; 382 retval = -EFAULT;
383 out: 383 out:
384 return retval; 384 return retval;
385 } 385 }
386 386
387 static int 387 static int
388 snd_compr_get_codec_caps(struct snd_compr_stream *stream, unsigned long arg) 388 snd_compr_get_codec_caps(struct snd_compr_stream *stream, unsigned long arg)
389 { 389 {
390 int retval; 390 int retval;
391 struct snd_compr_codec_caps *caps; 391 struct snd_compr_codec_caps *caps;
392 392
393 if (!stream->ops->get_codec_caps) 393 if (!stream->ops->get_codec_caps)
394 return -ENXIO; 394 return -ENXIO;
395 395
396 caps = kmalloc(sizeof(*caps), GFP_KERNEL); 396 caps = kmalloc(sizeof(*caps), GFP_KERNEL);
397 if (!caps) 397 if (!caps)
398 return -ENOMEM; 398 return -ENOMEM;
399 399
400 retval = stream->ops->get_codec_caps(stream, caps); 400 retval = stream->ops->get_codec_caps(stream, caps);
401 if (retval) 401 if (retval)
402 goto out; 402 goto out;
403 if (copy_to_user((void __user *)arg, caps, sizeof(*caps))) 403 if (copy_to_user((void __user *)arg, caps, sizeof(*caps)))
404 retval = -EFAULT; 404 retval = -EFAULT;
405 405
406 out: 406 out:
407 kfree(caps); 407 kfree(caps);
408 return retval; 408 return retval;
409 } 409 }
410 410
411 /* revisit this with snd_pcm_preallocate_xxx */ 411 /* revisit this with snd_pcm_preallocate_xxx */
412 static int snd_compr_allocate_buffer(struct snd_compr_stream *stream, 412 static int snd_compr_allocate_buffer(struct snd_compr_stream *stream,
413 struct snd_compr_params *params) 413 struct snd_compr_params *params)
414 { 414 {
415 unsigned int buffer_size; 415 unsigned int buffer_size;
416 void *buffer; 416 void *buffer;
417 417
418 buffer_size = params->buffer.fragment_size * params->buffer.fragments; 418 buffer_size = params->buffer.fragment_size * params->buffer.fragments;
419 if (stream->ops->copy) { 419 if (stream->ops->copy) {
420 buffer = NULL; 420 buffer = NULL;
421 /* if copy is defined the driver will be required to copy 421 /* if copy is defined the driver will be required to copy
422 * the data from core 422 * the data from core
423 */ 423 */
424 } else { 424 } else {
425 buffer = kmalloc(buffer_size, GFP_KERNEL); 425 buffer = kmalloc(buffer_size, GFP_KERNEL);
426 if (!buffer) 426 if (!buffer)
427 return -ENOMEM; 427 return -ENOMEM;
428 } 428 }
429 stream->runtime->fragment_size = params->buffer.fragment_size; 429 stream->runtime->fragment_size = params->buffer.fragment_size;
430 stream->runtime->fragments = params->buffer.fragments; 430 stream->runtime->fragments = params->buffer.fragments;
431 stream->runtime->buffer = buffer; 431 stream->runtime->buffer = buffer;
432 stream->runtime->buffer_size = buffer_size; 432 stream->runtime->buffer_size = buffer_size;
433 return 0; 433 return 0;
434 } 434 }
435 435
436 static int snd_compress_check_input(struct snd_compr_params *params) 436 static int snd_compress_check_input(struct snd_compr_params *params)
437 { 437 {
438 /* first let's check the buffer parameter's */ 438 /* first let's check the buffer parameter's */
439 if (params->buffer.fragment_size == 0 || 439 if (params->buffer.fragment_size == 0 ||
440 params->buffer.fragments > SIZE_MAX / params->buffer.fragment_size) 440 params->buffer.fragments > SIZE_MAX / params->buffer.fragment_size)
441 return -EINVAL; 441 return -EINVAL;
442 442
443 /* now codec parameters */ 443 /* now codec parameters */
444 if (params->codec.id == 0 || params->codec.id > SND_AUDIOCODEC_MAX) 444 if (params->codec.id == 0 || params->codec.id > SND_AUDIOCODEC_MAX)
445 return -EINVAL; 445 return -EINVAL;
446 446
447 if (params->codec.ch_in == 0 || params->codec.ch_out == 0) 447 if (params->codec.ch_in == 0 || params->codec.ch_out == 0)
448 return -EINVAL; 448 return -EINVAL;
449 449
450 if (!(params->codec.sample_rate & SNDRV_PCM_RATE_8000_192000)) 450 if (!(params->codec.sample_rate & SNDRV_PCM_RATE_8000_192000))
451 return -EINVAL; 451 return -EINVAL;
452 452
453 return 0; 453 return 0;
454 } 454 }
455 455
456 static int 456 static int
457 snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg) 457 snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
458 { 458 {
459 struct snd_compr_params *params; 459 struct snd_compr_params *params;
460 int retval; 460 int retval;
461 461
462 if (stream->runtime->state == SNDRV_PCM_STATE_OPEN) { 462 if (stream->runtime->state == SNDRV_PCM_STATE_OPEN) {
463 /* 463 /*
464 * we should allow parameter change only when stream has been 464 * we should allow parameter change only when stream has been
465 * opened not in other cases 465 * opened not in other cases
466 */ 466 */
467 params = kmalloc(sizeof(*params), GFP_KERNEL); 467 params = kmalloc(sizeof(*params), GFP_KERNEL);
468 if (!params) 468 if (!params)
469 return -ENOMEM; 469 return -ENOMEM;
470 if (copy_from_user(params, (void __user *)arg, sizeof(*params))) { 470 if (copy_from_user(params, (void __user *)arg, sizeof(*params))) {
471 retval = -EFAULT; 471 retval = -EFAULT;
472 goto out; 472 goto out;
473 } 473 }
474 474
475 retval = snd_compress_check_input(params); 475 retval = snd_compress_check_input(params);
476 if (retval) 476 if (retval)
477 goto out; 477 goto out;
478 478
479 retval = snd_compr_allocate_buffer(stream, params); 479 retval = snd_compr_allocate_buffer(stream, params);
480 if (retval) { 480 if (retval) {
481 retval = -ENOMEM; 481 retval = -ENOMEM;
482 goto out; 482 goto out;
483 } 483 }
484 484
485 retval = stream->ops->set_params(stream, params); 485 retval = stream->ops->set_params(stream, params);
486 if (retval) 486 if (retval)
487 goto out; 487 goto out;
488 stream->runtime->state = SNDRV_PCM_STATE_SETUP; 488 stream->runtime->state = SNDRV_PCM_STATE_SETUP;
489 stream->metadata_set = false;
490 stream->next_track = false;
489 } else { 491 } else {
490 return -EPERM; 492 return -EPERM;
491 } 493 }
492 out: 494 out:
493 kfree(params); 495 kfree(params);
494 return retval; 496 return retval;
495 } 497 }
496 498
497 static int 499 static int
498 snd_compr_get_params(struct snd_compr_stream *stream, unsigned long arg) 500 snd_compr_get_params(struct snd_compr_stream *stream, unsigned long arg)
499 { 501 {
500 struct snd_codec *params; 502 struct snd_codec *params;
501 int retval; 503 int retval;
502 504
503 if (!stream->ops->get_params) 505 if (!stream->ops->get_params)
504 return -EBADFD; 506 return -EBADFD;
505 507
506 params = kmalloc(sizeof(*params), GFP_KERNEL); 508 params = kmalloc(sizeof(*params), GFP_KERNEL);
507 if (!params) 509 if (!params)
508 return -ENOMEM; 510 return -ENOMEM;
509 retval = stream->ops->get_params(stream, params); 511 retval = stream->ops->get_params(stream, params);
510 if (retval) 512 if (retval)
511 goto out; 513 goto out;
512 if (copy_to_user((char __user *)arg, params, sizeof(*params))) 514 if (copy_to_user((char __user *)arg, params, sizeof(*params)))
513 retval = -EFAULT; 515 retval = -EFAULT;
514 516
515 out: 517 out:
516 kfree(params); 518 kfree(params);
517 return retval; 519 return retval;
518 } 520 }
519 521
522 static int
523 snd_compr_get_metadata(struct snd_compr_stream *stream, unsigned long arg)
524 {
525 struct snd_compr_metadata metadata;
526 int retval;
527
528 if (!stream->ops->get_metadata)
529 return -ENXIO;
530
531 if (copy_from_user(&metadata, (void __user *)arg, sizeof(metadata)))
532 return -EFAULT;
533
534 retval = stream->ops->get_metadata(stream, &metadata);
535 if (retval != 0)
536 return retval;
537
538 if (copy_to_user((void __user *)arg, &metadata, sizeof(metadata)))
539 return -EFAULT;
540
541 return 0;
542 }
543
544 static int
545 snd_compr_set_metadata(struct snd_compr_stream *stream, unsigned long arg)
546 {
547 struct snd_compr_metadata metadata;
548 int retval;
549
550 if (!stream->ops->set_metadata)
551 return -ENXIO;
552 /*
553 * we should allow parameter change only when stream has been
554 * opened not in other cases
555 */
556 if (copy_from_user(&metadata, (void __user *)arg, sizeof(metadata)))
557 return -EFAULT;
558
559 retval = stream->ops->set_metadata(stream, &metadata);
560 stream->metadata_set = true;
561
562 return retval;
563 }
564
520 static inline int 565 static inline int
521 snd_compr_tstamp(struct snd_compr_stream *stream, unsigned long arg) 566 snd_compr_tstamp(struct snd_compr_stream *stream, unsigned long arg)
522 { 567 {
523 struct snd_compr_tstamp tstamp = {0}; 568 struct snd_compr_tstamp tstamp = {0};
524 int ret; 569 int ret;
525 570
526 ret = snd_compr_update_tstamp(stream, &tstamp); 571 ret = snd_compr_update_tstamp(stream, &tstamp);
527 if (ret == 0) 572 if (ret == 0)
528 ret = copy_to_user((struct snd_compr_tstamp __user *)arg, 573 ret = copy_to_user((struct snd_compr_tstamp __user *)arg,
529 &tstamp, sizeof(tstamp)) ? -EFAULT : 0; 574 &tstamp, sizeof(tstamp)) ? -EFAULT : 0;
530 return ret; 575 return ret;
531 } 576 }
532 577
533 static int snd_compr_pause(struct snd_compr_stream *stream) 578 static int snd_compr_pause(struct snd_compr_stream *stream)
534 { 579 {
535 int retval; 580 int retval;
536 581
537 if (stream->runtime->state != SNDRV_PCM_STATE_RUNNING) 582 if (stream->runtime->state != SNDRV_PCM_STATE_RUNNING)
538 return -EPERM; 583 return -EPERM;
539 retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_PUSH); 584 retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_PUSH);
540 if (!retval) 585 if (!retval)
541 stream->runtime->state = SNDRV_PCM_STATE_PAUSED; 586 stream->runtime->state = SNDRV_PCM_STATE_PAUSED;
542 return retval; 587 return retval;
543 } 588 }
544 589
545 static int snd_compr_resume(struct snd_compr_stream *stream) 590 static int snd_compr_resume(struct snd_compr_stream *stream)
546 { 591 {
547 int retval; 592 int retval;
548 593
549 if (stream->runtime->state != SNDRV_PCM_STATE_PAUSED) 594 if (stream->runtime->state != SNDRV_PCM_STATE_PAUSED)
550 return -EPERM; 595 return -EPERM;
551 retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_RELEASE); 596 retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_RELEASE);
552 if (!retval) 597 if (!retval)
553 stream->runtime->state = SNDRV_PCM_STATE_RUNNING; 598 stream->runtime->state = SNDRV_PCM_STATE_RUNNING;
554 return retval; 599 return retval;
555 } 600 }
556 601
557 static int snd_compr_start(struct snd_compr_stream *stream) 602 static int snd_compr_start(struct snd_compr_stream *stream)
558 { 603 {
559 int retval; 604 int retval;
560 605
561 if (stream->runtime->state != SNDRV_PCM_STATE_PREPARED) 606 if (stream->runtime->state != SNDRV_PCM_STATE_PREPARED)
562 return -EPERM; 607 return -EPERM;
563 retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_START); 608 retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_START);
564 if (!retval) 609 if (!retval)
565 stream->runtime->state = SNDRV_PCM_STATE_RUNNING; 610 stream->runtime->state = SNDRV_PCM_STATE_RUNNING;
566 return retval; 611 return retval;
567 } 612 }
568 613
569 static int snd_compr_stop(struct snd_compr_stream *stream) 614 static int snd_compr_stop(struct snd_compr_stream *stream)
570 { 615 {
571 int retval; 616 int retval;
572 617
573 if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED || 618 if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED ||
574 stream->runtime->state == SNDRV_PCM_STATE_SETUP) 619 stream->runtime->state == SNDRV_PCM_STATE_SETUP)
575 return -EPERM; 620 return -EPERM;
576 retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_STOP); 621 retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_STOP);
577 if (!retval) { 622 if (!retval) {
578 stream->runtime->state = SNDRV_PCM_STATE_SETUP; 623 stream->runtime->state = SNDRV_PCM_STATE_SETUP;
579 wake_up(&stream->runtime->sleep); 624 wake_up(&stream->runtime->sleep);
580 stream->runtime->hw_pointer = 0; 625 stream->runtime->hw_pointer = 0;
581 stream->runtime->app_pointer = 0; 626 stream->runtime->app_pointer = 0;
582 stream->runtime->total_bytes_available = 0; 627 stream->runtime->total_bytes_available = 0;
583 stream->runtime->total_bytes_transferred = 0; 628 stream->runtime->total_bytes_transferred = 0;
584 } 629 }
585 return retval; 630 return retval;
586 } 631 }
587 632
588 static int snd_compr_drain(struct snd_compr_stream *stream) 633 static int snd_compr_drain(struct snd_compr_stream *stream)
589 { 634 {
590 int retval; 635 int retval;
591 636
592 if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED || 637 if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED ||
593 stream->runtime->state == SNDRV_PCM_STATE_SETUP) 638 stream->runtime->state == SNDRV_PCM_STATE_SETUP)
594 return -EPERM; 639 return -EPERM;
595 retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_DRAIN); 640 retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_DRAIN);
596 if (!retval) { 641 if (!retval) {
597 stream->runtime->state = SNDRV_PCM_STATE_DRAINING; 642 stream->runtime->state = SNDRV_PCM_STATE_DRAINING;
598 wake_up(&stream->runtime->sleep); 643 wake_up(&stream->runtime->sleep);
599 } 644 }
600 return retval; 645 return retval;
601 } 646 }
602 647
648 static int snd_compr_next_track(struct snd_compr_stream *stream)
649 {
650 int retval;
651
652 /* only a running stream can transition to next track */
653 if (stream->runtime->state != SNDRV_PCM_STATE_RUNNING)
654 return -EPERM;
655
656 /* you can signal next track isf this is intended to be a gapless stream
657 * and current track metadata is set
658 */
659 if (stream->metadata_set == false)
660 return -EPERM;
661
662 retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_NEXT_TRACK);
663 if (retval != 0)
664 return retval;
665 stream->metadata_set = false;
666 stream->next_track = true;
667 return 0;
668 }
669
670 static int snd_compr_partial_drain(struct snd_compr_stream *stream)
671 {
672 int retval;
673 if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED ||
674 stream->runtime->state == SNDRV_PCM_STATE_SETUP)
675 return -EPERM;
676 /* stream can be drained only when next track has been signalled */
677 if (stream->next_track == false)
678 return -EPERM;
679
680 retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_PARTIAL_DRAIN);
681
682 stream->next_track = false;
683 return retval;
684 }
685
603 static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg) 686 static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
604 { 687 {
605 struct snd_compr_file *data = f->private_data; 688 struct snd_compr_file *data = f->private_data;
606 struct snd_compr_stream *stream; 689 struct snd_compr_stream *stream;
607 int retval = -ENOTTY; 690 int retval = -ENOTTY;
608 691
609 if (snd_BUG_ON(!data)) 692 if (snd_BUG_ON(!data))
610 return -EFAULT; 693 return -EFAULT;
611 stream = &data->stream; 694 stream = &data->stream;
612 if (snd_BUG_ON(!stream)) 695 if (snd_BUG_ON(!stream))
613 return -EFAULT; 696 return -EFAULT;
614 mutex_lock(&stream->device->lock); 697 mutex_lock(&stream->device->lock);
615 switch (_IOC_NR(cmd)) { 698 switch (_IOC_NR(cmd)) {
616 case _IOC_NR(SNDRV_COMPRESS_IOCTL_VERSION): 699 case _IOC_NR(SNDRV_COMPRESS_IOCTL_VERSION):
617 put_user(SNDRV_COMPRESS_VERSION, 700 put_user(SNDRV_COMPRESS_VERSION,
618 (int __user *)arg) ? -EFAULT : 0; 701 (int __user *)arg) ? -EFAULT : 0;
619 break; 702 break;
620 case _IOC_NR(SNDRV_COMPRESS_GET_CAPS): 703 case _IOC_NR(SNDRV_COMPRESS_GET_CAPS):
621 retval = snd_compr_get_caps(stream, arg); 704 retval = snd_compr_get_caps(stream, arg);
622 break; 705 break;
623 case _IOC_NR(SNDRV_COMPRESS_GET_CODEC_CAPS): 706 case _IOC_NR(SNDRV_COMPRESS_GET_CODEC_CAPS):
624 retval = snd_compr_get_codec_caps(stream, arg); 707 retval = snd_compr_get_codec_caps(stream, arg);
625 break; 708 break;
626 case _IOC_NR(SNDRV_COMPRESS_SET_PARAMS): 709 case _IOC_NR(SNDRV_COMPRESS_SET_PARAMS):
627 retval = snd_compr_set_params(stream, arg); 710 retval = snd_compr_set_params(stream, arg);
628 break; 711 break;
629 case _IOC_NR(SNDRV_COMPRESS_GET_PARAMS): 712 case _IOC_NR(SNDRV_COMPRESS_GET_PARAMS):
630 retval = snd_compr_get_params(stream, arg); 713 retval = snd_compr_get_params(stream, arg);
631 break; 714 break;
715 case _IOC_NR(SNDRV_COMPRESS_SET_METADATA):
716 retval = snd_compr_set_metadata(stream, arg);
717 break;
718 case _IOC_NR(SNDRV_COMPRESS_GET_METADATA):
719 retval = snd_compr_get_metadata(stream, arg);
720 break;
632 case _IOC_NR(SNDRV_COMPRESS_TSTAMP): 721 case _IOC_NR(SNDRV_COMPRESS_TSTAMP):
633 retval = snd_compr_tstamp(stream, arg); 722 retval = snd_compr_tstamp(stream, arg);
634 break; 723 break;
635 case _IOC_NR(SNDRV_COMPRESS_AVAIL): 724 case _IOC_NR(SNDRV_COMPRESS_AVAIL):
636 retval = snd_compr_ioctl_avail(stream, arg); 725 retval = snd_compr_ioctl_avail(stream, arg);
637 break; 726 break;
638 case _IOC_NR(SNDRV_COMPRESS_PAUSE): 727 case _IOC_NR(SNDRV_COMPRESS_PAUSE):
639 retval = snd_compr_pause(stream); 728 retval = snd_compr_pause(stream);
640 break; 729 break;
641 case _IOC_NR(SNDRV_COMPRESS_RESUME): 730 case _IOC_NR(SNDRV_COMPRESS_RESUME):
642 retval = snd_compr_resume(stream); 731 retval = snd_compr_resume(stream);
643 break; 732 break;
644 case _IOC_NR(SNDRV_COMPRESS_START): 733 case _IOC_NR(SNDRV_COMPRESS_START):
645 retval = snd_compr_start(stream); 734 retval = snd_compr_start(stream);
646 break; 735 break;
647 case _IOC_NR(SNDRV_COMPRESS_STOP): 736 case _IOC_NR(SNDRV_COMPRESS_STOP):
648 retval = snd_compr_stop(stream); 737 retval = snd_compr_stop(stream);
649 break; 738 break;
650 case _IOC_NR(SNDRV_COMPRESS_DRAIN): 739 case _IOC_NR(SNDRV_COMPRESS_DRAIN):
651 retval = snd_compr_drain(stream); 740 retval = snd_compr_drain(stream);
652 break; 741 break;
742 case _IOC_NR(SNDRV_COMPRESS_PARTIAL_DRAIN):
743 retval = snd_compr_partial_drain(stream);
744 break;
745 case _IOC_NR(SNDRV_COMPRESS_NEXT_TRACK):
746 retval = snd_compr_next_track(stream);
747 break;
748
653 } 749 }
654 mutex_unlock(&stream->device->lock); 750 mutex_unlock(&stream->device->lock);
655 return retval; 751 return retval;
656 } 752 }
657 753
658 static const struct file_operations snd_compr_file_ops = { 754 static const struct file_operations snd_compr_file_ops = {
659 .owner = THIS_MODULE, 755 .owner = THIS_MODULE,
660 .open = snd_compr_open, 756 .open = snd_compr_open,
661 .release = snd_compr_free, 757 .release = snd_compr_free,
662 .write = snd_compr_write, 758 .write = snd_compr_write,
663 .read = snd_compr_read, 759 .read = snd_compr_read,
664 .unlocked_ioctl = snd_compr_ioctl, 760 .unlocked_ioctl = snd_compr_ioctl,
665 .mmap = snd_compr_mmap, 761 .mmap = snd_compr_mmap,
666 .poll = snd_compr_poll, 762 .poll = snd_compr_poll,
667 }; 763 };
668 764
669 static int snd_compress_dev_register(struct snd_device *device) 765 static int snd_compress_dev_register(struct snd_device *device)
670 { 766 {
671 int ret = -EINVAL; 767 int ret = -EINVAL;
672 char str[16]; 768 char str[16];
673 struct snd_compr *compr; 769 struct snd_compr *compr;
674 770
675 if (snd_BUG_ON(!device || !device->device_data)) 771 if (snd_BUG_ON(!device || !device->device_data))
676 return -EBADFD; 772 return -EBADFD;
677 compr = device->device_data; 773 compr = device->device_data;
678 774
679 sprintf(str, "comprC%iD%i", compr->card->number, compr->device); 775 sprintf(str, "comprC%iD%i", compr->card->number, compr->device);
680 pr_debug("reg %s for device %s, direction %d\n", str, compr->name, 776 pr_debug("reg %s for device %s, direction %d\n", str, compr->name,
681 compr->direction); 777 compr->direction);
682 /* register compressed device */ 778 /* register compressed device */
683 ret = snd_register_device(SNDRV_DEVICE_TYPE_COMPRESS, compr->card, 779 ret = snd_register_device(SNDRV_DEVICE_TYPE_COMPRESS, compr->card,
684 compr->device, &snd_compr_file_ops, compr, str); 780 compr->device, &snd_compr_file_ops, compr, str);
685 if (ret < 0) { 781 if (ret < 0) {
686 pr_err("snd_register_device failed\n %d", ret); 782 pr_err("snd_register_device failed\n %d", ret);
687 return ret; 783 return ret;
688 } 784 }
689 return ret; 785 return ret;
690 786
691 } 787 }
692 788
693 static int snd_compress_dev_disconnect(struct snd_device *device) 789 static int snd_compress_dev_disconnect(struct snd_device *device)
694 { 790 {
695 struct snd_compr *compr; 791 struct snd_compr *compr;
696 792
697 compr = device->device_data; 793 compr = device->device_data;
698 snd_unregister_device(compr->direction, compr->card, compr->device); 794 snd_unregister_device(compr->direction, compr->card, compr->device);
699 return 0; 795 return 0;
700 } 796 }
701 797
702 /* 798 /*
703 * snd_compress_new: create new compress device 799 * snd_compress_new: create new compress device
704 * @card: sound card pointer 800 * @card: sound card pointer
705 * @device: device number 801 * @device: device number
706 * @dirn: device direction, should be of type enum snd_compr_direction 802 * @dirn: device direction, should be of type enum snd_compr_direction
707 * @compr: compress device pointer 803 * @compr: compress device pointer
708 */ 804 */
709 int snd_compress_new(struct snd_card *card, int device, 805 int snd_compress_new(struct snd_card *card, int device,
710 int dirn, struct snd_compr *compr) 806 int dirn, struct snd_compr *compr)
711 { 807 {
712 static struct snd_device_ops ops = { 808 static struct snd_device_ops ops = {
713 .dev_free = NULL, 809 .dev_free = NULL,
714 .dev_register = snd_compress_dev_register, 810 .dev_register = snd_compress_dev_register,
715 .dev_disconnect = snd_compress_dev_disconnect, 811 .dev_disconnect = snd_compress_dev_disconnect,
716 }; 812 };
717 813
718 compr->card = card; 814 compr->card = card;
719 compr->device = device; 815 compr->device = device;
720 compr->direction = dirn; 816 compr->direction = dirn;
721 return snd_device_new(card, SNDRV_DEV_COMPRESS, compr, &ops); 817 return snd_device_new(card, SNDRV_DEV_COMPRESS, compr, &ops);
722 } 818 }
723 EXPORT_SYMBOL_GPL(snd_compress_new); 819 EXPORT_SYMBOL_GPL(snd_compress_new);
724 820
725 static int snd_compress_add_device(struct snd_compr *device) 821 static int snd_compress_add_device(struct snd_compr *device)
726 { 822 {
727 int ret; 823 int ret;
728 824
729 if (!device->card) 825 if (!device->card)
730 return -EINVAL; 826 return -EINVAL;
731 827
732 /* register the card */ 828 /* register the card */
733 ret = snd_card_register(device->card); 829 ret = snd_card_register(device->card);
734 if (ret) 830 if (ret)
735 goto out; 831 goto out;
736 return 0; 832 return 0;
737 833
738 out: 834 out:
739 pr_err("failed with %d\n", ret); 835 pr_err("failed with %d\n", ret);
740 return ret; 836 return ret;
741 837
742 } 838 }
743 839
744 static int snd_compress_remove_device(struct snd_compr *device) 840 static int snd_compress_remove_device(struct snd_compr *device)
745 { 841 {
746 return snd_card_free(device->card); 842 return snd_card_free(device->card);
747 } 843 }
748 844
749 /** 845 /**
750 * snd_compress_register - register compressed device 846 * snd_compress_register - register compressed device
751 * 847 *
752 * @device: compressed device to register 848 * @device: compressed device to register
753 */ 849 */
754 int snd_compress_register(struct snd_compr *device) 850 int snd_compress_register(struct snd_compr *device)
755 { 851 {
756 int retval; 852 int retval;
757 853
758 if (device->name == NULL || device->dev == NULL || device->ops == NULL) 854 if (device->name == NULL || device->dev == NULL || device->ops == NULL)
759 return -EINVAL; 855 return -EINVAL;
760 856
761 pr_debug("Registering compressed device %s\n", device->name); 857 pr_debug("Registering compressed device %s\n", device->name);
762 if (snd_BUG_ON(!device->ops->open)) 858 if (snd_BUG_ON(!device->ops->open))
763 return -EINVAL; 859 return -EINVAL;
764 if (snd_BUG_ON(!device->ops->free)) 860 if (snd_BUG_ON(!device->ops->free))
765 return -EINVAL; 861 return -EINVAL;
766 if (snd_BUG_ON(!device->ops->set_params)) 862 if (snd_BUG_ON(!device->ops->set_params))
767 return -EINVAL; 863 return -EINVAL;
768 if (snd_BUG_ON(!device->ops->trigger)) 864 if (snd_BUG_ON(!device->ops->trigger))
769 return -EINVAL; 865 return -EINVAL;
770 866
771 mutex_init(&device->lock); 867 mutex_init(&device->lock);
772 868
773 /* register a compressed card */ 869 /* register a compressed card */
774 mutex_lock(&device_mutex); 870 mutex_lock(&device_mutex);
775 retval = snd_compress_add_device(device); 871 retval = snd_compress_add_device(device);
776 mutex_unlock(&device_mutex); 872 mutex_unlock(&device_mutex);
777 return retval; 873 return retval;
778 } 874 }
779 EXPORT_SYMBOL_GPL(snd_compress_register); 875 EXPORT_SYMBOL_GPL(snd_compress_register);
780 876
781 int snd_compress_deregister(struct snd_compr *device) 877 int snd_compress_deregister(struct snd_compr *device)
782 { 878 {
783 pr_debug("Removing compressed device %s\n", device->name); 879 pr_debug("Removing compressed device %s\n", device->name);
784 mutex_lock(&device_mutex); 880 mutex_lock(&device_mutex);
785 snd_compress_remove_device(device); 881 snd_compress_remove_device(device);
786 mutex_unlock(&device_mutex); 882 mutex_unlock(&device_mutex);
787 return 0; 883 return 0;
788 } 884 }
789 EXPORT_SYMBOL_GPL(snd_compress_deregister); 885 EXPORT_SYMBOL_GPL(snd_compress_deregister);
790 886
791 static int __init snd_compress_init(void) 887 static int __init snd_compress_init(void)
792 { 888 {
793 return 0; 889 return 0;
794 } 890 }
795 891
796 static void __exit snd_compress_exit(void) 892 static void __exit snd_compress_exit(void)
797 { 893 {
798 } 894 }
799 895
800 module_init(snd_compress_init); 896 module_init(snd_compress_init);
801 module_exit(snd_compress_exit); 897 module_exit(snd_compress_exit);
802 898
803 MODULE_DESCRIPTION("ALSA Compressed offload framework"); 899 MODULE_DESCRIPTION("ALSA Compressed offload framework");
804 MODULE_AUTHOR("Vinod Koul <vinod.koul@linux.intel.com>"); 900 MODULE_AUTHOR("Vinod Koul <vinod.koul@linux.intel.com>");
805 MODULE_LICENSE("GPL v2"); 901 MODULE_LICENSE("GPL v2");
806 902