source: mainline/uspace/drv/audio/hdaudio/stream.c@ a94cbfa

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a94cbfa was 0e4c5f0, checked in by Jiri Svoboda <jiri@…>, 10 years ago

hdaudio capture support. wavplay fixes to recording code.

  • Property mode set to 100644
File size: 7.2 KB
Line 
1/*
2 * Copyright (c) 2014 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup hdaudio
30 * @{
31 */
32/** @file High Definition Audio stream
33 */
34
35#include <as.h>
36#include <bitops.h>
37#include <byteorder.h>
38#include <ddf/log.h>
39#include <ddi.h>
40#include <errno.h>
41#include <macros.h>
42#include <stdlib.h>
43
44#include "hdactl.h"
45#include "hdaudio.h"
46#include "regif.h"
47#include "spec/bdl.h"
48#include "stream.h"
49
50int hda_stream_buffers_alloc(hda_t *hda, hda_stream_buffers_t **rbufs)
51{
52 void *bdl;
53 void *buffer;
54 uintptr_t buffer_phys;
55 hda_stream_buffers_t *bufs = NULL;
56 size_t i;
57// size_t j, k;
58 int rc;
59
60 bufs = calloc(1, sizeof(hda_stream_buffers_t));
61 if (bufs == NULL) {
62 rc = ENOMEM;
63 goto error;
64 }
65
66 bufs->nbuffers = 4;
67 bufs->bufsize = 16384;
68
69 /*
70 * BDL must be aligned to 128 bytes. If 64OK is not set,
71 * it must be within the 32-bit address space.
72 */
73 bdl = AS_AREA_ANY;
74 rc = dmamem_map_anonymous(bufs->nbuffers * sizeof(hda_buffer_desc_t),
75 hda->ctl->ok64bit ? 0 : DMAMEM_4GiB, AS_AREA_READ | AS_AREA_WRITE,
76 0, &bufs->bdl_phys, &bdl);
77 if (rc != EOK)
78 goto error;
79
80 bufs->bdl = bdl;
81
82 /* Allocate arrays of buffer pointers */
83
84 bufs->buf = calloc(bufs->nbuffers, sizeof(void *));
85 if (bufs->buf == NULL)
86 goto error;
87
88 bufs->buf_phys = calloc(bufs->nbuffers, sizeof(uintptr_t));
89 if (bufs->buf_phys == NULL)
90 goto error;
91
92 /* Allocate buffers */
93/*
94 for (i = 0; i < bufs->nbuffers; i++) {
95 buffer = AS_AREA_ANY;
96 rc = dmamem_map_anonymous(bufs->bufsize,
97 bufs->hda->ctl->ok64bit ? 0 : DMAMEM_4GiB, AS_AREA_READ | AS_AREA_WRITE,
98 0, &buffer_phys, &buffer);
99 if (rc != EOK)
100 goto error;
101
102 ddf_msg(LVL_NOTE, "Stream buf phys=0x%llx virt=%p",
103 (unsigned long long)buffer_phys, buffer);
104
105 bufs->buf[i] = buffer;
106 bufs->buf_phys[i] = buffer_phys;
107
108 k = 0;
109 for (j = 0; j < bufs->bufsize / 2; j++) {
110 int16_t *bp = bufs->buf[i];
111 bp[j] = (k > 128) ? -100 : 100;
112 ++k;
113 if (k >= 256)
114 k = 0;
115 }
116 }
117*/
118 /* audio_pcm_iface requires a single contiguous buffer */
119 buffer = AS_AREA_ANY;
120 rc = dmamem_map_anonymous(bufs->bufsize * bufs->nbuffers,
121 hda->ctl->ok64bit ? 0 : DMAMEM_4GiB, AS_AREA_READ | AS_AREA_WRITE,
122 0, &buffer_phys, &buffer);
123 if (rc != EOK) {
124 ddf_msg(LVL_NOTE, "dmamem_map_anon -> %d", rc);
125 goto error;
126 }
127
128 for (i = 0; i < bufs->nbuffers; i++) {
129 bufs->buf[i] = buffer + i * bufs->bufsize;
130 bufs->buf_phys[i] = buffer_phys + i * bufs->bufsize;
131
132 ddf_msg(LVL_NOTE, "Stream buf phys=0x%llx virt=%p",
133 (long long unsigned)(uintptr_t)bufs->buf[i],
134 (void *)bufs->buf_phys[i]);
135/* k = 0;
136 for (j = 0; j < bufs->bufsize / 2; j++) {
137 int16_t *bp = bufs->buf[i];
138 bp[j] = (k > 128) ? -10000 : 10000;
139 ++k;
140 if (k >= 256)
141 k = 0;
142 }
143*/
144 }
145
146 /* Fill in BDL */
147 for (i = 0; i < bufs->nbuffers; i++) {
148 bufs->bdl[i].address = host2uint64_t_le(bufs->buf_phys[i]);
149 bufs->bdl[i].length = host2uint32_t_le(bufs->bufsize);
150 bufs->bdl[i].flags = BIT_V(uint32_t, bdf_ioc);
151 }
152
153 *rbufs = bufs;
154 return EOK;
155error:
156 hda_stream_buffers_free(bufs);
157 return ENOMEM;
158}
159
160void hda_stream_buffers_free(hda_stream_buffers_t *bufs)
161{
162 if (bufs == NULL)
163 return;
164
165 /* XXX */
166 free(bufs);
167}
168
169static void hda_stream_desc_configure(hda_stream_t *stream)
170{
171 hda_sdesc_regs_t *sdregs;
172 hda_stream_buffers_t *bufs = stream->buffers;
173 uint8_t ctl1;
174 uint8_t ctl3;
175
176 ctl3 = (stream->sid << 4);
177 ctl1 = 0x4;
178
179 sdregs = &stream->hda->regs->sdesc[stream->sdid];
180 hda_reg8_write(&sdregs->ctl3, ctl3);
181 hda_reg8_write(&sdregs->ctl1, ctl1);
182 hda_reg32_write(&sdregs->cbl, bufs->nbuffers * bufs->bufsize);
183 hda_reg16_write(&sdregs->lvi, bufs->nbuffers - 1);
184 hda_reg16_write(&sdregs->fmt, stream->fmt);
185 hda_reg32_write(&sdregs->bdpl, LOWER32(bufs->bdl_phys));
186 hda_reg32_write(&sdregs->bdpu, UPPER32(bufs->bdl_phys));
187}
188
189static void hda_stream_set_run(hda_stream_t *stream, bool run)
190{
191 uint32_t ctl;
192 hda_sdesc_regs_t *sdregs;
193
194 sdregs = &stream->hda->regs->sdesc[stream->sdid];
195
196 ctl = hda_reg8_read(&sdregs->ctl1);
197 if (run)
198 ctl = ctl | BIT_V(uint8_t, sdctl1_run);
199 else
200 ctl = ctl & ~BIT_V(uint8_t, sdctl1_run);
201
202 hda_reg8_write(&sdregs->ctl1, ctl);
203}
204
205static void hda_stream_reset_noinit(hda_stream_t *stream)
206{
207 uint32_t ctl;
208 hda_sdesc_regs_t *sdregs;
209
210 sdregs = &stream->hda->regs->sdesc[stream->sdid];
211
212 ctl = hda_reg8_read(&sdregs->ctl1);
213 ctl = ctl | BIT_V(uint8_t, sdctl1_srst);
214 hda_reg8_write(&sdregs->ctl1, ctl);
215
216 async_usleep(100 * 1000);
217
218 ctl = hda_reg8_read(&sdregs->ctl1);
219 ctl = ctl & ~BIT_V(uint8_t, sdctl1_srst);
220 hda_reg8_write(&sdregs->ctl1, ctl);
221
222 async_usleep(100 * 1000);
223}
224
225hda_stream_t *hda_stream_create(hda_t *hda, hda_stream_dir_t dir,
226 hda_stream_buffers_t *bufs, uint32_t fmt)
227{
228 hda_stream_t *stream;
229 uint8_t sdid;
230
231 stream = calloc(1, sizeof(hda_stream_t));
232 if (stream == NULL)
233 return NULL;
234
235 sdid = 0;
236
237 switch (dir) {
238 case sdir_input:
239 sdid = 0; /* XXX Allocate - first input SDESC */
240 break;
241 case sdir_output:
242 sdid = hda->ctl->iss; /* XXX Allocate - First output SDESC */
243 break;
244 case sdir_bidi:
245 sdid = hda->ctl->iss + hda->ctl->oss; /* XXX Allocate - First bidi SDESC */
246 break;
247 }
248
249 stream->hda = hda;
250 stream->dir = dir;
251 stream->sid = 1; /* XXX Allocate this */
252 stream->sdid = sdid;
253 stream->fmt = fmt;
254 stream->buffers = bufs;
255
256 ddf_msg(LVL_NOTE, "snum=%d sdidx=%d", stream->sid, stream->sdid);
257
258 ddf_msg(LVL_NOTE, "Configure stream descriptor");
259 hda_stream_desc_configure(stream);
260 return stream;
261}
262
263void hda_stream_destroy(hda_stream_t *stream)
264{
265 ddf_msg(LVL_NOTE, "hda_stream_destroy()");
266 hda_stream_reset_noinit(stream);
267 free(stream);
268}
269
270void hda_stream_start(hda_stream_t *stream)
271{
272 ddf_msg(LVL_NOTE, "hda_stream_start()");
273 hda_stream_set_run(stream, true);
274}
275
276void hda_stream_stop(hda_stream_t *stream)
277{
278 ddf_msg(LVL_NOTE, "hda_stream_stop()");
279 hda_stream_set_run(stream, false);
280}
281
282void hda_stream_reset(hda_stream_t *stream)
283{
284 ddf_msg(LVL_NOTE, "hda_stream_reset()");
285 hda_stream_reset_noinit(stream);
286 hda_stream_desc_configure(stream);
287}
288
289/** @}
290 */
Note: See TracBrowser for help on using the repository browser.