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

Last change on this file was 0d59ea7e, checked in by Jiri Svoboda <jiri@…>, 3 years ago

Multiple HD Audio converters cannot pull from a single stream

We select one arbitrary output converter for out PCM output, similar to what
we do for input.

We filter the 'other' VirtualBox output converters based on rates/formats
being zero.

  • Property mode set to 100644
File size: 7.2 KB
RevLine 
[1412a184]1/*
[0d59ea7e]2 * Copyright (c) 2022 Jiri Svoboda
[1412a184]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>
[903eff5]36#include <bitops.h>
37#include <byteorder.h>
[1412a184]38#include <ddf/log.h>
39#include <ddi.h>
40#include <errno.h>
[dd8ab1c]41#include <str_error.h>
[903eff5]42#include <macros.h>
[1412a184]43#include <stdlib.h>
44
45#include "hdactl.h"
46#include "hdaudio.h"
47#include "regif.h"
48#include "spec/bdl.h"
49#include "stream.h"
50
[b7fd2a0]51errno_t hda_stream_buffers_alloc(hda_t *hda, hda_stream_buffers_t **rbufs)
[1412a184]52{
53 void *bdl;
54 void *buffer;
55 uintptr_t buffer_phys;
[0e4c5f0]56 hda_stream_buffers_t *bufs = NULL;
[1412a184]57 size_t i;
[3fafe5e0]58 //size_t j, k;
[b7fd2a0]59 errno_t rc;
[1412a184]60
[0e4c5f0]61 bufs = calloc(1, sizeof(hda_stream_buffers_t));
62 if (bufs == NULL) {
63 rc = ENOMEM;
64 goto error;
65 }
66
67 bufs->nbuffers = 4;
68 bufs->bufsize = 16384;
[1412a184]69
70 /*
71 * BDL must be aligned to 128 bytes. If 64OK is not set,
72 * it must be within the 32-bit address space.
73 */
74 bdl = AS_AREA_ANY;
[0e4c5f0]75 rc = dmamem_map_anonymous(bufs->nbuffers * sizeof(hda_buffer_desc_t),
76 hda->ctl->ok64bit ? 0 : DMAMEM_4GiB, AS_AREA_READ | AS_AREA_WRITE,
77 0, &bufs->bdl_phys, &bdl);
[1412a184]78 if (rc != EOK)
79 goto error;
80
[0e4c5f0]81 bufs->bdl = bdl;
[1412a184]82
83 /* Allocate arrays of buffer pointers */
84
[0e4c5f0]85 bufs->buf = calloc(bufs->nbuffers, sizeof(void *));
86 if (bufs->buf == NULL)
[1412a184]87 goto error;
88
[0e4c5f0]89 bufs->buf_phys = calloc(bufs->nbuffers, sizeof(uintptr_t));
90 if (bufs->buf_phys == NULL)
[1412a184]91 goto error;
92
93 /* Allocate buffers */
[47e00b83]94#if 0
[0e4c5f0]95 for (i = 0; i < bufs->nbuffers; i++) {
[1412a184]96 buffer = AS_AREA_ANY;
[0e4c5f0]97 rc = dmamem_map_anonymous(bufs->bufsize,
98 bufs->hda->ctl->ok64bit ? 0 : DMAMEM_4GiB, AS_AREA_READ | AS_AREA_WRITE,
[1412a184]99 0, &buffer_phys, &buffer);
100 if (rc != EOK)
101 goto error;
102
[cf78637]103 ddf_msg(LVL_DEBUG, "Stream buf phys=0x%llx virt=%p",
[903eff5]104 (unsigned long long)buffer_phys, buffer);
105
[0e4c5f0]106 bufs->buf[i] = buffer;
107 bufs->buf_phys[i] = buffer_phys;
[1412a184]108
109 k = 0;
[0e4c5f0]110 for (j = 0; j < bufs->bufsize / 2; j++) {
111 int16_t *bp = bufs->buf[i];
[99cb9bf]112 bp[j] = (k > 128) ? -100 : 100;
[1412a184]113 ++k;
114 if (k >= 256)
115 k = 0;
116 }
117 }
[47e00b83]118#endif
[159c722d]119 /* audio_pcm_iface requires a single contiguous buffer */
120 buffer = AS_AREA_ANY;
[0e4c5f0]121 rc = dmamem_map_anonymous(bufs->bufsize * bufs->nbuffers,
122 hda->ctl->ok64bit ? 0 : DMAMEM_4GiB, AS_AREA_READ | AS_AREA_WRITE,
[159c722d]123 0, &buffer_phys, &buffer);
124 if (rc != EOK) {
[cf78637]125 ddf_msg(LVL_DEBUG, "dmamem_map_anon -> %s", str_error_name(rc));
[159c722d]126 goto error;
127 }
128
[0e4c5f0]129 for (i = 0; i < bufs->nbuffers; i++) {
130 bufs->buf[i] = buffer + i * bufs->bufsize;
131 bufs->buf_phys[i] = buffer_phys + i * bufs->bufsize;
[159c722d]132
[cf78637]133 ddf_msg(LVL_DEBUG, "Stream buf phys=0x%llx virt=%p",
[0e4c5f0]134 (long long unsigned)(uintptr_t)bufs->buf[i],
135 (void *)bufs->buf_phys[i]);
[159c722d]136 }
[1412a184]137
138 /* Fill in BDL */
[0e4c5f0]139 for (i = 0; i < bufs->nbuffers; i++) {
140 bufs->bdl[i].address = host2uint64_t_le(bufs->buf_phys[i]);
141 bufs->bdl[i].length = host2uint32_t_le(bufs->bufsize);
142 bufs->bdl[i].flags = BIT_V(uint32_t, bdf_ioc);
[1412a184]143 }
144
[0e4c5f0]145 *rbufs = bufs;
[1412a184]146 return EOK;
147error:
[0e4c5f0]148 hda_stream_buffers_free(bufs);
[1412a184]149 return ENOMEM;
150}
151
[0e4c5f0]152void hda_stream_buffers_free(hda_stream_buffers_t *bufs)
153{
154 if (bufs == NULL)
155 return;
156
157 /* XXX */
158 free(bufs);
159}
160
[1412a184]161static void hda_stream_desc_configure(hda_stream_t *stream)
162{
163 hda_sdesc_regs_t *sdregs;
[0e4c5f0]164 hda_stream_buffers_t *bufs = stream->buffers;
[903eff5]165 uint8_t ctl1;
166 uint8_t ctl3;
167
[0d59ea7e]168 /* Stream ID */
[903eff5]169 ctl3 = (stream->sid << 4);
[0d59ea7e]170
171 /* Interrupt on buffer completion */
172 ctl1 = BIT_V(uint8_t, sdctl1_ioce);
[1412a184]173
174 sdregs = &stream->hda->regs->sdesc[stream->sdid];
[903eff5]175 hda_reg8_write(&sdregs->ctl3, ctl3);
176 hda_reg8_write(&sdregs->ctl1, ctl1);
[0e4c5f0]177 hda_reg32_write(&sdregs->cbl, bufs->nbuffers * bufs->bufsize);
178 hda_reg16_write(&sdregs->lvi, bufs->nbuffers - 1);
[1412a184]179 hda_reg16_write(&sdregs->fmt, stream->fmt);
[0e4c5f0]180 hda_reg32_write(&sdregs->bdpl, LOWER32(bufs->bdl_phys));
181 hda_reg32_write(&sdregs->bdpu, UPPER32(bufs->bdl_phys));
[1412a184]182}
183
184static void hda_stream_set_run(hda_stream_t *stream, bool run)
185{
186 uint32_t ctl;
187 hda_sdesc_regs_t *sdregs;
188
189 sdregs = &stream->hda->regs->sdesc[stream->sdid];
190
191 ctl = hda_reg8_read(&sdregs->ctl1);
[6747b929]192 if (run)
193 ctl = ctl | BIT_V(uint8_t, sdctl1_run);
194 else
195 ctl = ctl & ~BIT_V(uint8_t, sdctl1_run);
196
[1412a184]197 hda_reg8_write(&sdregs->ctl1, ctl);
198}
199
[6747b929]200static void hda_stream_reset_noinit(hda_stream_t *stream)
201{
202 uint32_t ctl;
203 hda_sdesc_regs_t *sdregs;
204
205 sdregs = &stream->hda->regs->sdesc[stream->sdid];
206
207 ctl = hda_reg8_read(&sdregs->ctl1);
208 ctl = ctl | BIT_V(uint8_t, sdctl1_srst);
209 hda_reg8_write(&sdregs->ctl1, ctl);
210
[5f97ef44]211 fibril_usleep(100 * 1000);
[6747b929]212
[fff4f21]213 ctl = hda_reg8_read(&sdregs->ctl1);
214 ctl = ctl & ~BIT_V(uint8_t, sdctl1_srst);
215 hda_reg8_write(&sdregs->ctl1, ctl);
[6747b929]216
[5f97ef44]217 fibril_usleep(100 * 1000);
[6747b929]218}
219
[1412a184]220hda_stream_t *hda_stream_create(hda_t *hda, hda_stream_dir_t dir,
[0e4c5f0]221 hda_stream_buffers_t *bufs, uint32_t fmt)
[1412a184]222{
223 hda_stream_t *stream;
[0e4c5f0]224 uint8_t sdid;
[1412a184]225
226 stream = calloc(1, sizeof(hda_stream_t));
227 if (stream == NULL)
228 return NULL;
229
[0e4c5f0]230 sdid = 0;
231
232 switch (dir) {
233 case sdir_input:
234 sdid = 0; /* XXX Allocate - first input SDESC */
235 break;
236 case sdir_output:
237 sdid = hda->ctl->iss; /* XXX Allocate - First output SDESC */
238 break;
239 case sdir_bidi:
240 sdid = hda->ctl->iss + hda->ctl->oss; /* XXX Allocate - First bidi SDESC */
241 break;
242 }
243
[1412a184]244 stream->hda = hda;
245 stream->dir = dir;
246 stream->sid = 1; /* XXX Allocate this */
[0e4c5f0]247 stream->sdid = sdid;
[1412a184]248 stream->fmt = fmt;
[0e4c5f0]249 stream->buffers = bufs;
[1412a184]250
[cf78637]251 ddf_msg(LVL_DEBUG, "snum=%d sdidx=%d", stream->sid, stream->sdid);
[1412a184]252
[cf78637]253 ddf_msg(LVL_DEBUG, "Configure stream descriptor");
[1412a184]254 hda_stream_desc_configure(stream);
255 return stream;
256}
257
258void hda_stream_destroy(hda_stream_t *stream)
259{
[cf78637]260 ddf_msg(LVL_DEBUG, "hda_stream_destroy()");
[6747b929]261 hda_stream_reset_noinit(stream);
[1412a184]262 free(stream);
263}
264
265void hda_stream_start(hda_stream_t *stream)
266{
[cf78637]267 ddf_msg(LVL_DEBUG, "hda_stream_start()");
[1412a184]268 hda_stream_set_run(stream, true);
269}
270
[6747b929]271void hda_stream_stop(hda_stream_t *stream)
272{
[cf78637]273 ddf_msg(LVL_DEBUG, "hda_stream_stop()");
[6747b929]274 hda_stream_set_run(stream, false);
275}
276
277void hda_stream_reset(hda_stream_t *stream)
278{
[cf78637]279 ddf_msg(LVL_DEBUG, "hda_stream_reset()");
[6747b929]280 hda_stream_reset_noinit(stream);
281 hda_stream_desc_configure(stream);
282}
283
[1412a184]284/** @}
285 */
Note: See TracBrowser for help on using the repository browser.