1// Copyright 2017 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <zircon/assert.h> 6#include <zircon/thread_annotations.h> 7#include <fbl/auto_lock.h> 8#include <string.h> 9 10#include <intel-hda/utils/intel-hda-registers.h> 11 12#include "codec-cmd-job.h" 13#include "debug-logging.h" 14#include "intel-hda-controller.h" 15 16namespace audio { 17namespace intel_hda { 18 19namespace { 20fbl::Mutex snapshot_regs_buffer_lock; 21ihda_controller_snapshot_regs_resp_t snapshot_regs_buffer TA_GUARDED(snapshot_regs_buffer_lock); 22} // anon namespace 23 24zx_status_t IntelHDAController::SnapshotRegs(dispatcher::Channel* channel, 25 const ihda_controller_snapshot_regs_req_t& req) { 26 ZX_DEBUG_ASSERT(channel != nullptr); 27 28 // TODO(johngro) : What an enormous PITA. Every register needs to be 29 // accessed with the proper sized transaction on the PCI bus, so we cannot 30 // just use memcpy to do this. Life will be better when we have VMOs in 31 // place. Then, we can implement the IOCTL by simply cloning the reigster 32 // VMO (reducing its rights to read-only in the process) and sending it back 33 // to the calling process. The diagnostic util can then put their own 34 // cycles on the PCI bus. 35 fbl::AutoLock lock(&snapshot_regs_buffer_lock); 36 37 auto regs_ptr = reinterpret_cast<hda_registers_t*>(snapshot_regs_buffer.snapshot); 38 auto& out_regs = *regs_ptr; 39 40 static_assert(sizeof(snapshot_regs_buffer.snapshot) == sizeof(hda_registers_t), 41 "Register snapshot buffer size does not match register file size!"); 42 43 snapshot_regs_buffer.hdr = req.hdr; 44 memset(&out_regs, 0, sizeof(out_regs)); 45 46 out_regs.gcap = REG_RD(®s()->gcap); 47 out_regs.vmin = REG_RD(®s()->vmin); 48 out_regs.vmaj = REG_RD(®s()->vmaj); 49 out_regs.outpay = REG_RD(®s()->outpay); 50 out_regs.inpay = REG_RD(®s()->inpay); 51 out_regs.gctl = REG_RD(®s()->gctl); 52 out_regs.wakeen = REG_RD(®s()->wakeen); 53 out_regs.statests = REG_RD(®s()->statests); 54 out_regs.gsts = REG_RD(®s()->gsts); 55 out_regs.outstrmpay = REG_RD(®s()->outstrmpay); 56 out_regs.instrmpay = REG_RD(®s()->instrmpay); 57 out_regs.intctl = REG_RD(®s()->intctl); 58 out_regs.intsts = REG_RD(®s()->intsts); 59 out_regs.walclk = REG_RD(®s()->walclk); 60 out_regs.ssync = REG_RD(®s()->ssync); 61 out_regs.corblbase = REG_RD(®s()->corblbase); 62 out_regs.corbubase = REG_RD(®s()->corbubase); 63 out_regs.corbwp = REG_RD(®s()->corbwp); 64 out_regs.corbrp = REG_RD(®s()->corbrp); 65 out_regs.corbctl = REG_RD(®s()->corbctl); 66 out_regs.corbsts = REG_RD(®s()->corbsts); 67 out_regs.corbsize = REG_RD(®s()->corbsize); 68 out_regs.rirblbase = REG_RD(®s()->rirblbase); 69 out_regs.rirbubase = REG_RD(®s()->rirbubase); 70 out_regs.rirbwp = REG_RD(®s()->rirbwp); 71 out_regs.rintcnt = REG_RD(®s()->rintcnt); 72 out_regs.rirbctl = REG_RD(®s()->rirbctl); 73 out_regs.rirbsts = REG_RD(®s()->rirbsts); 74 out_regs.rirbsize = REG_RD(®s()->rirbsize); 75 out_regs.icoi = REG_RD(®s()->icoi); 76 out_regs.icii = REG_RD(®s()->icii); 77 out_regs.icis = REG_RD(®s()->icis); 78 out_regs.dpiblbase = REG_RD(®s()->dpiblbase); 79 out_regs.dpibubase = REG_RD(®s()->dpibubase); 80 81 uint16_t gcap = REG_RD(®s()->gcap); 82 unsigned int stream_cnt = HDA_REG_GCAP_ISS(gcap) 83 + HDA_REG_GCAP_OSS(gcap) 84 + HDA_REG_GCAP_BSS(gcap); 85 86 for (unsigned int i = 0; i < stream_cnt; ++i) { 87 auto& sin = regs()->stream_desc[i]; 88 auto& sout = out_regs.stream_desc[i]; 89 90 sout.ctl_sts.w = REG_RD(&sin.ctl_sts.w); 91 sout.lpib = REG_RD(&sin.lpib); 92 sout.cbl = REG_RD(&sin.cbl); 93 sout.lvi = REG_RD(&sin.lvi); 94 sout.fifod = REG_RD(&sin.fifod); 95 sout.fmt = REG_RD(&sin.fmt); 96 sout.bdpl = REG_RD(&sin.bdpl); 97 sout.bdpu = REG_RD(&sin.bdpu); 98 } 99 100 return channel->Write(&snapshot_regs_buffer, sizeof(snapshot_regs_buffer)); 101} 102 103} // namespace intel_hda 104} // namespace audio 105