mirror of
https://github.com/AsahiLinux/m1n1
synced 2024-11-21 22:23:05 +00:00
aop: Stream high-power mic samples to ADMAC
Output audio format still unknown, not sure if it's garbage (see lpai commit) or some weird packed float encoding I'm not figuring out. Signed-off-by: Eileen Yoon <eyn@gmx.com>
This commit is contained in:
parent
0ebc339761
commit
2b62c08619
3 changed files with 284 additions and 310 deletions
|
@ -1,310 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: MIT
|
||||
import sys, pathlib
|
||||
sys.path.append(str(pathlib.Path(__file__).resolve().parents[1]))
|
||||
|
||||
import struct
|
||||
import traceback
|
||||
from construct import *
|
||||
|
||||
from m1n1.setup import *
|
||||
from m1n1.shell import run_shell
|
||||
from m1n1.hw.dart import DART, DARTRegs
|
||||
from m1n1.fw.asc import StandardASC, ASCDummyEndpoint
|
||||
from m1n1.fw.asc.base import *
|
||||
from m1n1.fw.aop import *
|
||||
from m1n1.fw.aop.ipc import *
|
||||
from m1n1.fw.afk.rbep import *
|
||||
from m1n1.fw.afk.epic import *
|
||||
|
||||
# Set up a secondary proxy channel so that we can stream
|
||||
# the microphone samples
|
||||
p.usb_iodev_vuart_setup(p.iodev_whoami())
|
||||
p.iodev_set_usage(IODEV.USB_VUART, USAGE.UARTPROXY)
|
||||
|
||||
p.pmgr_adt_clocks_enable("/arm-io/dart-aop")
|
||||
|
||||
adt_dc = u.adt["/arm-io/aop/iop-aop-nub/aop-audio/dc-2400000"]
|
||||
|
||||
pdm_config = Container(
|
||||
unk1=2,
|
||||
clockSource=u'pll ',
|
||||
pdmFrequency=2400000,
|
||||
unk3_clk=24000000,
|
||||
unk4_clk=24000000,
|
||||
unk5_clk=24000000,
|
||||
channelPolaritySelect=256,
|
||||
unk7=99,
|
||||
unk8=1013248,
|
||||
unk9=0,
|
||||
ratios=Container(
|
||||
r1=15,
|
||||
r2=5,
|
||||
r3=2,
|
||||
),
|
||||
filterLengths=0x542c47,
|
||||
coeff_bulk=120,
|
||||
coefficients=GreedyRange(Int32sl).parse(adt_dc.coefficients),
|
||||
unk10=1,
|
||||
micTurnOnTimeMs=20,
|
||||
unk11=1,
|
||||
micSettleTimeMs=50,
|
||||
)
|
||||
|
||||
decimator_config = Container(
|
||||
latency=15,
|
||||
ratios=Container(
|
||||
r1=15,
|
||||
r2=5,
|
||||
r3=2,
|
||||
),
|
||||
filterLengths=0x542c47,
|
||||
coeff_bulk=120,
|
||||
coefficients=GreedyRange(Int32sl).parse(adt_dc.coefficients),
|
||||
)
|
||||
|
||||
class AFKEP_Hello(AFKEPMessage):
|
||||
TYPE = 63, 48, Constant(0x80)
|
||||
UNK = 7, 0
|
||||
|
||||
class AFKEP_Hello_Ack(AFKEPMessage):
|
||||
TYPE = 63, 48, Constant(0xa0)
|
||||
|
||||
class EPICEndpoint(AFKRingBufEndpoint):
|
||||
BUFSIZE = 0x1000
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.seq = 0x0
|
||||
self.wait_reply = False
|
||||
self.ready = False
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@msg_handler(0x80, AFKEP_Hello)
|
||||
def Hello(self, msg):
|
||||
self.rxbuf, self.rxbuf_dva = self.asc.ioalloc(self.BUFSIZE)
|
||||
self.txbuf, self.txbuf_dva = self.asc.ioalloc(self.BUFSIZE)
|
||||
|
||||
self.send(AFKEP_Hello_Ack())
|
||||
|
||||
def handle_hello(self, hdr, sub, fd):
|
||||
if sub.type != 0xc0:
|
||||
return False
|
||||
|
||||
payload = fd.read()
|
||||
name = payload.split(b"\0")[0].decode("ascii")
|
||||
self.log(f"Hello! (endpoint {name})")
|
||||
self.ready = True
|
||||
return True
|
||||
|
||||
def handle_reply(self, hdr, sub, fd):
|
||||
if self.wait_reply:
|
||||
self.pending_call.read_resp(fd)
|
||||
self.wait_reply = False
|
||||
return True
|
||||
return False
|
||||
|
||||
def handle_ipc(self, data):
|
||||
fd = BytesIO(data)
|
||||
hdr = EPICHeader.parse_stream(fd)
|
||||
sub = EPICSubHeaderVer2.parse_stream(fd)
|
||||
|
||||
handled = False
|
||||
|
||||
if sub.category == EPICCategory.REPORT:
|
||||
handled = self.handle_hello(hdr, sub, fd)
|
||||
if sub.category == EPICCategory.REPLY:
|
||||
handled = self.handle_reply(hdr, sub, fd)
|
||||
|
||||
if not handled and getattr(self, 'VERBOSE', False):
|
||||
self.log(f"< 0x{hdr.channel:x} Type {hdr.type} Ver {hdr.version} Tag {hdr.seq}")
|
||||
self.log(f" Len {sub.length} Ver {sub.version} Cat {sub.category} Type {sub.type:#x} Ts {sub.timestamp:#x}")
|
||||
self.log(f" Unk1 {sub.unk1:#x} Unk2 {sub.unk2:#x}")
|
||||
chexdump(fd.read())
|
||||
|
||||
def indirect(self, call, chan=0x1000000d, timeout=0.1):
|
||||
tx = call.ARGS.build(call.args)
|
||||
self.asc.iface.writemem(self.txbuf, tx[4:])
|
||||
|
||||
cmd = self.roundtrip(IndirectCall(
|
||||
txbuf=self.txbuf_dva, txlen=len(tx) - 4,
|
||||
rxbuf=self.rxbuf_dva, rxlen=self.BUFSIZE,
|
||||
retcode=0,
|
||||
), category=EPICCategory.COMMAND, typ=call.TYPE)
|
||||
fd = BytesIO()
|
||||
fd.write(struct.pack("<I", cmd.rets.retcode))
|
||||
fd.write(self.asc.iface.readmem(self.rxbuf, cmd.rets.rxlen))
|
||||
fd.seek(0)
|
||||
call.read_resp(fd)
|
||||
return call
|
||||
|
||||
def roundtrip(self, call, chan=0x1000000d, timeout=0.3,
|
||||
category=EPICCategory.NOTIFY, typ=None):
|
||||
tx = call.ARGS.build(call.args)
|
||||
fd = BytesIO()
|
||||
fd.write(EPICHeader.build(Container(
|
||||
channel=chan,
|
||||
type=EPICType.NOTIFY,
|
||||
version=2,
|
||||
seq=self.seq,
|
||||
)))
|
||||
self.seq += 1
|
||||
fd.write(EPICSubHeaderVer2.build(Container(
|
||||
length=len(tx),
|
||||
category=category,
|
||||
type=typ or call.TYPE,
|
||||
)))
|
||||
fd.write(tx)
|
||||
|
||||
self.pending_call = call
|
||||
self.wait_reply = True
|
||||
self.send_ipc(fd.getvalue())
|
||||
|
||||
deadline = time.time() + timeout
|
||||
while time.time() < deadline and self.wait_reply:
|
||||
self.asc.work()
|
||||
if self.wait_reply:
|
||||
self.wait_reply = False
|
||||
raise ASCTimeout("ASC reply timed out")
|
||||
|
||||
return call
|
||||
|
||||
class SPUAppEndpoint(EPICEndpoint):
|
||||
SHORT = "SPUAppep"
|
||||
|
||||
class AccelEndpoint(EPICEndpoint):
|
||||
SHORT = "accelep"
|
||||
|
||||
class GyroEndpoint(EPICEndpoint):
|
||||
SHORT = "gyroep"
|
||||
|
||||
class UNK23Endpoint(EPICEndpoint):
|
||||
SHORT = "unk23ep"
|
||||
|
||||
class LASEndpoint(EPICEndpoint):
|
||||
SHORT = "lasep"
|
||||
#VERBOSE = True # <--- uncomment to see lid angle measurements
|
||||
|
||||
class WakehintEndpoint(EPICEndpoint):
|
||||
SHORT = "wakehintep"
|
||||
|
||||
class UNK26Endpoint(EPICEndpoint):
|
||||
SHORT = "unk26ep"
|
||||
|
||||
class AudioEndpoint(EPICEndpoint):
|
||||
SHORT = "audioep"
|
||||
|
||||
|
||||
class OSLogMessage(Register64):
|
||||
TYPE = 63, 56
|
||||
|
||||
class OSLog_Init(OSLogMessage):
|
||||
TYPE = 63, 56, Constant(1)
|
||||
UNK = 51, 0
|
||||
DVA = 7, 0
|
||||
|
||||
class AOPOSLogEndpoint(ASCBaseEndpoint):
|
||||
BASE_MESSAGE = OSLogMessage
|
||||
SHORT = "oslog"
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.started = False
|
||||
|
||||
@msg_handler(1, OSLog_Init)
|
||||
def Init(self, msg):
|
||||
self.iobuffer, self.iobuffer_dva = self.asc.ioalloc(0x1_0000)
|
||||
self.send(OSLog_Init(DVA=self.iobuffer_dva//0x1000))
|
||||
self.started = True
|
||||
return True
|
||||
|
||||
|
||||
class AOPClient(StandardASC, AOPBase):
|
||||
ENDPOINTS = {
|
||||
8: AOPOSLogEndpoint,
|
||||
|
||||
0x20: SPUAppEndpoint,
|
||||
0x21: AccelEndpoint,
|
||||
0x22: GyroEndpoint,
|
||||
0x23: UNK23Endpoint,
|
||||
0x24: LASEndpoint,
|
||||
0x25: WakehintEndpoint,
|
||||
0x26: UNK26Endpoint,
|
||||
0x27: AudioEndpoint,
|
||||
0x28: EPICEndpoint,
|
||||
0x29: EPICEndpoint,
|
||||
0x2a: EPICEndpoint,
|
||||
0x2b: EPICEndpoint
|
||||
}
|
||||
|
||||
def __init__(self, u, adtpath, dart=None):
|
||||
node = u.adt[adtpath]
|
||||
self.base = node.get_reg(0)[0]
|
||||
|
||||
AOPBase.__init__(self, u, node)
|
||||
super().__init__(u, self.base, dart)
|
||||
|
||||
p.dapf_init_all()
|
||||
|
||||
dart = DART.from_adt(u, "/arm-io/dart-aop", iova_range=(0x2c000, 0x10_000_000))
|
||||
dart.initialize()
|
||||
dart.regs.TCR[0].set(BYPASS_DAPF=0, BYPASS_DART=0, TRANSLATE_ENABLE=1)
|
||||
dart.regs.TCR[7].set(BYPASS_DAPF=0, BYPASS_DART=0, TRANSLATE_ENABLE=1)
|
||||
dart.regs.TCR[15].val = 0x20100
|
||||
|
||||
aop = AOPClient(u, "/arm-io/aop", dart)
|
||||
|
||||
aop.update_bootargs({
|
||||
'p0CE': 0x20000,
|
||||
# 'laCn': 0x0,
|
||||
# 'tPOA': 0x1,
|
||||
})
|
||||
|
||||
aop.verbose = 4
|
||||
|
||||
def set_aop_audio_pstate(devid, pstate):
|
||||
audep.roundtrip(SetDeviceProp(
|
||||
devid=devid,
|
||||
modifier=202,
|
||||
data=Container(
|
||||
devid=devid,
|
||||
cookie=1,
|
||||
target_pstate=pstate,
|
||||
unk2=1,
|
||||
)
|
||||
)).check_retcode()
|
||||
|
||||
try:
|
||||
aop.boot()
|
||||
for epno in range(0x20, 0x2c):
|
||||
aop.start_ep(epno)
|
||||
|
||||
timeout = 10
|
||||
while (not aop.audioep.ready) and timeout:
|
||||
aop.work_for(0.1)
|
||||
timeout -= 1
|
||||
|
||||
if not timeout:
|
||||
raise Exception("Timed out waiting on audio endpoint")
|
||||
|
||||
print("Finished boot")
|
||||
|
||||
audep = aop.audioep
|
||||
|
||||
audep.roundtrip(AttachDevice(devid='pdm0')).check_retcode()
|
||||
audep.indirect(SetDeviceProp(
|
||||
devid='pdm0', modifier=200, data=pdm_config)
|
||||
).check_retcode()
|
||||
audep.indirect(SetDeviceProp(
|
||||
devid='pdm0', modifier=210, data=decimator_config)
|
||||
).check_retcode()
|
||||
audep.roundtrip(AttachDevice(devid='hpai')).check_retcode()
|
||||
audep.roundtrip(AttachDevice(devid='lpai')).check_retcode()
|
||||
audep.roundtrip(SetDeviceProp(
|
||||
devid='lpai', modifier=301, data=Container(unk1=7, unk2=7, unk3=1, unk4=7))
|
||||
).check_retcode()
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
except Exception:
|
||||
print(traceback.format_exc())
|
||||
|
||||
run_shell(locals(), poll_func=aop.work)
|
170
proxyclient/experiments/aop_audio.py
Executable file
170
proxyclient/experiments/aop_audio.py
Executable file
|
@ -0,0 +1,170 @@
|
|||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: MIT
|
||||
import sys, pathlib
|
||||
sys.path.append(str(pathlib.Path(__file__).resolve().parents[1]))
|
||||
|
||||
import struct
|
||||
from construct import *
|
||||
|
||||
from m1n1.setup import *
|
||||
from m1n1.shell import run_shell
|
||||
from m1n1.hw.dart import DART
|
||||
from m1n1.fw.aop.client import AOPClient
|
||||
from m1n1.fw.aop.ipc import *
|
||||
|
||||
# on the first terminal: M1N1DEVICE=/dev/ttyACM0 python3 experiments/aop_audio.py
|
||||
# at that point (hpai at pw1), aop powers on admac and you should be dropped into a shell
|
||||
# on a second terminal in parallel: M1N1DEVICE=/dev/ttyACM1 tools/admac_stream.py --node admac-aop-audio --channel 1 -v | xxd -g 4 -c 12 -e
|
||||
# inside the shell (on the first terminal), aop_start()
|
||||
# there should now be microphone samples streamed to admac
|
||||
# see povik's commit #fc66046
|
||||
|
||||
# aop nodes have no clocks described in adt for j293. it does it itself
|
||||
p.pmgr_adt_clocks_enable("/arm-io/aop")
|
||||
p.pmgr_adt_clocks_enable("/arm-io/dart-aop")
|
||||
|
||||
# Set up a secondary proxy channel so that we can stream
|
||||
# the microphone samples
|
||||
p.usb_iodev_vuart_setup(p.iodev_whoami())
|
||||
p.iodev_set_usage(IODEV.USB_VUART, USAGE.UARTPROXY)
|
||||
|
||||
pdm2 = u.adt["/arm-io/aop/iop-aop-nub/aop-audio/audio-pdm2"]
|
||||
decm = u.adt["/arm-io/aop/iop-aop-nub/aop-audio/dc-2400000"]
|
||||
|
||||
pdm_config = Container(
|
||||
bytesPerSample=pdm2.bytesPerSample, # 2 ??
|
||||
clockSource=pdm2.clockSource, # 'pll '
|
||||
pdmFrequency=pdm2.pdmFrequency, # 2400000
|
||||
pdmcFrequency=pdm2.pdmcFrequency, # 24000000
|
||||
slowClockSpeed=pdm2.slowClockSpeed, # 24000000
|
||||
fastClockSpeed=pdm2.fastClockSpeed, # 24000000
|
||||
channelPolaritySelect=pdm2.channelPolaritySelect, # 256
|
||||
channelPhaseSelect=pdm2.channelPhaseSelect, # traces say 99 but device tree says 0
|
||||
unk8=0xf7600,
|
||||
unk9=0, # this should be latency (thus 15, see below) but traces say 0
|
||||
ratios=Container(
|
||||
r1=decm.ratios.r0,
|
||||
r2=decm.ratios.r1,
|
||||
r3=decm.ratios.r2,
|
||||
),
|
||||
filterLengths=decm.filterLengths,
|
||||
coeff_bulk=120,
|
||||
coefficients=GreedyRange(Int32sl).parse(decm.coefficients),
|
||||
unk10=1,
|
||||
micTurnOnTimeMs=pdm2.micTurnOnTimeMs, # 20
|
||||
unk11=1,
|
||||
micSettleTimeMs=pdm2.micSettleTimeMs, # 50
|
||||
)
|
||||
|
||||
decimator_config = Container(
|
||||
latency=decm.latency, # 15
|
||||
ratios=Container(
|
||||
r1=decm.ratios.r0, # 15
|
||||
r2=decm.ratios.r1, # 5
|
||||
r3=decm.ratios.r2, # 2
|
||||
),
|
||||
filterLengths=decm.filterLengths,
|
||||
coeff_bulk=120,
|
||||
coefficients=GreedyRange(Int32sl).parse(decm.coefficients),
|
||||
)
|
||||
|
||||
dart = DART.from_adt(u, "/arm-io/dart-aop",
|
||||
iova_range=(u.adt["/arm-io/dart-aop"].vm_base, 0x1000000000))
|
||||
dart.initialize()
|
||||
|
||||
aop = AOPClient(u, "/arm-io/aop", dart)
|
||||
aop.update_bootargs({
|
||||
'p0CE': 0x20000,
|
||||
'laCn': 0x0,
|
||||
'tPOA': 0x1,
|
||||
"gila": 0x80,
|
||||
})
|
||||
aop.verbose = 4
|
||||
|
||||
p.dapf_init_all()
|
||||
aop.asc.OUTBOX_CTRL.val = 0x20001 # (FIFOCNT=0x0, OVERFLOW=0, EMPTY=1, FULL=0, RPTR=0x0, WPTR=0x0, ENABLE=1)
|
||||
|
||||
# incredible power state naming scheme:
|
||||
# idle: in sleep state (default at boot)
|
||||
# pw1 : in active state (admac powers on) but not capturing
|
||||
# pwrd: start capturing
|
||||
# to start capturing, we put the 'hpai' (high power audio input?) device
|
||||
# from idle -> pw1 -> pwrd state. it starts capturing at pwrd
|
||||
# shutdown sequence must also be pwrd -> pw1 -> idle
|
||||
|
||||
def aop_start():
|
||||
aop.audio.send_notify(SetDeviceProp(
|
||||
devid=u'hpai',
|
||||
modifier=202,
|
||||
data=Container(
|
||||
devid=u'hpai',
|
||||
cookie=2,
|
||||
target_pstate=u'pwrd',
|
||||
unk2=1,
|
||||
)
|
||||
))
|
||||
|
||||
def aop_stop():
|
||||
aop.audio.send_notify(SetDeviceProp(
|
||||
devid='hpai',
|
||||
modifier=202,
|
||||
data=Container(
|
||||
devid='hpai',
|
||||
cookie=3,
|
||||
target_pstate='pw1 ',
|
||||
unk2=1,
|
||||
)
|
||||
))
|
||||
|
||||
aop.audio.send_notify(SetDeviceProp(
|
||||
devid='hpai',
|
||||
modifier=202,
|
||||
data=Container(
|
||||
devid='hpai',
|
||||
cookie=4,
|
||||
target_pstate='idle',
|
||||
unk2=0,
|
||||
)
|
||||
))
|
||||
|
||||
def main():
|
||||
aop.start()
|
||||
for epno in [0x20, 0x21, 0x22, 0x24, 0x25, 0x26, 0x27, 0x28]:
|
||||
aop.start_ep(epno)
|
||||
aop.work_for(0.3)
|
||||
audep = aop.audio
|
||||
|
||||
audep.send_notify(AttachDevice(devid='hpai')) # high power audio input; actual mic
|
||||
audep.send_notify(AttachDevice(devid='lpai')) # low power audio input; voice trigger mic
|
||||
audep.send_notify(AttachDevice(devid='pdm0')) # leap: low-energy audio processor I think
|
||||
# [syslog] * [udioPDMNodeBase.cpp:554]PDMDev<pdm0> off ->xi0 , 0->2400000 AP state 1
|
||||
|
||||
# initChannelControl (<7, 7, 1, 7>)
|
||||
audep.send_notify(SetDeviceProp(devid='lpai', modifier=301, data=Container(unk1=7, unk2=7, unk3=1, unk4=7)))
|
||||
audep.send_notify(SetDeviceProp(devid='pdm0', modifier=200, data=pdm_config))
|
||||
audep.send_notify(SetDeviceProp(devid='pdm0', modifier=210, data=decimator_config))
|
||||
ret = audep.send_roundtrip(AudioPropertyState(devid="hpai"))
|
||||
print("hpai state: %s" % (ret.state)) # idle
|
||||
|
||||
audep.send_notify(SetDeviceProp(
|
||||
devid='hpai',
|
||||
modifier=202,
|
||||
data=Container(
|
||||
devid='hpai',
|
||||
cookie=1,
|
||||
target_pstate='pw1 ',
|
||||
unk2=0,
|
||||
)
|
||||
))
|
||||
|
||||
ret = audep.send_roundtrip(AudioPropertyState(devid="hpai"))
|
||||
print("hpai state: %s" % (ret.state))
|
||||
assert(ret.state == "pw1 ")
|
||||
|
||||
try:
|
||||
main()
|
||||
pass
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
|
||||
run_shell(locals(), poll_func=aop.work)
|
|
@ -118,6 +118,30 @@ class WrappedCall(EPICCall):
|
|||
self.dump()
|
||||
raise ValueError(f"retcode {self.rets.retcode} in {str(type(self))} (call dumped, see above)")
|
||||
|
||||
@reg_calltype
|
||||
class AudioProbeDevice(EPICCall):
|
||||
TYPE = 0x20
|
||||
SUBTYPE = 0xc3_00_00_01
|
||||
ARGS = Struct(
|
||||
"pad" / Const(0x0, Int32ul),
|
||||
"unk1" / Hex(Const(0xffffffff, Int32ul)),
|
||||
"subtype" / Hex(Const(0xc3000001, Int32ul)),
|
||||
"pad2" / ZPadding(16),
|
||||
"cookie" / Default(Hex(Int32ul), 0),
|
||||
"len" / Hex(Const(0x28, Int64ul)),
|
||||
"devno" / Int32ul,
|
||||
)
|
||||
RETS = Struct(
|
||||
"retcode" / Const(0x0, Int32ul),
|
||||
"devid" / FourCC,
|
||||
"format" / FourCC,
|
||||
"sample_rate" / Int32ul,
|
||||
"channels" / Int32ul,
|
||||
"bytes_per_sample" / Int32ul,
|
||||
"unk_1f" / Default(Hex(Int32ul), 0),
|
||||
"unk" / Array(51, Default(Hex(Int32ul), 0)),
|
||||
)
|
||||
|
||||
@WrappedCall.reg_subclass
|
||||
class AttachDevice(WrappedCall):
|
||||
CALLTYPE = 0xc3_00_00_02
|
||||
|
@ -246,6 +270,96 @@ DEVPROPS = {
|
|||
),
|
||||
}
|
||||
|
||||
class AudioPropertyKey(IntEnum):
|
||||
STATE = 200 # 0xc8
|
||||
POWER = 202 # 0xca
|
||||
MAIN = 203 # 0xcb
|
||||
FORMAT = 302 # 0x12e
|
||||
|
||||
@reg_calltype
|
||||
class AudioProperty(EPICCall):
|
||||
TYPE = 0x20
|
||||
SUBTYPE = 0xc3000004
|
||||
SUBCLASSES = {}
|
||||
|
||||
@classmethod
|
||||
def subclass(cls, cls2):
|
||||
cls.SUBCLASSES[int(cls2.SUBTYPE)] = cls2
|
||||
return cls2
|
||||
|
||||
@AudioProperty.subclass
|
||||
class AudioPropertyState(AudioProperty):
|
||||
SUBSUBTYPE = AudioPropertyKey.STATE
|
||||
ARGS = Struct(
|
||||
"pad" / Const(0x0, Int32ul),
|
||||
"unk1" / Hex(Const(0xffffffff, Int32ul)),
|
||||
"calltype" / Hex(Const(0xc3000004, Int32ul)),
|
||||
"blank2" / ZPadding(16),
|
||||
"cookie" / Default(Hex(Int32ul), 0),
|
||||
"len" / Hex(Const(0x30, Int64ul)),
|
||||
"devid" / FourCC,
|
||||
"modifier" / Const(AudioPropertyKey.STATE, Int32ul),
|
||||
"data" / Const(0x1, Int32ul),
|
||||
)
|
||||
RETS = Struct(
|
||||
"retcode" / Const(0x0, Int32ul),
|
||||
"size" / Const(4, Int32ul),
|
||||
"state" / FourCC,
|
||||
)
|
||||
|
||||
@AudioProperty.subclass
|
||||
class AudioPropertyFormat(AudioProperty):
|
||||
SUBSUBTYPE = AudioPropertyKey.FORMAT
|
||||
ARGS = Struct(
|
||||
"pad" / Const(0x0, Int32ul),
|
||||
"unk1" / Hex(Const(0xffffffff, Int32ul)),
|
||||
"calltype" / Hex(Const(0xc3000004, Int32ul)),
|
||||
"blank2" / ZPadding(16),
|
||||
"cookie" / Default(Hex(Int32ul), 0),
|
||||
"len" / Hex(Const(0x30, Int64ul)),
|
||||
"devid" / FourCC,
|
||||
"modifier" / Const(AudioPropertyKey.FORMAT, Int32ul),
|
||||
"data" / Const(0x1, Int32ul),
|
||||
)
|
||||
RETS = Struct(
|
||||
"retcode" / Const(0x0, Int32ul),
|
||||
"format" / Int32ul, # 16 == float32?
|
||||
"fourcc" / FourCC, # PCML
|
||||
"sample_rate" / Int32ul, # 16000
|
||||
"channels" / Int32ul, # 3
|
||||
"bytes_per_sample" / Int32ul, # 2
|
||||
)
|
||||
|
||||
AudioPowerSetting = Struct(
|
||||
"devid" / FourCC,
|
||||
"unk1" / Int32ul,
|
||||
"cookie" / Default(Hex(Int32ul), 0),
|
||||
"blank" / ZPadding(8),
|
||||
"target_pstate" / FourCC,
|
||||
"unk2" / Int32ul,
|
||||
"blank2" / ZPadding(20),
|
||||
)
|
||||
|
||||
@AudioProperty.subclass
|
||||
class AudioPropertyPower(AudioProperty):
|
||||
SUBSUBTYPE = AudioPropertyKey.POWER
|
||||
ARGS = Struct(
|
||||
"pad" / Const(0x0, Int32ul),
|
||||
"unk1" / Hex(Const(0xffffffff, Int32ul)),
|
||||
"calltype" / Hex(Const(0xc3000005, Int32ul)),
|
||||
"blank2" / ZPadding(16),
|
||||
"cookie" / Default(Hex(Int32ul), 0),
|
||||
"len" / Hex(Const(0x30 + 0x30, Int64ul)), # len(this.data) + 0x30
|
||||
"devid" / FourCC,
|
||||
"modifier" / Const(AudioPropertyKey.POWER, Int32ul),
|
||||
"len2" / Hex(Const(0x30, Int32ul)), # len(this.data)
|
||||
"data" / AudioPowerSetting,
|
||||
)
|
||||
RETS = Struct(
|
||||
"retcode" / Const(0x0, Int32ul),
|
||||
"value" / HexDump(GreedyBytes),
|
||||
)
|
||||
|
||||
@WrappedCall.reg_subclass
|
||||
class GetDeviceProp(WrappedCall):
|
||||
CALLTYPE = 0xc3_00_00_04
|
||||
|
|
Loading…
Reference in a new issue