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

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

And there was sound.

  • Property mode set to 100644
File size: 6.8 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
50static int hda_stream_buffers_alloc(hda_stream_t *stream)
51{
52 void *bdl;
53 void *buffer;
54 uintptr_t buffer_phys;
55 size_t i;
56// size_t j, k;
57 int rc;
58
59 stream->nbuffers = 4;
60 stream->bufsize = 16384;
61
62 /*
63 * BDL must be aligned to 128 bytes. If 64OK is not set,
64 * it must be within the 32-bit address space.
65 */
66 bdl = AS_AREA_ANY;
67 rc = dmamem_map_anonymous(stream->nbuffers * sizeof(hda_buffer_desc_t),
68 stream->hda->ctl->ok64bit ? 0 : DMAMEM_4GiB, AS_AREA_READ | AS_AREA_WRITE,
69 0, &stream->bdl_phys, &bdl);
70 if (rc != EOK)
71 goto error;
72
73 stream->bdl = bdl;
74
75 /* Allocate arrays of buffer pointers */
76
77 stream->buf = calloc(stream->nbuffers, sizeof(void *));
78 if (stream->buf == NULL)
79 goto error;
80
81 stream->buf_phys = calloc(stream->nbuffers, sizeof(uintptr_t));
82 if (stream->buf_phys == NULL)
83 goto error;
84
85 /* Allocate buffers */
86/*
87 for (i = 0; i < stream->nbuffers; i++) {
88 buffer = AS_AREA_ANY;
89 rc = dmamem_map_anonymous(stream->bufsize,
90 stream->hda->ctl->ok64bit ? 0 : DMAMEM_4GiB, AS_AREA_READ | AS_AREA_WRITE,
91 0, &buffer_phys, &buffer);
92 if (rc != EOK)
93 goto error;
94
95 ddf_msg(LVL_NOTE, "Stream buf phys=0x%llx virt=%p",
96 (unsigned long long)buffer_phys, buffer);
97
98 stream->buf[i] = buffer;
99 stream->buf_phys[i] = buffer_phys;
100
101 k = 0;
102 for (j = 0; j < stream->bufsize / 2; j++) {
103 int16_t *bp = stream->buf[i];
104 bp[j] = (k > 128) ? -100 : 100;
105 ++k;
106 if (k >= 256)
107 k = 0;
108 }
109 }
110*/
111// async_usleep(1000*1000);
112 /* audio_pcm_iface requires a single contiguous buffer */
113 buffer = AS_AREA_ANY;
114 rc = dmamem_map_anonymous(stream->bufsize * stream->nbuffers,
115 stream->hda->ctl->ok64bit ? 0 : DMAMEM_4GiB, AS_AREA_READ | AS_AREA_WRITE,
116 0, &buffer_phys, &buffer);
117 if (rc != EOK) {
118 ddf_msg(LVL_NOTE, "dmamem_map_anon -> %d", rc);
119 goto error;
120 }
121
122 for (i = 0; i < stream->nbuffers; i++) {
123 stream->buf[i] = buffer + i * stream->bufsize;
124 stream->buf_phys[i] = buffer_phys + i * stream->bufsize;
125
126 ddf_msg(LVL_NOTE, "Stream buf phys=0x%llx virt=%p",
127 (long long unsigned)(uintptr_t)stream->buf[i],
128 (void *)stream->buf_phys[i]);
129/* k = 0;
130 for (j = 0; j < stream->bufsize / 2; j++) {
131 int16_t *bp = stream->buf[i];
132 bp[j] = (k > 128) ? -10000 : 10000;
133 ++k;
134 if (k >= 256)
135 k = 0;
136 }
137*/
138 }
139
140 /* Fill in BDL */
141 for (i = 0; i < stream->nbuffers; i++) {
142 stream->bdl[i].address = host2uint64_t_le(stream->buf_phys[i]);
143 stream->bdl[i].length = host2uint32_t_le(stream->bufsize);
144 stream->bdl[i].flags = BIT_V(uint32_t, bdf_ioc);
145 }
146
147 return EOK;
148error:
149 return ENOMEM;
150}
151
152static void hda_stream_desc_configure(hda_stream_t *stream)
153{
154 hda_sdesc_regs_t *sdregs;
155 uint8_t ctl1;
156 uint8_t ctl3;
157
158 ctl3 = (stream->sid << 4);
159 ctl1 = 0x4;
160
161 sdregs = &stream->hda->regs->sdesc[stream->sdid];
162 hda_reg8_write(&sdregs->ctl3, ctl3);
163 hda_reg8_write(&sdregs->ctl1, ctl1);
164 hda_reg32_write(&sdregs->cbl, stream->nbuffers * stream->bufsize);
165 hda_reg16_write(&sdregs->lvi, stream->nbuffers - 1);
166 hda_reg16_write(&sdregs->fmt, stream->fmt);
167 hda_reg32_write(&sdregs->bdpl, LOWER32(stream->bdl_phys));
168 hda_reg32_write(&sdregs->bdpu, UPPER32(stream->bdl_phys));
169}
170
171static void hda_stream_set_run(hda_stream_t *stream, bool run)
172{
173 uint32_t ctl;
174 hda_sdesc_regs_t *sdregs;
175
176 sdregs = &stream->hda->regs->sdesc[stream->sdid];
177
178 ctl = hda_reg8_read(&sdregs->ctl1);
179 if (run)
180 ctl = ctl | BIT_V(uint8_t, sdctl1_run);
181 else
182 ctl = ctl & ~BIT_V(uint8_t, sdctl1_run);
183
184 hda_reg8_write(&sdregs->ctl1, ctl);
185}
186
187static void hda_stream_reset_noinit(hda_stream_t *stream)
188{
189 uint32_t ctl;
190 hda_sdesc_regs_t *sdregs;
191
192 sdregs = &stream->hda->regs->sdesc[stream->sdid];
193
194 ctl = hda_reg8_read(&sdregs->ctl1);
195 ctl = ctl | BIT_V(uint8_t, sdctl1_srst);
196 hda_reg8_write(&sdregs->ctl1, ctl);
197
198 async_usleep(100 * 1000);
199
200 ctl = hda_reg8_read(&sdregs->ctl1);
201 ctl = ctl & ~BIT_V(uint8_t, sdctl1_srst);
202 hda_reg8_write(&sdregs->ctl1, ctl);
203
204 async_usleep(100 * 1000);
205}
206
207hda_stream_t *hda_stream_create(hda_t *hda, hda_stream_dir_t dir,
208 uint32_t fmt)
209{
210 hda_stream_t *stream;
211 int rc;
212
213 stream = calloc(1, sizeof(hda_stream_t));
214 if (stream == NULL)
215 return NULL;
216
217 stream->hda = hda;
218 stream->dir = dir;
219 stream->sid = 1; /* XXX Allocate this */
220 stream->sdid = hda->ctl->iss; /* XXX Allocate - First output SDESC */
221 stream->fmt = fmt;
222
223 ddf_msg(LVL_NOTE, "snum=%d sdidx=%d", stream->sid, stream->sdid);
224
225 ddf_msg(LVL_NOTE, "Allocate buffers");
226 rc = hda_stream_buffers_alloc(stream);
227 if (rc != EOK)
228 goto error;
229
230 ddf_msg(LVL_NOTE, "Configure stream descriptor");
231 hda_stream_desc_configure(stream);
232 return stream;
233error:
234 return NULL;
235}
236
237void hda_stream_destroy(hda_stream_t *stream)
238{
239 ddf_msg(LVL_NOTE, "hda_stream_destroy()");
240 hda_stream_reset_noinit(stream);
241 free(stream);
242}
243
244void hda_stream_start(hda_stream_t *stream)
245{
246 ddf_msg(LVL_NOTE, "hda_stream_start()");
247 hda_stream_set_run(stream, true);
248}
249
250void hda_stream_stop(hda_stream_t *stream)
251{
252 ddf_msg(LVL_NOTE, "hda_stream_stop()");
253 hda_stream_set_run(stream, false);
254}
255
256void hda_stream_reset(hda_stream_t *stream)
257{
258 ddf_msg(LVL_NOTE, "hda_stream_reset()");
259 hda_stream_reset_noinit(stream);
260 hda_stream_desc_configure(stream);
261}
262
263/** @}
264 */
Note: See TracBrowser for help on using the repository browser.