source: mainline/uspace/drv/audio/hdaudio/hdactl.c@ 17d34a8

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 17d34a8 was 5a6cc679, checked in by Jenda <jenda.jzqk73@…>, 8 years ago

Merge commit '50f19b7ee8e94570b5c63896736c4eb49cfa18db' into forwardport

Not all ints are converted to errno_t in xhci tree yet, however it compiles and works :)

  • Property mode set to 100644
File size: 17.5 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 controller
33 */
34
35#include <as.h>
36#include <async.h>
37#include <bitops.h>
38#include <ddf/log.h>
39#include <ddi.h>
40#include <errno.h>
41#include <fibril_synch.h>
42#include <macros.h>
43#include <stdint.h>
44
45#include "codec.h"
46#include "hdactl.h"
47#include "regif.h"
48#include "spec/regs.h"
49
50enum {
51 ctrl_init_wait_max = 10,
52 codec_enum_wait_us = 512,
53 corb_wait_max = 10,
54 rirb_wait_max = 100,
55 solrb_wait_us = 100 * 1000
56};
57
58static void hda_ctl_process_rirb(hda_ctl_t *);
59
60/** Perform set-reset handshake on a 16-bit register.
61 *
62 * The bit(s) specified in the mask are written as 1, then we wait
63 * for them to read as 1. Then we write them as 0 and we wait for them
64 * to read as 0.
65 */
66static errno_t hda_ctl_reg16_set_reset(uint16_t *reg, uint16_t mask)
67{
68 uint16_t val;
69 int wcnt;
70
71 val = hda_reg16_read(reg);
72 hda_reg16_write(reg, val | mask);
73
74 wcnt = 1000;
75 while (wcnt > 0) {
76 val = hda_reg16_read(reg);
77 if ((val & mask) == mask)
78 break;
79
80 async_usleep(1000);
81 --wcnt;
82 }
83
84 if ((val & mask) != mask)
85 return ETIMEOUT;
86
87 val = hda_reg16_read(reg);
88 hda_reg16_write(reg, val & ~mask);
89
90 wcnt = 1000;
91 while (wcnt > 0) {
92 val = hda_reg16_read(reg);
93 if ((val & mask) == 0)
94 break;
95
96 async_usleep(1000);
97 --wcnt;
98 }
99
100 if ((val & mask) != 0)
101 return ETIMEOUT;
102
103 return EOK;
104}
105
106/** Select an appropriate CORB/RIRB size.
107 *
108 * We always use the largest available size. In @a sizecap each of bits
109 * 0, 1, 2 determine whether one of the supported size (0 == 2 entries,
110 * 1 == 16 entries, 2 == 256 entries) is supported. @a *selsz is set to
111 * one of 0, 1, 2 on success.
112 *
113 * @param sizecap CORB/RIRB Size Capability
114 * @param selsz Place to store CORB/RIRB Size
115 * @return EOK on success, EINVAL if sizecap has no valid bits set
116 *
117 */
118static errno_t hda_rb_size_select(uint8_t sizecap, uint8_t *selsz)
119{
120 int i;
121
122 for (i = 2; i >= 0; --i) {
123 if ((sizecap & BIT_V(uint8_t, i)) != 0) {
124 *selsz = i;
125 return EOK;
126 }
127 }
128
129 return EINVAL;
130}
131
132static size_t hda_rb_entries(uint8_t selsz)
133{
134 switch (selsz) {
135 case 0:
136 return 2;
137 case 1:
138 return 16;
139 case 2:
140 return 256;
141 default:
142 assert(false);
143 return 0;
144 }
145}
146
147/** Initialize the CORB */
148static errno_t hda_corb_init(hda_t *hda)
149{
150 uint8_t ctl;
151 uint8_t corbsz;
152 uint8_t sizecap;
153 uint8_t selsz;
154 errno_t rc;
155
156 ddf_msg(LVL_NOTE, "hda_corb_init()");
157
158 /* Stop CORB if not stopped */
159 ctl = hda_reg8_read(&hda->regs->corbctl);
160 if ((ctl & BIT_V(uint8_t, corbctl_run)) != 0) {
161 ddf_msg(LVL_NOTE, "CORB is enabled, disabling first.");
162 hda_reg8_write(&hda->regs->corbctl, ctl & ~BIT_V(uint8_t,
163 corbctl_run));
164 }
165
166 /* Determine CORB size and allocate CORB buffer */
167 corbsz = hda_reg8_read(&hda->regs->corbsize);
168 sizecap = BIT_RANGE_EXTRACT(uint8_t, corbsize_cap_h,
169 corbsize_cap_l, corbsz);
170 rc = hda_rb_size_select(sizecap, &selsz);
171 if (rc != EOK) {
172 ddf_msg(LVL_ERROR, "Invalid CORB Size Capability");
173 goto error;
174 }
175 corbsz = corbsz & ~BIT_RANGE(uint8_t, corbsize_size_h, corbsize_size_l);
176 corbsz = corbsz | selsz;
177
178 ddf_msg(LVL_NOTE, "Setting CORB Size register to 0x%x", corbsz);
179 hda_reg8_write(&hda->regs->corbsize, corbsz);
180 hda->ctl->corb_entries = hda_rb_entries(selsz);
181
182
183 /*
184 * CORB must be aligned to 128 bytes. If 64OK is not set,
185 * it must be within the 32-bit address space.
186 */
187 hda->ctl->corb_virt = AS_AREA_ANY;
188 rc = dmamem_map_anonymous(hda->ctl->corb_entries * sizeof(uint32_t),
189 hda->ctl->ok64bit ? 0 : DMAMEM_4GiB, AS_AREA_READ | AS_AREA_WRITE, 0,
190 &hda->ctl->corb_phys, &hda->ctl->corb_virt);
191
192 ddf_msg(LVL_NOTE, "Set CORB base registers");
193
194 /* Update CORB base registers */
195 hda_reg32_write(&hda->regs->corblbase, LOWER32(hda->ctl->corb_phys));
196 hda_reg32_write(&hda->regs->corbubase, UPPER32(hda->ctl->corb_phys));
197
198 ddf_msg(LVL_NOTE, "Reset CORB Read/Write pointers");
199
200 /* Reset CORB Read Pointer */
201 rc = hda_ctl_reg16_set_reset(&hda->regs->corbrp,
202 BIT_V(uint16_t, corbrp_rst));
203 if (rc != EOK) {
204 ddf_msg(LVL_NOTE, "Failed resetting CORBRP");
205 goto error;
206 }
207
208 /* Reset CORB Write Pointer */
209 hda_reg16_write(&hda->regs->corbwp, 0);
210
211 /* Start CORB */
212 ctl = hda_reg8_read(&hda->regs->corbctl);
213 ddf_msg(LVL_NOTE, "CORBctl (0x%x) = 0x%x",
214 (unsigned)((void *)&hda->regs->corbctl - (void *)hda->regs), ctl | BIT_V(uint8_t, corbctl_run));
215 hda_reg8_write(&hda->regs->corbctl, ctl | BIT_V(uint8_t, corbctl_run));
216
217 ddf_msg(LVL_NOTE, "CORB initialized");
218 return EOK;
219error:
220 if (hda->ctl->corb_virt != NULL)
221 dmamem_unmap_anonymous(&hda->ctl->corb_virt);
222 return EIO;
223}
224
225/** Tear down the CORB */
226static void hda_corb_fini(hda_t *hda)
227{
228 uint8_t ctl;
229
230 /* Stop CORB */
231 ctl = hda_reg8_read(&hda->regs->corbctl);
232 hda_reg8_write(&hda->regs->corbctl, ctl & ~BIT_V(uint8_t, corbctl_run));
233
234 if (hda->ctl->corb_virt != NULL)
235 dmamem_unmap_anonymous(&hda->ctl->corb_virt);
236}
237
238/** Initialize the RIRB */
239static errno_t hda_rirb_init(hda_t *hda)
240{
241 uint8_t ctl;
242 uint8_t rirbsz;
243 uint8_t sizecap;
244 uint8_t selsz;
245 errno_t rc;
246
247 ddf_msg(LVL_NOTE, "hda_rirb_init()");
248
249 /* Stop RIRB if not stopped */
250 ctl = hda_reg8_read(&hda->regs->rirbctl);
251 if ((ctl & BIT_V(uint8_t, rirbctl_run)) != 0) {
252 ddf_msg(LVL_NOTE, "RIRB is enabled, disabling first.");
253 hda_reg8_write(&hda->regs->corbctl, ctl & ~BIT_V(uint8_t,
254 rirbctl_run));
255 }
256
257 /* Determine RIRB size and allocate RIRB buffer */
258 rirbsz = hda_reg8_read(&hda->regs->rirbsize);
259 sizecap = BIT_RANGE_EXTRACT(uint8_t, rirbsize_cap_h,
260 rirbsize_cap_l, rirbsz);
261 rc = hda_rb_size_select(sizecap, &selsz);
262 if (rc != EOK) {
263 ddf_msg(LVL_ERROR, "Invalid RIRB Size Capability");
264 goto error;
265 }
266 rirbsz = rirbsz & ~BIT_RANGE(uint8_t, rirbsize_size_h, rirbsize_size_l);
267 rirbsz = rirbsz | (selsz << rirbsize_size_l);
268
269 ddf_msg(LVL_NOTE, "Setting RIRB Size register to 0x%x", rirbsz);
270 hda_reg8_write(&hda->regs->rirbsize, rirbsz);
271 hda->ctl->rirb_entries = hda_rb_entries(selsz);
272
273 /*
274 * RIRB must be aligned to 128 bytes. If 64OK is not set,
275 * it must be within the 32-bit address space.
276 */
277 hda->ctl->rirb_virt = AS_AREA_ANY;
278 rc = dmamem_map_anonymous(hda->ctl->rirb_entries * sizeof(uint64_t),
279 hda->ctl->ok64bit ? 0 : DMAMEM_4GiB, AS_AREA_READ | AS_AREA_WRITE, 0,
280 &hda->ctl->rirb_phys, &hda->ctl->rirb_virt);
281
282 ddf_msg(LVL_NOTE, "Set RIRB base registers");
283
284 /* Update RIRB base registers */
285 hda_reg32_write(&hda->regs->rirblbase, LOWER32(hda->ctl->rirb_phys));
286 hda_reg32_write(&hda->regs->rirbubase, UPPER32(hda->ctl->rirb_phys));
287
288 ddf_msg(LVL_NOTE, "Reset RIRB Write pointer");
289
290 /* Reset RIRB Write Pointer */
291 hda_reg16_write(&hda->regs->rirbwp, BIT_V(uint16_t, rirbwp_rst));
292
293 /* Set RINTCNT - Qemu won't read from CORB if this is zero */
294 hda_reg16_write(&hda->regs->rintcnt, hda->ctl->rirb_entries / 2);
295
296 hda->ctl->rirb_rp = 0;
297
298 /* Start RIRB and enable RIRB interrupt */
299 ctl = hda_reg8_read(&hda->regs->rirbctl);
300 ddf_msg(LVL_NOTE, "RIRBctl (0x%x) = 0x%x",
301 (unsigned)((void *)&hda->regs->rirbctl - (void *)hda->regs), ctl | BIT_V(uint8_t, rirbctl_run));
302 hda_reg8_write(&hda->regs->rirbctl, ctl | BIT_V(uint8_t, rirbctl_run) |
303 BIT_V(uint8_t, rirbctl_int));
304
305 ddf_msg(LVL_NOTE, "RIRB initialized");
306 return EOK;
307error:
308 if (hda->ctl->rirb_virt != NULL)
309 dmamem_unmap_anonymous(&hda->ctl->rirb_virt);
310 return EIO;
311}
312
313/** Tear down the RIRB */
314static void hda_rirb_fini(hda_t *hda)
315{
316 uint8_t ctl;
317
318 /* Stop RIRB and disable RIRB interrupt */
319 ctl = hda_reg8_read(&hda->regs->rirbctl);
320 hda_reg8_write(&hda->regs->rirbctl, ctl &
321 ~(BIT_V(uint8_t, rirbctl_run) | BIT_V(uint8_t, rirbctl_int)));
322
323 if (hda->ctl->rirb_virt != NULL)
324 dmamem_unmap_anonymous(&hda->ctl->rirb_virt);
325}
326
327static size_t hda_get_corbrp(hda_t *hda)
328{
329 uint16_t corbrp;
330
331 corbrp = hda_reg16_read(&hda->regs->corbrp);
332 return BIT_RANGE_EXTRACT(uint16_t, corbrp_rp_h, corbrp_rp_l, corbrp);
333}
334
335static size_t hda_get_corbwp(hda_t *hda)
336{
337 uint16_t corbwp;
338
339 corbwp = hda_reg16_read(&hda->regs->corbwp);
340 return BIT_RANGE_EXTRACT(uint16_t, corbwp_wp_h, corbwp_wp_l, corbwp);
341}
342
343static void hda_set_corbwp(hda_t *hda, size_t wp)
344{
345 ddf_msg(LVL_DEBUG2, "Set CORBWP = %zu", wp);
346 hda_reg16_write(&hda->regs->corbwp, wp);
347}
348
349static size_t hda_get_rirbwp(hda_t *hda)
350{
351 uint16_t rirbwp;
352
353 rirbwp = hda_reg16_read(&hda->regs->rirbwp);
354 return BIT_RANGE_EXTRACT(uint16_t, rirbwp_wp_h, rirbwp_wp_l, rirbwp);
355}
356
357/** Determine number of free entries in CORB */
358static size_t hda_corb_avail(hda_t *hda)
359{
360 int rp, wp;
361 int avail;
362
363 rp = hda_get_corbrp(hda);
364 wp = hda_get_corbwp(hda);
365
366 avail = rp - wp - 1;
367 while (avail < 0)
368 avail += hda->ctl->corb_entries;
369
370 return avail;
371}
372
373/** Write to CORB */
374static errno_t hda_corb_write(hda_t *hda, uint32_t *data, size_t count)
375{
376 size_t avail;
377 size_t wp;
378 size_t idx;
379 size_t now;
380 size_t i;
381 uint32_t *corb;
382 int wcnt;
383
384 avail = hda_corb_avail(hda);
385 wp = hda_get_corbwp(hda);
386 corb = (uint32_t *)hda->ctl->corb_virt;
387
388 idx = 0;
389 while (idx < count) {
390 now = min(avail, count - idx);
391
392 for (i = 0; i < now; i++) {
393 wp = (wp + 1) % hda->ctl->corb_entries;
394 corb[wp] = data[idx++];
395 }
396
397 hda_set_corbwp(hda, wp);
398
399 if (idx < count) {
400 /* We filled up CORB but still data remaining */
401 wcnt = corb_wait_max;
402 while (hda_corb_avail(hda) < 1 && wcnt > 0) {
403 async_usleep(100);
404 --wcnt;
405 }
406
407 /* If CORB is still full return timeout error */
408 if (hda_corb_avail(hda) < 1)
409 return ETIMEOUT;
410 }
411 }
412
413 return EOK;
414}
415
416static errno_t hda_rirb_read(hda_t *hda, hda_rirb_entry_t *data)
417{
418 size_t wp;
419 hda_rirb_entry_t resp;
420 hda_rirb_entry_t *rirb;
421
422 rirb = (hda_rirb_entry_t *)hda->ctl->rirb_virt;
423
424 wp = hda_get_rirbwp(hda);
425 ddf_msg(LVL_DEBUG2, "hda_rirb_read: wp=%zu", wp);
426 if (hda->ctl->rirb_rp == wp)
427 return ENOENT;
428
429 hda->ctl->rirb_rp = (hda->ctl->rirb_rp + 1) % hda->ctl->rirb_entries;
430 resp = rirb[hda->ctl->rirb_rp];
431
432 ddf_msg(LVL_DEBUG2, "RESPONSE resp=0x%x respex=0x%x",
433 resp.resp, resp.respex);
434 *data = resp;
435 return EOK;
436}
437
438static errno_t hda_solrb_read(hda_t *hda, hda_rirb_entry_t *data, size_t count)
439{
440 hda_rirb_entry_t resp;
441
442 ddf_msg(LVL_DEBUG, "hda_solrb_read()");
443
444 fibril_mutex_lock(&hda->ctl->solrb_lock);
445
446 while (count > 0) {
447 while (count > 0 && hda->ctl->solrb_rp != hda->ctl->solrb_wp) {
448 hda->ctl->solrb_rp = (hda->ctl->solrb_rp + 1) % softrb_entries;
449 resp = hda->ctl->solrb[hda->ctl->solrb_rp];
450
451 ddf_msg(LVL_DEBUG2, "solrb RESPONSE resp=0x%x respex=0x%x",
452 resp.resp, resp.respex);
453 if ((resp.respex & BIT_V(uint32_t, respex_unsol)) == 0) {
454 /* Solicited response */
455 *data++ = resp;
456 --count;
457 }
458 }
459
460 if (count > 0) {
461 if (hda->ctl->solrb_wp == hda->ctl->solrb_rp) {
462 fibril_condvar_wait_timeout(
463 &hda->ctl->solrb_cv, &hda->ctl->solrb_lock,
464 solrb_wait_us);
465 }
466
467 if (hda->ctl->solrb_wp == hda->ctl->solrb_rp) {
468 ddf_msg(LVL_NOTE, "hda_solrb_read() - last ditch effort process RIRB");
469 fibril_mutex_unlock(&hda->ctl->solrb_lock);
470 hda_ctl_process_rirb(hda->ctl);
471 fibril_mutex_lock(&hda->ctl->solrb_lock);
472 }
473
474 if (hda->ctl->solrb_wp == hda->ctl->solrb_rp) {
475 ddf_msg(LVL_NOTE, "hda_solrb_read() time out");
476 fibril_mutex_unlock(&hda->ctl->solrb_lock);
477 return ETIMEOUT;
478 }
479 }
480 }
481
482 fibril_mutex_unlock(&hda->ctl->solrb_lock);
483 return EOK;
484}
485
486hda_ctl_t *hda_ctl_init(hda_t *hda)
487{
488 hda_ctl_t *ctl;
489 uint32_t gctl;
490 uint32_t intctl;
491 int cnt;
492 errno_t rc;
493
494 ctl = calloc(1, sizeof(hda_ctl_t));
495 if (ctl == NULL)
496 return NULL;
497
498 fibril_mutex_initialize(&ctl->solrb_lock);
499 fibril_condvar_initialize(&ctl->solrb_cv);
500
501 hda->ctl = ctl;
502 ctl->hda = hda;
503
504 uint8_t vmaj = hda_reg8_read(&hda->regs->vmaj);
505 uint8_t vmin = hda_reg8_read(&hda->regs->vmin);
506 ddf_msg(LVL_NOTE, "HDA version %d.%d", vmaj, vmin);
507
508 if (vmaj != 1 || vmin != 0) {
509 ddf_msg(LVL_ERROR, "Unsupported HDA version (%d.%d).",
510 vmaj, vmin);
511 goto error;
512 }
513
514 ddf_msg(LVL_NOTE, "reg 0x%zx STATESTS = 0x%x",
515 (void *)&hda->regs->statests - (void *)hda->regs,
516 hda_reg16_read(&hda->regs->statests));
517 /**
518 * Clear STATESTS bits so they don't generate an interrupt later
519 * when we enable interrupts.
520 */
521 hda_reg16_write(&hda->regs->statests, 0x7f);
522
523 ddf_msg(LVL_NOTE, "after clearing reg 0x%zx STATESTS = 0x%x",
524 (void *)&hda->regs->statests - (void *)hda->regs,
525 hda_reg16_read(&hda->regs->statests));
526
527 gctl = hda_reg32_read(&hda->regs->gctl);
528 if ((gctl & BIT_V(uint32_t, gctl_crst)) != 0) {
529 ddf_msg(LVL_NOTE, "Controller not in reset. Resetting.");
530 hda_reg32_write(&hda->regs->gctl, gctl & ~BIT_V(uint32_t, gctl_crst));
531 }
532
533 ddf_msg(LVL_NOTE, "Taking controller out of reset.");
534 hda_reg32_write(&hda->regs->gctl, gctl | BIT_V(uint32_t, gctl_crst));
535
536 /* Wait for CRST to read as 1 */
537 cnt = ctrl_init_wait_max;
538 while (cnt > 0) {
539 gctl = hda_reg32_read(&hda->regs->gctl);
540 if ((gctl & BIT_V(uint32_t, gctl_crst)) != 0) {
541 ddf_msg(LVL_NOTE, "gctl=0x%x", gctl);
542 break;
543 }
544
545 ddf_msg(LVL_NOTE, "Waiting for controller to initialize.");
546 async_usleep(100*1000);
547 --cnt;
548 }
549
550 if (cnt == 0) {
551 ddf_msg(LVL_ERROR, "Timed out waiting for controller to come up.");
552 goto error;
553 }
554
555 ddf_msg(LVL_NOTE, "Controller is out of reset.");
556
557 ddf_msg(LVL_NOTE, "Read GCAP");
558 uint16_t gcap = hda_reg16_read(&hda->regs->gcap);
559 ctl->ok64bit = (gcap & BIT_V(uint16_t, gcap_64ok)) != 0;
560 ctl->oss = BIT_RANGE_EXTRACT(uint16_t, gcap_oss_h, gcap_oss_l, gcap);
561 ctl->iss = BIT_RANGE_EXTRACT(uint16_t, gcap_iss_h, gcap_iss_l, gcap);
562 ctl->bss = BIT_RANGE_EXTRACT(uint16_t, gcap_bss_h, gcap_bss_l, gcap);
563 ddf_msg(LVL_NOTE, "GCAP: 0x%x (64OK=%d)", gcap, ctl->ok64bit);
564 ddf_msg(LVL_NOTE, "iss: %d, oss: %d, bss: %d\n",
565 ctl->iss, ctl->oss, ctl->bss);
566 /* Give codecs enough time to enumerate themselves */
567 async_usleep(codec_enum_wait_us);
568
569 ddf_msg(LVL_NOTE, "STATESTS = 0x%x",
570 hda_reg16_read(&hda->regs->statests));
571
572 /* Enable interrupts */
573 intctl = hda_reg32_read(&hda->regs->intctl);
574 ddf_msg(LVL_NOTE, "intctl (0x%x) := 0x%x",
575 (unsigned)((void *)&hda->regs->intctl - (void *)hda->regs),
576 intctl | BIT_V(uint32_t, intctl_gie) | BIT_V(uint32_t, intctl_cie));
577 hda_reg32_write(&hda->regs->intctl, intctl |
578 BIT_V(uint32_t, intctl_gie) | BIT_V(uint32_t, intctl_cie) |
579 0x3fffffff);
580
581 rc = hda_corb_init(hda);
582 if (rc != EOK)
583 goto error;
584
585 rc = hda_rirb_init(hda);
586 if (rc != EOK)
587 goto error;
588
589 ddf_msg(LVL_NOTE, "call hda_codec_init()");
590 hda->ctl->codec = hda_codec_init(hda, 0);
591 if (hda->ctl->codec == NULL) {
592 ddf_msg(LVL_NOTE, "hda_codec_init() failed");
593 goto error;
594 }
595
596 ddf_msg(LVL_NOTE, "intsts=0x%x", hda_reg32_read(&hda->regs->intsts));
597 ddf_msg(LVL_NOTE, "sdesc[%d].sts=0x%x",
598 hda->ctl->iss, hda_reg8_read(&hda->regs->sdesc[hda->ctl->iss].sts));
599
600 return ctl;
601error:
602 hda_rirb_fini(hda);
603 hda_corb_fini(hda);
604 free(ctl);
605 hda->ctl = NULL;
606 return NULL;
607}
608
609void hda_ctl_fini(hda_ctl_t *ctl)
610{
611 ddf_msg(LVL_NOTE, "hda_ctl_fini()");
612 hda_rirb_fini(ctl->hda);
613 hda_corb_fini(ctl->hda);
614 free(ctl);
615}
616
617errno_t hda_cmd(hda_t *hda, uint32_t verb, uint32_t *resp)
618{
619 errno_t rc;
620 hda_rirb_entry_t rentry;
621
622 rc = hda_corb_write(hda, &verb, 1);
623 if (rc != EOK)
624 return rc;
625
626 if (resp != NULL) {
627 rc = hda_solrb_read(hda, &rentry, 1);
628 if (rc != EOK)
629 return rc;
630
631 /* XXX Verify that response came from the correct codec */
632 *resp = rentry.resp;
633 }
634
635 return EOK;
636}
637
638static void hda_ctl_process_rirb(hda_ctl_t *ctl)
639{
640 hda_rirb_entry_t resp;
641 errno_t rc;
642
643 while (true) {
644 rc = hda_rirb_read(ctl->hda, &resp);
645 if (rc != EOK) {
646// ddf_msg(LVL_NOTE, "nothing in rirb");
647 break;
648 }
649
650 ddf_msg(LVL_DEBUG2, "writing to solrb");
651 fibril_mutex_lock(&ctl->solrb_lock);
652 ctl->solrb_wp = (ctl->solrb_wp + 1) % softrb_entries;
653 ctl->solrb[ctl->solrb_wp] = resp;
654 fibril_mutex_unlock(&ctl->solrb_lock);
655 fibril_condvar_broadcast(&ctl->solrb_cv);
656 }
657}
658
659void hda_ctl_interrupt(hda_ctl_t *ctl)
660{
661 hda_ctl_process_rirb(ctl);
662}
663
664void hda_ctl_dump_info(hda_ctl_t *ctl)
665{
666 ddf_msg(LVL_NOTE, "corbwp=%d, corbrp=%d",
667 hda_reg16_read(&ctl->hda->regs->corbwp),
668 hda_reg16_read(&ctl->hda->regs->corbrp));
669 ddf_msg(LVL_NOTE, "corbctl=0x%x, corbsts=0x%x",
670 hda_reg8_read(&ctl->hda->regs->corbctl),
671 hda_reg8_read(&ctl->hda->regs->corbsts));
672 ddf_msg(LVL_NOTE, "rirbwp=0x%x, soft-rirbrp=0x%zx",
673 hda_reg16_read(&ctl->hda->regs->rirbwp),
674 ctl->rirb_rp);
675 ddf_msg(LVL_NOTE, "solrb_wp=0x%zx, solrb_rp=0x%zx",
676 ctl->solrb_wp, ctl->solrb_wp);
677}
678
679/** @}
680 */
Note: See TracBrowser for help on using the repository browser.