0,0 → 1,936 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
; Universal Interface for Intel High Definition Audio Codec ; |
; ; |
; Generic widget tree parser ; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|
; widget node for parsing |
struc HDA_GNODE |
{ |
.nid dw ? ;NID of this widget |
.nconns dw ? ;number of input connections |
.conn_list dd ? |
.slist dw ? ;temporary list |
dw ? |
|
.wid_caps dd ? ;widget capabilities |
.type db ? ;widget type |
.pin_ctl db ? ;pin controls |
.checked db ? ;the flag indicates that the node is already parsed |
.pin_caps dd ? ;pin widget capabilities |
.def_cfg dd ? ;default configuration |
.amp_out_caps dd ? ;AMP out capabilities |
.amp_in_caps dd ? ;AMP in capabilities |
.next dd ? ; struct list_head list |
.sizeof: |
} |
|
virtual at 0 |
HDA_GNODE HDA_GNODE |
end virtual |
|
struc HDA_GSPEC |
{ |
.dac_node dd ? ;DAC node |
dd ? |
.out_pin_node dd ? ;Output pin (Line-Out) node |
dd ? |
|
.def_amp_in_caps dd ? |
.def_amp_out_caps dd ? |
|
; .pcm_rec dd ? ;PCM information |
.nid_list dd 0 ;list of widgets |
} |
|
struc VOLUME_CTL |
{ |
.out_amp_node dd 0 ;Asper+ : To get/set volume |
.num_steps db ? ; num_steps=NumSteps+1 |
.step_size db ? ; step_size=StepSize+1 |
.maxDb dd ? ; Max volume in Db. maxDb=(num_steps*step_size/4*100) |
} |
|
; retrieve the default device type from the default config value |
|
proc defcfg_type stdcall, node:dword |
push edx |
mov edx, [node] |
mov eax, [edx + HDA_GNODE.def_cfg] |
and eax, AC_DEFCFG_DEVICE |
shr eax, AC_DEFCFG_DEVICE_SHIFT |
pop edx |
ret |
endp |
|
proc defcfg_location stdcall, node:dword |
push edx |
mov edx, [node] |
mov eax, [edx + HDA_GNODE.def_cfg] |
and eax, AC_DEFCFG_LOCATION |
shr eax, AC_DEFCFG_LOCATION_SHIFT |
pop edx |
ret |
endp |
|
proc defcfg_port_conn stdcall, node:dword |
push edx |
mov edx, [node] |
mov eax, [edx + HDA_GNODE.def_cfg] |
and eax, AC_DEFCFG_PORT_CONN |
shr eax, AC_DEFCFG_PORT_CONN_SHIFT |
pop edx |
ret |
endp |
|
proc defcfg_color stdcall, node:dword |
push edx |
mov edx, [node] |
mov eax, [edx + HDA_GNODE.def_cfg] |
and eax, AC_DEFCFG_COLOR |
shr eax, AC_DEFCFG_COLOR_SHIFT |
pop edx |
ret |
endp |
|
|
; destructor |
proc snd_hda_generic_free |
push eax ebx edx edi |
; free all widgets |
mov ebx, [spec.nid_list] ; ebx = 1st node address |
test ebx, ebx |
jz .out |
mov edx, [ebx + HDA_GNODE.next] ;edx = 2nd node address |
|
.next: |
test edx, edx |
jz .free_head |
|
mov eax, [edx + HDA_GNODE.conn_list] |
lea edi, [edx + HDA_GNODE.slist] |
cmp eax, edi |
je @f |
pusha |
call Kfree ;free conn_list |
popa |
@@: |
mov eax, edx |
mov edx, [edx + HDA_GNODE.next] |
pusha |
call Kfree ;free node |
popa |
jmp .next |
.free_head: |
mov eax, [spec.nid_list] |
pusha |
call Kfree ;free the very 1st node in the list |
popa |
mov [spec.nid_list], 0 |
.out: |
pop edi edx ebx eax |
ret |
endp |
|
|
; add a new widget node and read its attributes |
proc add_new_node stdcall, nid:dword |
push ebx ecx edx edi esi |
|
mov eax, HDA_GNODE.sizeof |
call Kmalloc |
test eax, eax |
jz .err_out ; Not enough memory |
|
mov edx, eax |
;Asper+ [ |
mov edi, edx |
xor eax, eax |
mov ecx, HDA_GNODE.sizeof |
rep stosb |
;Asper+ ] |
|
mov eax, [nid] |
mov word [edx + HDA_GNODE.nid], ax |
stdcall get_wcaps, eax |
mov [edx + HDA_GNODE.wid_caps], eax |
mov ebx, eax |
stdcall get_wcaps_type, eax |
mov byte [edx + HDA_GNODE.type], al |
|
mov eax, HDA_MAX_CONNECTIONS*2 ;HDA_MAX_CONNECTIONS * sizeof(word) |
push ebx ecx edx |
call Kmalloc ;malloc temporary conn_list |
pop edx ecx ebx |
mov edi, eax |
|
test ebx, AC_WCAP_CONN_LIST |
jz .no_conn_list |
|
stdcall snd_hda_get_connections, [nid], edi, HDA_MAX_CONNECTIONS |
mov ecx, eax |
cmp ecx, 0 |
jge @f |
|
mov eax, edx |
pusha |
call Kfree ;free node |
popa |
mov eax, ecx |
jmp .out |
.no_conn_list: |
|
xor ecx, ecx |
@@: |
cmp ecx, 2 ;nconns <= ARRAY_SIZE(node->slist) ? |
jg @f |
|
lea eax, [edx + HDA_GNODE.slist] |
mov [edx + HDA_GNODE.conn_list], eax |
jmp .set_conn_list |
@@: |
mov eax, ecx |
shl ecx, 1 |
push ebx ecx edx edi |
call Kmalloc ;malloc conn_list |
pop edi edx ecx ebx |
shr ecx, 1 |
test eax, eax |
jnz @f |
|
mov eax, edi |
pusha |
call Kfree ;free temporary conn_list |
popa |
jmp .err_out |
@@: |
mov [edx + HDA_GNODE.conn_list], eax |
.set_conn_list: |
mov [edx + HDA_GNODE.nconns], cx |
push edi |
mov esi, edi |
mov edi, eax |
rep movsw |
pop edi |
|
|
mov al, byte [edx + HDA_GNODE.type] |
test al, AC_WID_PIN |
jz @f |
;Asper+ [ |
cmp al, AC_WID_VENDOR |
je @f |
;Asper+ ] |
|
|
stdcall read_pin_cap, [nid] |
mov [edx + HDA_GNODE.pin_caps], eax |
stdcall snd_hda_codec_read, [nid], 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0 |
mov byte [edx + HDA_GNODE.pin_ctl], al |
stdcall snd_hda_codec_get_pincfg, [nid] |
mov [edx + HDA_GNODE.def_cfg], eax |
@@: |
|
xor eax, eax |
test ebx, AC_WCAP_OUT_AMP |
jz .no_out_amp |
test ebx, AC_WCAP_AMP_OVRD |
jz @f |
snd_hda_param_read [nid], AC_PAR_AMP_OUT_CAP |
@@: |
test eax, eax |
jnz @f |
mov eax, [spec.def_amp_out_caps] |
@@: |
mov [edx + HDA_GNODE.amp_out_caps], eax |
.no_out_amp: |
|
;;Asper+: Beeper [ |
; pusha |
; mov bl, byte [edx + HDA_GNODE.type] |
; cmp bl, AC_WID_BEEP |
; jne .not_beeper |
; |
; mov ebx, [nid] |
; mov [codec.beeper_nid], bx |
; |
; test eax, eax |
; jz .no_beeper_amp |
; ;set beep amplifier here |
; stdcall unmute_output, edx |
; .no_beeper_amp: |
; ;try to beep here |
; stdcall snd_hda_codec_read, [nid], 0, AC_VERB_GET_BEEP_CONTROL, 0 ;eax |
; if DEBUG |
; push eax esi |
; mov esi, msgBeeperNid |
; call SysMsgBoardStr |
; push eax |
; mov eax, [nid] |
; stdcall fdword2str, 2 |
; call SysMsgBoardStr |
; |
; mov esi, msgBeeperValue |
; call SysMsgBoardStr |
; pop eax |
; stdcall fdword2str, 2 |
; call SysMsgBoardStr |
; |
; mov esi, msgBeepNow |
; call SysMsgBoardStr |
; pop esi eax |
; end if |
; mov ecx, 256*1 |
; .next_tone: |
; dec ecx |
; movzx ebx, [esi + HDA_GNODE.nid] |
; stdcall snd_hda_codec_write, [nid], 0, AC_VERB_SET_BEEP_CONTROL, ecx |
; ;mov eax, 0x8000 |
; ;stdcall StallExec |
; test ecx, ecx |
; jnz .next_tone |
; .end_beep: |
; stdcall snd_hda_codec_read, [nid], 0, AC_VERB_GET_BEEP_CONTROL, 0 ;eax |
; if DEBUG |
; ;push eax esi |
; mov esi, msgBeeperValue |
; call SysMsgBoardStr |
; stdcall fdword2str, 2 |
; call SysMsgBoardStr |
; ;pop esi eax |
; end if |
; .not_beeper: |
; popa |
;;Asper+: Beeper ] |
|
xor eax, eax |
test ebx, AC_WCAP_IN_AMP |
jz .no_in_amp |
test ebx, AC_WCAP_AMP_OVRD |
jz @f |
snd_hda_param_read [nid], AC_PAR_AMP_IN_CAP |
@@: |
test eax, eax |
jnz @f |
mov eax, [spec.def_amp_in_caps] |
@@: |
mov [edx + HDA_GNODE.amp_in_caps], eax |
.no_in_amp: |
|
mov esi, [spec.nid_list] |
test esi, esi |
jnz @f |
mov [spec.nid_list], edx |
jmp .out |
@@: |
|
;Asper+: Sort pins by DA:Sequence during tree building [ |
mov ecx, esi |
movzx ebx, byte [edx + HDA_GNODE.def_cfg] |
push edi |
.next_node: |
cmp [esi + HDA_GNODE.type], AC_WID_PIN |
jne @f |
cmp [edx + HDA_GNODE.type], AC_WID_PIN |
je .pin |
|
mov edi, [spec.nid_list] |
cmp [edi + HDA_GNODE.type], AC_WID_PIN |
jne .not_pin |
mov [edx + HDA_GNODE.next], edi |
.head: ;CleverMouse+ |
mov [spec.nid_list], edx |
pop edi |
jmp .out |
.pin: |
movzx edi, byte [esi + HDA_GNODE.def_cfg] |
cmp edi, ebx |
jle @f |
.not_pin: |
mov [edx + HDA_GNODE.next], esi |
cmp esi, [spec.nid_list] ;CleverMouse+ |
jz .head ;CleverMouse+ |
mov esi, ecx |
jmp .insert |
@@: |
mov eax, [esi + HDA_GNODE.next] |
test eax, eax |
jz .insert |
mov ecx, esi |
mov esi, eax |
jmp .next_node |
.insert: |
mov [esi + HDA_GNODE.next], edx |
pop edi |
;Asper+ ] |
|
.out: |
mov eax, edi |
pusha |
call Kfree ;free temporary conn_list |
popa |
xor eax, eax |
pop esi edi edx ecx ebx |
ret |
|
.err_out: |
mov eax, edx |
pusha |
call Kfree ;free node |
popa |
xor eax, eax |
dec eax |
pop esi edi edx ecx ebx |
ret |
endp |
|
|
|
; build the AFG subtree |
proc build_afg_tree |
push ebx ecx edx |
|
mov ebx, [codec.afg] |
snd_hda_param_read ebx, AC_PAR_AMP_OUT_CAP |
|
mov [spec.def_amp_out_caps], eax |
snd_hda_param_read ebx, AC_PAR_AMP_IN_CAP |
mov [spec.def_amp_in_caps], eax |
|
stdcall snd_hda_get_sub_nodes, ebx |
mov ecx, eax |
and ecx, 0xFFFF ;ecx = nodes number |
mov edx, eax |
shr edx, 16 ;eax = address of the first nid |
|
test edx, edx |
jz @f |
cmp ecx, 0 |
jge .nid_ok |
@@: |
if FDEBUG |
push esi |
mov esi, emsgInvalidAFGSubtree |
call SysMsgBoardStr |
pop esi |
end if |
xor eax, eax |
dec eax |
jmp .out |
.nid_ok: |
|
; parse all nodes belonging to the AFG |
.next_node: |
test ecx, ecx |
jz .build_done |
|
stdcall add_new_node, edx |
test eax, eax |
jnz .out |
inc edx |
dec ecx |
jmp .next_node |
.build_done: |
xor eax, eax |
.out: |
pop edx ecx ebx |
ret |
endp |
|
|
; look for the node record for the given NID |
proc hda_get_node stdcall, nid:dword |
push ebx edx esi |
movzx ebx, word [nid] |
mov esi, [spec.nid_list] |
test esi, esi |
jz .out |
|
.next_node: |
mov edx, [esi + HDA_GNODE.next] |
test edx, edx ;Asper+ |
jz .not_found ;Asper+ |
mov ax, word [esi + HDA_GNODE.nid] |
cmp ax, bx |
je .out |
mov esi, edx |
jmp .next_node |
|
.not_found: ;Asper+ |
xor esi, esi |
.out: |
mov eax, esi |
pop esi edx ebx |
ret |
endp |
|
;Asper+[ |
proc set_eapd stdcall, node:dword ;nid:dword, on:dword |
push eax ebx esi |
mov esi, [node] |
cmp [esi + HDA_GNODE.type], AC_WID_PIN |
jne .out |
; eapd capable? |
test [esi + HDA_GNODE.pin_caps], AC_PINCAP_EAPD |
jz .out |
;stdcall snd_hda_codec_read, ebx, 0, AC_VERB_GET_EAPD_BTLENABLE, AC_EAPDBTL_EAPD |
;or eax, AC_EAPDBTL_EAPD |
movzx ebx, [esi + HDA_GNODE.nid] |
stdcall snd_hda_codec_write, ebx, 0, AC_VERB_SET_EAPD_BTLENABLE, AC_EAPDBTL_EAPD ;eax |
if DEBUG |
push eax esi |
mov esi, msgEnableEAPD |
call SysMsgBoardStr |
mov eax, ebx |
stdcall fdword2str, 3 |
call SysMsgBoardStr |
pop esi eax |
end if |
.out: |
pop esi ebx eax |
ret |
endp |
;Asper+] |
|
; unmute (and set max vol) the output amplifier |
proc unmute_output stdcall, node:dword |
|
push ebx ecx edx esi |
mov esi, [node] |
test [esi + HDA_GNODE.wid_caps], AC_WCAP_OUT_AMP |
jz .out |
movzx eax, word [esi + HDA_GNODE.nid] |
if DEBUG |
push esi |
mov esi, msgUnmuteOut |
call SysMsgBoardStr |
stdcall fdword2str, 3 |
call SysMsgBoardStr |
pop esi |
end if |
|
stdcall set_eapd, esi ;Asper+: set EAPD if exist |
|
mov ebx, eax |
mov eax, [esi + HDA_GNODE.amp_out_caps] |
mov ecx, eax |
|
and eax, AC_AMPCAP_NUM_STEPS |
shr eax, AC_AMPCAP_NUM_STEPS_SHIFT |
|
stdcall snd_hda_codec_amp_stereo, ebx, HDA_OUTPUT, 0, 0xFF, eax |
|
and ecx, AC_AMPCAP_STEP_SIZE |
shr ecx, AC_AMPCAP_STEP_SIZE_SHIFT |
|
test al, al |
jz .out |
if DEBUG |
push eax esi |
mov esi, msgAmpVal |
call SysMsgBoardStr |
stdcall fdword2str, 1 |
call SysMsgBoardStr |
|
mov esi, strSemicolon |
call SysMsgBoardStr |
mov eax, ecx |
stdcall fdword2str, 3 |
call SysMsgBoardStr |
pop esi eax |
end if |
mov [volume.out_amp_node], esi |
inc al |
mov [volume.num_steps], al |
inc cl |
mov [volume.step_size], cl |
mul cl |
shr eax, 2 |
imul eax, 100 |
mov [volume.maxDb], eax |
|
.out: |
xor eax, eax |
pop esi edx ecx ebx |
ret |
endp |
|
; unmute (and set max vol) the input amplifier |
proc unmute_input stdcall, node:dword, index:dword |
push ecx edx esi |
test [esi + HDA_GNODE.wid_caps], AC_WCAP_IN_AMP |
jz .out |
and [index], 0xF ;Asper+ : Ranger |
mov esi, [node] |
movzx eax, word [esi + HDA_GNODE.nid] |
if DEBUG |
push eax esi |
mov esi, msgUnmuteIn |
call SysMsgBoardStr |
stdcall fdword2str, 3 |
call SysMsgBoardStr |
mov esi, msgIdx |
call SysMsgBoardStr |
mov eax, [index] |
stdcall fdword2str, 3 |
call SysMsgBoardStr |
pop esi eax |
end if |
|
mov edx, [esi + HDA_GNODE.amp_in_caps] |
mov ecx, edx |
|
and edx, AC_AMPCAP_NUM_STEPS |
shr edx, AC_AMPCAP_NUM_STEPS_SHIFT |
|
stdcall snd_hda_codec_amp_stereo, eax, HDA_INPUT, [index], 0xFF, edx |
.out: |
xor eax, eax |
pop esi edx ecx |
ret |
endp |
|
|
; select the input connection of the given node. |
proc select_input_connection stdcall, node:dword, index:dword |
push ebx esi |
mov esi, [node] |
movzx eax, word [esi + HDA_GNODE.nid] |
mov ebx, [index] |
if DEBUG |
mov esi, msgConnect |
call SysMsgBoardStr |
stdcall fdword2str, 3 |
call SysMsgBoardStr |
|
mov esi, msgIdx |
call SysMsgBoardStr |
push eax |
mov eax, ebx |
stdcall fdword2str, 3 |
call SysMsgBoardStr |
pop eax |
end if |
stdcall snd_hda_codec_write, eax, 0, AC_VERB_SET_CONNECT_SEL, ebx |
pop esi ebx |
ret |
endp |
|
|
; clear checked flag of each node in the node list |
proc clear_check_flags |
push eax esi |
mov esi, [spec.nid_list] |
test esi, esi |
jz .out |
.next_node: |
mov byte [esi + HDA_GNODE.checked], 0 |
mov eax, [esi + HDA_GNODE.next] |
test eax, eax |
jz .out |
mov esi, eax |
jmp .next_node |
|
.out: |
pop esi eax |
ret |
endp |
|
; |
; parse the output path recursively until reach to an audio output widget |
; |
; returns 0 if not found, 1 if found, or a negative error code. |
; |
proc parse_output_path stdcall, node:dword, dac_idx:dword |
push ebx ecx edx esi |
mov esi, [node] |
mov al, byte [esi + HDA_GNODE.checked] |
test al, al |
jnz .ret_zero |
|
mov byte [esi + HDA_GNODE.checked], 1 |
|
mov al, byte [esi + HDA_GNODE.type] |
cmp al, AC_WID_AUD_OUT |
jne .not_wid_aud_out |
|
movzx eax, word [esi + HDA_GNODE.nid] |
mov ebx, [esi + HDA_GNODE.wid_caps] |
test ebx, AC_WCAP_DIGITAL |
jz @f |
if DEBUG |
push esi |
mov esi, msgSkipDigitalOutNode |
call SysMsgBoardStr |
stdcall fdword2str, 3 |
call SysMsgBoardStr |
pop esi |
end if |
jmp .ret_zero |
@@: |
if DEBUG |
push eax esi |
mov esi, msgAudOutFound |
call SysMsgBoardStr |
stdcall fdword2str, 3 |
call SysMsgBoardStr |
pop esi eax |
end if |
|
push eax |
stdcall unmute_output, esi ;Asper+ |
pop eax |
mov ecx, [dac_idx] |
shl ecx, 2 |
push eax |
mov eax, [spec.dac_node+ecx] |
test eax, eax |
pop eax |
jz @f |
; already DAC node is assigned, just unmute & connect |
cmp eax, [node] |
je .ret_one |
jmp .ret_zero |
@@: |
mov ecx, [dac_idx] |
shl ecx, 2 |
mov [spec.dac_node+ecx], eax |
jmp .ret_one ;found |
.not_wid_aud_out: |
movzx ebx, [esi + HDA_GNODE.nconns] |
xor ecx, ecx |
mov edx, [esi + HDA_GNODE.conn_list] |
test ebx, ebx |
jz .ret_zero |
.next_node: |
stdcall hda_get_node, [edx] |
test eax, eax |
jz .continue |
|
stdcall parse_output_path, eax, [dac_idx] |
|
cmp [esi + HDA_GNODE.nconns], 1 |
jle @f |
stdcall select_input_connection, esi, ecx |
@@: |
;UNSUPPORTED YET! stdcall unmute_input, esi, ecx |
stdcall unmute_output, esi |
jmp .ret_one |
|
.continue: |
add edx, 2 |
inc ecx |
cmp ecx, ebx |
jl .next_node |
.ret_zero: |
xor eax, eax |
pop esi edx ecx ebx |
ret |
.ret_one: |
xor eax, eax |
inc eax |
.ret: ;Asper+ |
pop esi edx ecx ebx |
ret |
endp |
|
; Look for the output PIN widget with the given jack type |
; and parse the output path to that PIN. |
; |
; Returns the PIN node when the path to DAC is established. |
proc parse_output_jack stdcall, jack_type:dword |
push edx esi |
|
mov esi, [spec.nid_list] |
test esi, esi |
jz .ret_zero |
.next_pin: |
cmp [esi + HDA_GNODE.type], AC_WID_PIN |
jne .continue |
|
; output capable? |
mov eax, [esi + HDA_GNODE.pin_caps] |
test eax, AC_PINCAP_OUT |
jz .continue |
|
stdcall defcfg_port_conn, esi |
cmp eax, AC_JACK_PORT_NONE |
je .continue ;unconnected |
|
mov edx, [jack_type] |
cmp edx, 0 |
jl @f |
|
stdcall defcfg_type, esi |
cmp edx, eax |
jne .continue |
|
test [esi + HDA_GNODE.wid_caps], AC_WCAP_DIGITAL |
jnz .continue ; skip SPDIF |
@@: |
; output as default? |
if DEBUG |
pusha |
; push esi |
; mov esi, msgPin_Nid |
; call SysMsgBoardStr |
; pop esi |
movzx eax, [esi + HDA_GNODE.nid] |
movzx ebx, [esi + HDA_GNODE.pin_ctl] |
mov ecx, [esi + HDA_GNODE.pin_caps] |
mov edx, [esi + HDA_GNODE.def_cfg] |
mov edi, [esi + HDA_GNODE.amp_out_caps] |
mov esi, msgPin_Nid |
call SysMsgBoardStr |
stdcall fdword2str, 3 |
call SysMsgBoardStr |
|
mov esi, msgPin_Ctl |
call SysMsgBoardStr |
mov eax, ebx |
stdcall fdword2str, 2 |
call SysMsgBoardStr |
|
mov esi, msgPin_Caps |
call SysMsgBoardStr |
mov eax, ecx |
stdcall fdword2str, 2 |
call SysMsgBoardStr |
|
mov esi, msgDef_Cfg |
call SysMsgBoardStr |
mov eax, edx |
stdcall fdword2str, 2 |
call SysMsgBoardStr |
|
mov esi, msgAmp_Out_Caps |
call SysMsgBoardStr |
mov eax, edi |
stdcall fdword2str, 2 |
call SysMsgBoardStr |
|
popa |
end if |
; test [esi + HDA_GNODE.pin_ctl], AC_PINCTL_OUT_EN |
; jz .continue |
stdcall clear_check_flags |
stdcall parse_output_path, esi, 0 |
|
test eax, eax |
jnz @f |
mov edx, [spec.out_pin_node] |
test edx, edx |
jz @f |
stdcall clear_check_flags |
stdcall parse_output_path, esi, 1 |
@@: |
cmp eax, 0 |
jle .l1 |
|
; unmute the PIN output |
stdcall unmute_output, esi |
; set PIN-Out enable |
xor edx, edx |
test [esi + HDA_GNODE.pin_caps], AC_PINCAP_HP_DRV |
jz @f |
mov edx, AC_PINCTL_HP_EN |
@@: |
or edx, AC_PINCTL_OUT_EN |
movzx eax, [esi + HDA_GNODE.nid] |
stdcall snd_hda_codec_write, eax, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, edx |
mov eax, esi |
jmp .out |
.l1: |
.continue: |
mov edx, [esi + HDA_GNODE.next] |
test edx, edx |
jz .ret_zero |
mov esi, edx |
jmp .next_pin |
.ret_zero: |
xor eax, eax |
.out: |
pop esi edx |
ret |
endp |
|
|
; parse outputs |
proc parse_output |
push edx |
; Look for the output PIN widget |
; |
; first, look for the line-out pin |
stdcall parse_output_jack, AC_JACK_LINE_OUT |
test eax, eax |
jz @f |
mov [spec.out_pin_node], eax ; found, remember the PIN node |
jmp .l1 |
@@: |
; if no line-out is found, try speaker out |
stdcall parse_output_jack, AC_JACK_SPEAKER |
test eax, eax |
jz .l1 |
mov [spec.out_pin_node], eax ; found, remember the PIN node |
.l1: |
; look for the HP-out pin |
stdcall parse_output_jack, AC_JACK_HP_OUT |
test eax, eax |
jz .l2 |
|
mov edx, [spec.out_pin_node] |
test edx, edx |
jnz @f |
mov [spec.out_pin_node], eax |
jmp .l2 |
@@: |
mov [spec.out_pin_node+4], eax |
.l2: |
mov edx, [spec.out_pin_node] |
test edx, edx |
jnz @f |
; no line-out or HP pins found, |
; then choose for the first output pin |
stdcall parse_output_jack, -1 |
|
mov [spec.out_pin_node], eax |
test eax, eax |
jnz @f |
if DEBUG |
push esi |
mov esi, emsgNoProperOutputPathFound |
call SysMsgBoardStr |
pop esi |
end if |
@@: |
pop edx |
xor eax, eax |
ret |
endp |
|
|
;(...) Skip functions for the input (capture is not supported). |
|
; the generic parser |
proc snd_hda_parse_generic_codec |
mov eax, [codec.afg] |
test eax, eax |
jz .out |
|
stdcall build_afg_tree |
cmp eax, 0 |
jl .error |
|
stdcall parse_output |
xor eax, eax |
.out: |
ret |
.error: |
stdcall snd_hda_generic_free |
ret |
endp |
|
|
; some data |
spec HDA_GSPEC |
volume VOLUME_CTL |