/drivers/audio/intel_hda/CODEC.INC |
---|
0,0 → 1,1336 |
;; Compose a 32bit command word to be sent to the HD-audio controller |
proc make_codec_cmd stdcall, nid:dword, direct:dword, verb:dword, parm:dword |
push ebx |
and dword [codec.addr], 0xF |
and dword [direct], 1 |
and dword [nid], 0x7F |
and dword [verb], 0xFFF |
and dword [parm], 0xFFFF |
mov eax, [codec.addr] |
shl eax, 28 |
mov ebx, [direct] |
shl ebx, 27 |
or eax, ebx |
mov ebx, [nid] |
shl ebx, 20 |
or eax, ebx |
mov ebx, [verb] |
shl ebx, 8 |
or eax, ebx |
mov ebx, [parm] |
or eax, ebx |
pop ebx |
ret |
.err: |
pop ebx |
mov eax, -1 |
ret |
endp |
;; Send and receive a verb |
proc codec_exec_verb stdcall, cmd:dword;, res:dword <- returned in eax |
push ebx edx |
mov ebx, [cmd] |
cmp ebx, -1 |
jne @f |
pop edx ebx |
mov eax, -1 |
ret |
@@: |
if FDEBUG ;YAHOO |
push eax esi |
mov esi, msgVerbQuery |
call SysMsgBoardStr |
mov eax, ebx |
stdcall fdword2str, 2 |
call SysMsgBoardStr |
pop esi eax |
end if |
mov edx, -1 |
.again: |
; call snd_hda_power_up |
stdcall azx_send_cmd, ebx |
mov ebx, eax |
test ebx, ebx |
jnz @f |
call azx_get_response |
mov edx, eax |
if FDEBUG |
test edx, edx |
jz .end_debug |
push eax esi |
mov esi, msgVerbAnswer |
call SysMsgBoardStr |
mov eax, edx |
stdcall fdword2str, 2 |
call SysMsgBoardStr |
pop esi eax |
.end_debug: |
end if |
@@: |
; call snd_hda_power_down |
cmp edx, -1 |
jne .l1 |
mov eax, [ctrl.rirb_error] |
test eax, eax |
jz .l1 |
mov eax, [ctrl.response_reset] |
jz @f |
if DEBUG |
push esi |
mov esi, emsgBusResetFatalComm |
call SysMsgBoardStr |
pop esi |
end if |
call azx_bus_reset |
@@: |
.l1: |
;; clear reset-flag when the communication gets recovered |
test ebx, ebx |
jnz @f |
mov [ctrl.response_reset], 0 |
@@: |
mov eax, edx |
pop edx ebx |
ret |
endp |
;; |
;; snd_hda_codec_read - send a command and get the response |
;; @nid: NID to send the command |
;; @direct: direct flag |
;; @verb: the verb to send |
;; @parm: the parameter for the verb |
;; |
;; Send a single command and read the corresponding response. |
;; |
;; Returns the obtained response value, or -1 for an error. |
;; |
proc snd_hda_codec_read stdcall, nid:dword, direct:dword, verb:dword, parm:dword |
stdcall make_codec_cmd, [nid], [direct], [verb], [parm] |
stdcall codec_exec_verb, eax |
ret |
endp |
;; |
;; snd_hda_codec_write - send a single command without waiting for response |
;; @nid: NID to send the command |
;; @direct: direct flag |
;; @verb: the verb to send |
;; @parm: the parameter for the verb |
;; |
;; Send a single command without waiting for response. |
;; |
;; Returns 0 if successful, or a negative error code. |
;; |
proc snd_hda_codec_write stdcall, nid:dword, direct:dword, verb:dword, parm:dword |
; Do we need to support a sync write? |
stdcall make_codec_cmd, [nid], [direct], [verb], [parm] |
stdcall codec_exec_verb, eax |
ret |
endp |
;; |
;; snd_hda_sequence_write - sequence writes |
;; @seq: VERB array to send |
;; |
;; Send the commands sequentially from the given array. |
;; The array must be terminated with NID=0. |
;; |
proc snd_hda_sequence_write stdcall, seq:dword |
push eax ebx ecx esi |
mov esi, [seq] |
@@: |
mov ecx, [esi + hda_verb.nid] |
mov ebx, [esi + hda_verb.verb] |
mov eax, [esi + hda_verb.param] |
stdcall snd_hda_codec_write, ecx, 0, ebx, eax |
add esi, hda_verb.sizeof |
test ecx, ecx |
jnz @b |
pop esi ecx ebx eax |
ret |
endp |
macro snd_hda_param_read nid, param |
{ |
stdcall snd_hda_codec_read, nid, 0, AC_VERB_PARAMETERS, param |
} |
;; |
;; snd_hda_get_sub_nodes - get the range of sub nodes |
;; @codec: the HDA codec |
;; @nid: NID to parse |
;; @start_id: the pointer to store the start NID |
;; |
;; Parse the NID and store the start NID of its sub-nodes. |
;; Returns the number of sub-nodes. |
;; |
proc snd_hda_get_sub_nodes stdcall, nid:dword;, start_id:dword <- returned in upper word of eax |
snd_hda_param_read [nid], AC_PAR_NODE_COUNT |
cmp eax, -1 |
jne @f |
inc eax |
@@: |
and eax, 0x7FFF7FFF |
ret |
endp |
;; |
;; snd_hda_get_connections - get connection list |
;; @codec: the HDA codec |
;; @nid: NID to parse |
;; @conn_list: connection list array |
;; @max_conns: max. number of connections to store |
;; |
;; Parses the connection list of the given widget and stores the list |
;; of NIDs. |
;; |
;; Returns the number of connections, or a negative error code. |
;; |
proc snd_hda_get_connections stdcall, nid:dword, conn_list:dword, max_conns:dword ;Asper: Complete translation! |
locals |
parm dd ? |
conn_len dd ? |
conns dd 0 |
shift db 8 |
num_elements dd 4 |
mask dd 0x7F |
wcaps dd ? |
prev_nid dw 1 ;Asper: Hmm.. Probably ALSA bug that it isn't initialized. I suppose to init it with 1. |
endl |
push ebx ecx edx edi esi |
mov edi, [conn_list] |
test edi, edi |
jz .err_out |
mov ecx, [max_conns] |
cmp ecx, 0 |
jle .err_out |
stdcall get_wcaps, [nid] |
mov ebx, eax |
mov [wcaps], eax |
stdcall get_wcaps_type, ebx |
cmp eax, AC_WID_VOL_KNB |
je .conn_list_ok |
test ebx, AC_WCAP_CONN_LIST |
jnz .conn_list_ok |
if DEBUG |
mov esi, emsgConnListNotAvailable |
call SysMsgBoardStr |
mov eax, [nid] |
stdcall fdword2str, 3 |
call SysMsgBoardStr |
end if |
xor eax, eax |
dec eax |
jmp .out |
.conn_list_ok: |
snd_hda_param_read [nid], AC_PAR_CONNLIST_LEN |
mov [parm], eax |
test eax, AC_CLIST_LONG |
jz @f |
; long form |
mov [shift], 16 |
mov [num_elements], 2 |
mov [mask], 0x7FFF ;Asper+ |
@@: |
and eax, AC_CLIST_LENGTH |
test eax, eax |
jz .out ; no connection |
mov [conn_len], eax |
cmp eax, 1 |
jne .multi_conns |
; single connection |
stdcall snd_hda_codec_read, [nid], 0, AC_VERB_GET_CONNECT_LIST, 0 |
mov [parm], eax |
cmp [parm], -1 |
jne @f |
cmp [ctrl.rirb_error], 0 |
jne @f |
xor eax, eax |
dec eax |
jmp .out |
@@: |
mov eax, [parm] |
and eax, [mask] |
stosd |
xor eax, eax |
inc eax |
jmp .out |
.multi_conns: |
; multi connection |
xor ecx, ecx |
mov edx, [num_elements] |
.next_conn: |
mov eax, ecx |
.mod: |
cmp eax, edx |
jl .mod_counted |
sub eax, edx |
jmp .mod |
.mod_counted: |
test eax, eax |
jnz .l1 |
stdcall snd_hda_codec_read, [nid], 0, AC_VERB_GET_CONNECT_LIST, ecx |
mov [parm], eax |
cmp eax, -1 |
jne .l1 |
cmp [ctrl.rirb_error], 0 |
jne .err_out |
.l1: |
mov eax, 1 |
push ecx |
mov cl, [shift] |
dec cl |
shl eax, cl |
and eax, [parm] |
pop ecx |
mov ebx, eax ;ranges |
mov eax, [parm] |
and eax, [mask] ;val |
test eax, eax |
jnz @f |
if DEBUG |
push eax esi |
mov esi, emsgInvConnList |
call SysMsgBoardStr |
mov eax, [nid] |
stdcall fdword2str, 1 |
call SysMsgBoardStr |
mov esi, strSemicolon |
call SysMsgBoardStr |
mov eax, ecx |
stdcall fdword2str, 0 |
call SysMsgBoardStr |
mov esi, strSemicolon |
call SysMsgBoardStr |
mov eax, [parm] |
stdcall fdword2str, 2 |
call SysMsgBoardStr |
pop esi eax |
end if |
xor eax, eax |
jmp .out |
@@: |
push ecx |
mov cl, [shift] |
shr [parm], cl |
pop ecx |
test ebx, ebx |
jz .range_zero |
; ranges between the previous and this one |
movzx esi, word [prev_nid] |
test esi, esi |
jz .l2 |
cmp esi, eax |
jl @f |
.l2: |
if DEBUG |
push eax esi |
push esi |
mov esi, emsgInvDepRangeVal |
call SysMsgBoardStr |
pop esi |
push eax |
mov eax, esi |
stdcall fdword2str, 0 |
call SysMsgBoardStr |
mov esi, strSemicolon |
call SysMsgBoardStr |
pop eax |
stdcall fdword2str, 2 |
call SysMsgBoardStr |
pop esi eax |
end if |
jmp .continue |
@@: |
push ecx |
mov ecx, esi |
inc ecx |
mov ebx, [conns] |
.next_conn2: |
cmp ebx, [max_conns] |
jl @f |
if DEBUG |
push esi |
mov esi, emsgTooManyConns |
call SysMsgBoardStr |
pop esi |
end if |
pop ecx |
jmp .err_out |
@@: |
shl ebx, 1 |
push edi |
add edi, ebx |
mov word [edi], cx |
pop edi |
shr ebx, 1 |
inc ebx |
inc ecx |
cmp ecx, eax |
jle .next_conn2 |
mov [conns], ebx |
pop ecx |
jmp .end_range_test |
.range_zero: |
mov ebx, [conns] |
cmp ebx, [max_conns] |
jl @f |
if DEBUG |
push esi |
mov esi, emsgTooManyConns |
call SysMsgBoardStr |
pop esi |
end if |
jmp .err_out |
@@: |
shl ebx, 1 |
push edi |
add edi, ebx |
mov word [edi], ax |
pop edi |
shr ebx, 1 |
inc ebx |
mov [conns], ebx |
.end_range_test: |
mov [prev_nid], ax |
.continue: |
inc ecx |
cmp ecx, [conn_len] |
jl .next_conn |
mov eax, [conns] |
.out: |
pop esi edi edx ecx ebx |
ret |
.err_out: |
pop esi edi edx ecx ebx |
mov eax, -1 |
ret |
endp |
; Asper: Have to be realized later, when we will work with such events, but not NOW! |
;proc snd_hda_queue_unsol_events stdcall, res:dword, res_ex:dword |
; push ebx edi esi |
; ... |
; pop esi edi ebx |
; ret |
;endp |
; This functions also will be later realized. |
;proc process_unsol_events stdcall, work:dword |
;proc init_usol_queue stdcall, bus:dword |
;; |
;; snd_hda_bus_new - create a HDA bus |
;; @card: the card entry |
;; @temp: the template for hda_bus information |
;; @busp: the pointer to store the created bus instance |
;; |
;; Returns 0 if successful, or a negative error code. |
;; |
;proc snd_hda_bus_new |
; if we want to support unsolicited events, we have to solve this |
; bus->workq = create_singlethread_workqueue(bus->workq_name); |
; (...) |
; xor eax, eax |
; ret |
;endp |
;; |
;; snd_hda_codec_init - initialize a HDA codec |
;; |
;; Returns 0 if successful, or a negative error code. |
;; |
proc snd_hda_codec_init ; We use just one codec (the first found) |
snd_hda_param_read AC_NODE_ROOT, AC_PAR_VENDOR_ID |
cmp eax, -1 |
jne @f |
snd_hda_param_read AC_NODE_ROOT, AC_PAR_VENDOR_ID |
@@: |
mov [codec.chip_id], ax |
shr eax, 16 |
mov [codec.vendor_id], ax |
snd_hda_param_read AC_NODE_ROOT, AC_PAR_SUBSYSTEM_ID |
mov [codec.subsystem_id], eax |
snd_hda_param_read AC_NODE_ROOT, AC_PAR_REV_ID |
mov [codec.revision_id], eax |
stdcall setup_fg_nodes |
mov eax, [codec.afg] |
test eax, eax |
jnz @f |
mov eax, [codec.mfg] |
test eax, eax |
jnz @f |
if DEBUG |
push esi |
mov esi, emsgNoAFGorMFGFound |
call SysMsgBoardStr |
pop esi |
end if |
mov eax, -1 |
ret |
@@: |
mov ebx, eax |
push ebx |
stdcall read_widget_caps, eax |
cmp eax, 0 |
jge @f |
if DEBUG |
push esi |
mov esi, emsgNoMem |
call SysMsgBoardStr |
pop esi |
end if |
pop ebx |
mov eax, -1 |
ret |
@@: |
call read_pin_defaults |
cmp eax, 0 |
jge @f |
pop ebx |
mov eax, -1 |
ret |
@@: |
mov eax, [codec.subsystem_id] |
test eax, eax |
jnz @f |
stdcall snd_hda_codec_read, ebx, 0, AC_VERB_GET_SUBSYSTEM_ID, 0 |
@@: |
; power up all before initialization |
; stdcall snd_hda_set_power_state, ebx, AC_PWRST_D0 |
pop ebx |
ret |
endp |
;; |
;; snd_hda_codec_configure - (Re-)configure the HD-audio codec |
;; |
;; Start parsing of the given codec tree and (re-)initialize the whole |
;; patch instance. |
;; |
;; Returns 0 if successful or a negative error code. |
;; |
proc snd_hda_codec_configure |
call get_codec_name |
@@: |
; call the default parser |
stdcall snd_hda_parse_generic_codec ;entry point to generic tree parser!!! |
;Asper+:patch for HP Elitebook 8730w [ |
; push eax ebx |
; mov ebx, [codec.afg] |
; stdcall snd_hda_codec_write, ebx, 0, AC_VERB_SET_GPIO_MASK, 0x02 |
; stdcall snd_hda_codec_write, ebx, 0, AC_VERB_SET_GPIO_DIRECTION, 0x02 |
; stdcall snd_hda_codec_write, ebx, 0, AC_VERB_SET_GPIO_DATA, 0x02 ; first muted |
; pop ebx eax |
;Asper+ ] |
test eax, eax |
jz @f |
if DEBUG |
push esi |
mov esi, emsgNoParserAvailable |
call SysMsgBoardStr |
pop esi |
end if |
@@: |
.out: |
ret |
endp |
; get_codec_name - store the codec name |
proc get_codec_name |
push eax ebx edi esi |
mov eax, [codec.ac_vendor_ids] |
test eax, eax |
jnz .get_chip_name |
mov ax, [codec.vendor_id] |
mov edi, hda_vendor_ids |
@@: |
mov ebx, [edi] |
test ebx, ebx |
jz .unknown |
cmp ax, bx |
jne .next |
mov eax, [edi+4] |
mov [codec.ac_vendor_ids], eax |
mov esi, eax |
call SysMsgBoardStr |
.get_chip_name: |
stdcall detect_chip, [edi+8] |
pop esi edi ebx eax |
ret |
.next: |
add edi, 12 |
jmp @b |
.unknown: |
mov [codec.ac_vendor_ids], ac_unknown |
mov [codec.chip_ids], chip_unknown |
mov esi, chip_unknown |
call SysMsgBoardStr |
movzx eax, [codec.chip_id] |
stdcall fdword2str, 2 |
call SysMsgBoardStr |
pop esi edi ebx eax |
ret |
endp |
align 4 |
proc detect_chip stdcall, chip_tab:dword |
push eax ebx edi esi |
mov ax, [codec.chip_id] |
mov edi, [chip_tab] |
@@: |
mov ebx, [edi] |
cmp ebx, 0xFF |
je .unknown |
cmp ax, bx |
jne .next |
mov eax, [edi+4] |
mov [codec.chip_ids], eax |
mov esi, eax |
call SysMsgBoardStr |
pop esi edi ebx eax |
ret |
.next: |
add edi, 8 |
jmp @b |
.unknown: |
mov [codec.chip_ids], chip_unknown |
mov esi, chip_unknown |
call SysMsgBoardStr |
movzx eax, [codec.chip_id] |
stdcall fdword2str, 2 |
call SysMsgBoardStr |
pop esi edi ebx eax |
ret |
endp |
;; look for an AFG and MFG nodes |
proc setup_fg_nodes |
push eax ebx ecx |
stdcall snd_hda_get_sub_nodes, AC_NODE_ROOT |
mov ecx, eax |
and ecx, 0x7FFF ; total_nodes |
mov ebx, eax |
shr ebx, 16 |
and ebx, 0x7FFF ; nid |
if DEBUG ;YAHOO |
push eax esi |
mov esi, msgSETUP_FG_NODES |
call SysMsgBoardStr |
mov eax, ebx |
stdcall fdword2str, 1 |
call SysMsgBoardStr |
mov esi, strSemicolon |
call SysMsgBoardStr |
mov eax, ecx |
stdcall fdword2str, 3 |
call SysMsgBoardStr |
pop esi eax |
end if |
.next: |
test ecx, ecx |
jz .l1 |
snd_hda_param_read ebx, AC_PAR_FUNCTION_TYPE |
and eax, 0xFF |
if DEBUG ;YAHOO |
push eax esi |
mov esi, msgFG_TYPE |
call SysMsgBoardStr |
stdcall fdword2str, 3 |
call SysMsgBoardStr |
pop esi eax |
end if |
cmp eax, AC_GRP_AUDIO_FUNCTION |
jne @f |
mov [codec.afg], ebx |
mov [codec.function_id], eax |
jmp .continue |
@@: |
cmp eax, AC_GRP_MODEM_FUNCTION |
jne @f |
mov [codec.mfg], ebx |
mov [codec.function_id], eax |
jmp .continue |
@@: |
.continue: |
inc ebx |
dec ecx |
jnz .next |
.l1: |
pop ecx ebx eax |
ret |
endp |
;====================================================================================== |
; read widget caps for each widget and store in cache |
proc read_widget_caps stdcall, fg_node:dword |
push ebx ecx edx edi |
stdcall snd_hda_get_sub_nodes, [fg_node] |
mov ecx, eax |
and ecx, 0x7FFF ; total_nodes |
mov [codec.num_nodes], cx |
mov ebx, eax |
shr ebx, 16 |
and ebx, 0x7FFF ; nid |
mov [codec.start_nid], bx |
if DEBUG ;YAHOO |
push eax esi |
mov esi, msgSETUP_FG_NODES |
call SysMsgBoardStr |
mov eax, ebx |
stdcall fdword2str, 1 |
call SysMsgBoardStr |
mov esi, strSemicolon |
call SysMsgBoardStr |
mov eax, ecx |
stdcall fdword2str, 3 |
call SysMsgBoardStr |
pop esi eax |
end if |
if FDEBUG ;YAHOO |
push esi |
mov esi, msgWCaps |
call SysMsgBoardStr |
pop esi |
end if |
mov eax, ecx |
shl eax, 2 |
push ebx ecx |
call Kmalloc |
pop ecx ebx |
test eax, eax |
jz .err_out |
mov [codec.wcaps], eax |
mov edi, eax |
.next_node: |
snd_hda_param_read ebx, AC_PAR_AUDIO_WIDGET_CAP |
stosd |
inc ebx |
dec ecx |
jnz .next_node |
pop edi edx ecx ebx |
xor eax, eax |
ret |
.err_out: |
pop edi edx ecx ebx |
xor eax, eax |
dec eax |
ret |
endp |
; read all pin default configurations and save codec->init_pins |
proc read_pin_defaults |
push ebx ecx edx edi |
movzx ebx, [codec.start_nid] |
movzx ecx, [codec.num_nodes] |
;Asper [ |
mov eax, HDA_PINCFG.sizeof |
mul cl |
push ebx ecx |
call Kmalloc |
pop ecx ebx |
test eax, eax |
jz .err_out |
mov [codec.init_pins], eax |
mov edi, eax |
;Asper ] |
if FDEBUG |
push eax esi |
mov esi, msgPinCfgs |
call SysMsgBoardStr |
pop esi eax |
end if |
.next_node: |
stdcall get_wcaps, ebx |
and eax, AC_WCAP_TYPE |
shr eax, AC_WCAP_TYPE_SHIFT |
cmp eax, AC_WID_PIN |
jne .continue |
mov [edi + HDA_PINCFG.nid], bx |
stdcall snd_hda_codec_read, ebx, 0, AC_VERB_GET_CONFIG_DEFAULT, 0 |
mov [edi + HDA_PINCFG.cfg], eax |
.continue: |
add edi, HDA_PINCFG.sizeof |
inc ebx |
dec ecx |
jnz .next_node |
;Asper [ |
and ebx, 0xFFFF |
sub bx, [codec.start_nid] |
mov [codec.num_pins], ebx |
;Asper ] |
pop edi edx ecx ebx |
xor eax, eax |
ret |
.err_out: |
pop edi edx ecx ebx |
xor eax, eax |
dec eax |
ret |
endp |
; look up the given pin config list and return the item matching with NID |
proc look_up_pincfg stdcall, array:dword, nid:dword |
push ebx ecx edx |
mov ecx, [codec.num_pins] |
mov eax, [array] |
mov ebx, [nid] |
.next_pin: |
mov dx, [eax + HDA_PINCFG.nid] |
cmp dx, bx |
je .out |
.continue: |
add eax, HDA_PINCFG.sizeof |
dec ecx |
jnz .next_pin |
xor eax, eax |
.out: |
pop edx ecx ebx |
ret |
endp |
; write a config value for the given NID |
proc set_pincfg stdcall, nid:dword, cfg:dword |
push eax ebx ecx edx |
mov eax, [cfg] |
xor ebx, ebx |
mov edx, AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 |
mov ecx, 4 |
@@: |
mov bl, al |
stdcall snd_hda_codec_write, [nid], 0, edx, ebx |
shr eax, 8 |
inc edx |
dec ecx |
jnz @b |
.l1: |
pop edx ecx ebx eax |
ret |
endp |
;; |
;; snd_hda_codec_get_pincfg - Obtain a pin-default configuration |
;; @codec: the HDA codec |
;; @nid: NID to get the pin config |
;; |
;; Get the current pin config value of the given pin NID. |
;; If the pincfg value is cached or overridden via sysfs or driver, |
;; returns the cached value. |
;; |
proc snd_hda_codec_get_pincfg stdcall, nid:dword |
push edi |
stdcall look_up_pincfg, [codec.init_pins], [nid] |
test eax, eax |
jz @f |
mov edi, eax |
mov eax, [edi + HDA_PINCFG.cfg] |
@@: |
pop edi |
ret |
endp |
;====================================================================================== |
;; |
;; snd_hda_codec_setup_stream - set up the codec for streaming |
;; @nid: the NID to set up |
;; @stream_tag: stream tag to pass, it's between 0x1 and 0xf. |
;; @channel_id: channel id to pass, zero based. |
;; @format: stream format. |
;; |
proc hda_codec_setup_stream stdcall, nid:dword, stream_tag:dword, channel_id:dword, format:dword |
push eax |
mov eax, [nid] |
test eax, eax |
jnz @f |
pop eax |
ret |
@@: |
if DEBUG |
push esi |
mov esi, msgHDACodecSetupStream |
call SysMsgBoardStr |
stdcall fdword2str, 3 |
call SysMsgBoardStr |
mov esi, msgStream |
call SysMsgBoardStr |
mov eax, [stream_tag] |
stdcall fdword2str, 3 |
call SysMsgBoardStr |
mov esi, msgChannel |
call SysMsgBoardStr |
mov eax, [channel_id] |
stdcall fdword2str, 3 |
call SysMsgBoardStr |
mov esi, msgFormat |
call SysMsgBoardStr |
mov eax, [format] |
stdcall fdword2str, 3 |
call SysMsgBoardStr |
pop esi |
end if |
mov eax, [stream_tag] |
shl eax, 4 |
or eax, [channel_id] |
stdcall snd_hda_codec_write, [nid], 0, AC_VERB_SET_CHANNEL_STREAMID, eax |
mov eax, 1000 ; wait 1 ms |
call StallExec |
stdcall snd_hda_codec_write, [nid], 0, AC_VERB_SET_STREAM_FORMAT, [format] |
pop eax |
ret |
endp |
proc snd_hda_codec_cleanup_stream stdcall, nid:dword |
push eax |
mov eax, [nid] |
test eax, eax |
jz @f |
pop eax |
ret |
@@: |
if DEBUG |
push esi |
mov esi, msgHDACodecCleanupStream |
call SysMsgBoardStr |
stdcall fdword2str, 3 |
call SysMsgBoardStr |
pop esi |
end if |
stdcall snd_hda_codec_write, [nid], 0, AC_VERB_SET_CHANNEL_STREAMID, 0 |
if 0 ; keep the format |
mov eax, 1000000 ; wait 100 ms |
call StallExec |
stdcall snd_hda_codec_write, [nid], 0, AC_VERB_SET_STREAM_FORMAT, 0 |
end if |
pop eax |
ret |
endp |
proc read_pin_cap, nid:dword |
snd_hda_param_read [nid], AC_PAR_PIN_CAP |
ret |
endp |
;; read the current volume |
proc get_volume_mute stdcall, nid:dword, ch:dword, direction:dword, index:dword |
push ebx |
mov ebx, AC_AMP_GET_LEFT |
mov eax, [ch] |
test eax, eax |
jz @f |
mov ebx, AC_AMP_GET_RIGHT |
@@: |
mov eax, [direction] |
cmp eax, HDA_OUTPUT |
jne @f |
or ebx, AC_AMP_GET_OUTPUT |
jmp .l1 |
@@: |
or ebx, AC_AMP_GET_INPUT |
.l1: |
or ebx, [index] |
stdcall snd_hda_codec_read, [nid], 0, AC_VERB_GET_AMP_GAIN_MUTE, ebx |
and eax, 0xFF |
pop ebx |
ret |
endp |
;; write the current volume in info to the h/w |
proc put_volume_mute stdcall, nid:dword, ch:dword, direction:dword, index:dword, val:dword |
push eax ebx |
mov ebx, AC_AMP_SET_LEFT |
mov eax, [ch] |
test eax, eax |
jz @f |
mov ebx, AC_AMP_SET_RIGHT |
@@: |
mov eax, [direction] |
cmp eax, HDA_OUTPUT |
jne @f |
or ebx, AC_AMP_SET_OUTPUT |
jmp .l1 |
@@: |
or ebx, AC_AMP_SET_INPUT |
.l1: |
mov eax, [index] |
shl eax, AC_AMP_SET_INDEX_SHIFT |
or ebx, eax |
or ebx, [val] |
stdcall snd_hda_codec_write, [nid], 0, AC_VERB_SET_AMP_GAIN_MUTE, ebx |
pop ebx eax |
ret |
endp |
;; |
;; snd_hda_codec_amp_update - update the AMP value |
;; @nid: NID to read the AMP value |
;; @ch: channel (left=0 or right=1) |
;; @direction: #HDA_INPUT or #HDA_OUTPUT |
;; @idx: the index value (only for input direction) |
;; @mask: bit mask to set |
;; @val: the bits value to set |
;; |
;; Update the AMP value with a bit mask. |
;; Returns 0 if the value is unchanged, 1 if changed. |
;; |
;-proc snd_hda_codec_amp_update stdcall, nid:dword, ch:dword, direction:dword, idx:dword, mask:dword, val:dword |
;- push ebx edx |
;- mov eax, [mask] |
;- mov ebx, [val] |
;- and ebx, eax |
;- xor eax, -1 |
;- mov edx, eax |
;- stdcall get_volume_mute, [nid], [ch], [direction], [idx] |
;- and eax, edx |
;- or ebx, eax |
;- |
;- stdcall put_volume_mute, [nid], [ch], [direction], [idx], ebx |
;- xor eax, eax |
;- inc eax |
;- pop edx ebx |
;- ret |
;-endp |
;; |
;; snd_hda_codec_amp_stereo - update the AMP stereo values |
;; @nid: NID to read the AMP value |
;; @direction: #HDA_INPUT or #HDA_OUTPUT |
;; @idx: the index value (only for input direction) |
;; @mask: bit mask to set |
;; @val: the bits value to set |
;; |
;; Update the AMP values like snd_hda_codec_amp_update(), but for a |
;; stereo widget with the same mask and value. |
;; |
proc snd_hda_codec_amp_stereo stdcall, nid:dword, direction:dword, idx:dword, mask:dword, val:dword |
push ebx edx |
mov ebx, [val] |
mov edx, [mask] |
and ebx, edx |
stdcall put_volume_mute, [nid], 0, [direction], [idx], ebx |
stdcall put_volume_mute, [nid], 1, [direction], [idx], ebx |
pop edx ebx |
ret |
endp |
;; set power state of the codec |
proc snd_hda_set_power_state stdcall, fg:dword, power_state:dword |
push eax ebx ecx edx |
; this delay seems necessary to avoid click noise at power down |
mov ebx, [power_state] |
cmp ebx, AC_PWRST_D3 |
jne @f |
mov eax, 100000 |
call StallExec |
@@: |
stdcall snd_hda_codec_read, [fg], 0, AC_VERB_SET_POWER_STATE, ebx |
;partial workaround for "azx_get_response timeout" |
cmp ebx, AC_PWRST_D0 |
jne @f |
mov dx, [codec.vendor_id] |
cmp dx, 0x14F1 |
jne @f |
mov eax, 10000 |
call StallExec |
@@: |
movzx ecx, [codec.num_nodes] |
movzx edx, [codec.start_nid] |
.next_nid: |
stdcall get_wcaps, edx |
test eax, AC_WCAP_POWER |
jz .skip_nid |
stdcall get_wcaps_type, eax |
cmp ebx, AC_PWRST_D3 |
jne .l1 |
cmp eax, AC_WID_PIN |
jne .l1 |
;don't power down the widget if it controls |
;eapd and EAPD_BTLENABLE is set. |
stdcall read_pin_cap, edx |
test eax, AC_PINCAP_EAPD |
jz .l2 |
stdcall snd_hda_codec_read, edx, 0, AC_VERB_GET_EAPD_BTLENABLE, 0 |
and eax, 0x02 |
test eax, eax |
jnz .skip_nid |
.l2: |
.l1: |
stdcall snd_hda_codec_write, edx, 0, AC_VERB_SET_POWER_STATE, ebx |
.skip_nid: |
inc edx |
dec ecx |
jnz .next_nid |
cmp ebx, AC_PWRST_D0 |
jne .out |
;wait until codec reaches to D0 |
mov ecx, 500 |
.wait_D0: |
stdcall snd_hda_codec_read, [fg], 0, AC_VERB_GET_POWER_STATE, 0 |
cmp eax, ebx |
je .out |
mov eax, 1000 ; msleep(1); |
call StallExec |
dec ecx |
jnz .wait_D0 |
.out: |
pop edx ecx ebx eax |
ret |
endp |
;data |
; codec vendors |
align 16 |
msg_Cirrus db 'Cirrus Logic ',0 |
msg_Motorola db 'Motorola ',0 |
msg_SiliconImage db 'Silicon Image ',0 |
msg_Realtek db 'Realtek ',0 |
msg_Creative db 'Creative ',0 |
msg_IDT db 'IDT ',0 |
msg_LSI db 'LSI ',0 |
msg_AnalogDevices db 'Analog Devices ',0 |
msg_CMedia db 'C-Media ',0 |
msg_Conexant db 'Conexant ',0 |
msg_Chrontel db 'Chrontel ',0 |
msg_LG db 'LG ',0 |
msg_Wolfson db 'Wolfson Microelectronics ',0 |
msg_Qumranet db 'Qumranet ',0 |
msg_SigmaTel db 'SigmaTel ',0 |
ac_unknown db 'unknown manufacturer ',0 |
chip_unknown db 'unknown codec id ', 0 |
; codec vendor labels |
align 4 |
hda_vendor_ids: |
dd 0x1002, msg_ATI, chips_ATI |
dd 0x1013, msg_Cirrus, chips_Cirrus |
dd 0x1057, msg_Motorola, chips_Motorola |
dd 0x1095, msg_SiliconImage, chips_SiliconImage |
dd 0x10de, msg_NVidia, chips_NVidia |
dd 0x10ec, msg_Realtek, chips_Realtek |
dd 0x1102, msg_Creative, chips_Creative |
dd 0x1106, msg_VIA, chips_VIA |
dd 0x111d, msg_IDT, chips_IDT |
dd 0x11c1, msg_LSI, chips_LSI |
dd 0x11d4, msg_AnalogDevices, chips_Analog |
dd 0x13f6, msg_CMedia, chips_CMedia |
dd 0x14f1, msg_Conexant, chips_Conexant |
dd 0x17e8, msg_Chrontel, chips_Chrontel |
dd 0x1854, msg_LG, chips_LG |
dd 0x1aec, msg_Wolfson, chips_Wolfson |
dd 0x1af4, msg_Qumranet, chips_Qumranet ; Qemu 0.14 |
dd 0x434d, msg_CMedia, chips_CMedia |
dd 0x8086, msg_Intel, chips_Intel |
dd 0x8384, msg_SigmaTel, chips_SigmaTel |
dd 0 ; terminator |
align 16 ;known codecs |
chips_ATI dd 0xAA01, chip_ATIR6XX |
dd 0xFF |
chips_Cirrus dd 0xFF |
chips_Motorola dd 0xFF |
chips_SiliconImage dd 0x1392, chip_SI1392 |
dd 0xFF |
chips_NVidia dd 0x0002, chip_MCP78 |
dd 0xFF |
chips_Realtek dd 0x0262, chip_ALC262 |
dd 0x0268, chip_ALC268 |
dd 0x0269, chip_ALC269 |
dd 0x0272, chip_ALC272 |
dd 0x0662, chip_ALC662 |
dd 0x0663, chip_ALC663 |
dd 0x0883, chip_ALC883 |
dd 0x0887, chip_ALC887 |
dd 0x0888, chip_ALC888 |
dd 0x0889, chip_ALC889 |
dd 0xFF |
chips_Creative dd 0xFF |
chips_VIA dd 0xE721, chip_VT1708B_1 |
dd 0x0397, chip_VT17085_0 |
dd 0xFF |
chips_IDT dd 0xFF |
chips_LSI dd 0xFF |
chips_Analog dd 0x1986, chip_AD1986A |
dd 0x198B, chip_AD198B |
dd 0xFF |
chips_CMedia dd 0xFF |
chips_Conexant dd 0x5045, chip_CX20549 |
dd 0x5051, chip_CX20561 |
dd 0xFF |
chips_Chrontel dd 0xFF |
chips_LG dd 0xFF |
chips_Wolfson dd 0xFF |
chips_Intel dd 0xFF |
chips_Qumranet dd 0x0010, chip_HDA_OUTPUT |
dd 0x0020, chip_HDA_DUPLEX |
dd 0xFF |
chips_SigmaTel dd 0x7680, chip_STAC9221 |
dd 0x7682, chip_STAC9221_A2 |
dd 0xFF |
align 16 |
;AnalogDevices |
chip_AD1986A db 'AD1986A',13,10,0 |
chip_AD198B db 'AD198B',13,10,0 |
;ATI |
chip_ATIR6XX db 'ATIR6XX',13,10,0 |
;Silicon Image |
chip_SI1392 db 'SI1392',13,10,0 |
;NVidia |
chip_MCP78 db 'MCP78',13,10,0 |
;Realtek |
chip_ALC262 db 'ALC262',13,10,0 |
chip_ALC268 db 'ALC268',13,10,0 |
chip_ALC269 db 'ALC269',13,10,0 |
chip_ALC272 db 'ALC272',13,10,0 |
chip_ALC662 db 'ALC662',13,10,0 |
chip_ALC663 db 'ALC663',13,10,0 |
chip_ALC883 db 'ALC883',13,10,0 |
chip_ALC887 db 'ALC887',13,10,0 |
chip_ALC888 db 'ALC888',13,10,0 |
chip_ALC889 db 'ALC889',13,10,0 |
;Sigmatel |
chip_STAC9221 db 'STAC9221',13,10,0 |
chip_STAC9221_A2 db 'STAC9221_A2',13,10,0 |
;VIA |
chip_VT1708B_1 db 'VT1708B_1',13,10,0 |
chip_VT17085_0 db 'VT17085_0',13,10,0 |
;Conexant |
chip_CX20549 db 'CX20549',13,10,0 |
chip_CX20561 db 'CX20561',13,10,0 |
;Qumranet |
chip_HDA_OUTPUT db 'HDA-OUTPUT',13,10,0 |
chip_HDA_DUPLEX db 'HDA-DUPLEX',13,10,0 |
/drivers/audio/intel_hda/CODEC_H.INC |
---|
0,0 → 1,648 |
; Universal Interface for Intel High Definition Audio Codec |
; nodes |
AC_NODE_ROOT equ 0x00 |
; function group types |
AC_GRP_AUDIO_FUNCTION equ 0x01 |
AC_GRP_MODEM_FUNCTION equ 0x02 |
; widget types |
AC_WID_AUD_OUT equ 0x0 ; Audio Out |
AC_WID_AUD_IN equ 0x1 ; Audio In |
AC_WID_AUD_MIX equ 0x2 ; Audio Mixer |
AC_WID_AUD_SEL equ 0x3 ; Audio Selector |
AC_WID_PIN equ 0x4 ; Pin Complex |
AC_WID_POWER equ 0x5 ; Power |
AC_WID_VOL_KNB equ 0x6 ; Volume Knob |
AC_WID_BEEP equ 0x7 ; Beep Generator |
AC_WID_VENDOR equ 0x0F ; Vendor specific |
; GET verbs |
AC_VERB_GET_STREAM_FORMAT equ 0x0A00 |
AC_VERB_GET_AMP_GAIN_MUTE equ 0x0B00 |
AC_VERB_GET_PROC_COEF equ 0x0C00 |
AC_VERB_GET_COEF_INDEX equ 0x0D00 |
AC_VERB_PARAMETERS equ 0x0F00 |
AC_VERB_GET_CONNECT_SEL equ 0x0F01 |
AC_VERB_GET_CONNECT_LIST equ 0x0F02 |
AC_VERB_GET_PROC_STATE equ 0x0F03 |
AC_VERB_GET_SDI_SELECT equ 0x0F04 |
AC_VERB_GET_POWER_STATE equ 0x0F05 |
AC_VERB_GET_CONV equ 0x0F06 |
AC_VERB_GET_PIN_WIDGET_CONTROL equ 0x0F07 |
AC_VERB_GET_UNSOLICITED_RESPONSE equ 0x0F08 |
AC_VERB_GET_PIN_SENSE equ 0x0F09 |
AC_VERB_GET_BEEP_CONTROL equ 0x0F0A |
AC_VERB_GET_EAPD_BTLENABLE equ 0x0F0C |
AC_VERB_GET_DIGI_CONVERT_1 equ 0x0F0D |
AC_VERB_GET_DIGI_CONVERT_2 equ 0x0F0E ; unused |
AC_VERB_GET_VOLUME_KNOB_CONTROL equ 0x0F0F |
; f10-f1a: GPIO |
AC_VERB_GET_GPIO_DATA equ 0x0F15 |
AC_VERB_GET_GPIO_MASK equ 0x0F16 |
AC_VERB_GET_GPIO_DIRECTION equ 0x0F17 |
AC_VERB_GET_GPIO_WAKE_MASK equ 0x0F18 |
AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK equ 0x0F19 |
AC_VERB_GET_GPIO_STICKY_MASK equ 0x0F1A |
AC_VERB_GET_CONFIG_DEFAULT equ 0x0F1C |
; f20: AFG/MFG |
AC_VERB_GET_SUBSYSTEM_ID equ 0x0F20 |
AC_VERB_GET_CVT_CHAN_COUNT equ 0x0F2D |
AC_VERB_GET_HDMI_DIP_SIZE equ 0x0F2E |
AC_VERB_GET_HDMI_ELDD equ 0x0F2F |
AC_VERB_GET_HDMI_DIP_INDEX equ 0x0F30 |
AC_VERB_GET_HDMI_DIP_DATA equ 0x0F31 |
AC_VERB_GET_HDMI_DIP_XMIT equ 0x0F32 |
AC_VERB_GET_HDMI_CP_CTRL equ 0x0F33 |
AC_VERB_GET_HDMI_CHAN_SLOT equ 0x0F34 |
; SET verbs |
AC_VERB_SET_STREAM_FORMAT equ 0x200 |
AC_VERB_SET_AMP_GAIN_MUTE equ 0x300 |
AC_VERB_SET_PROC_COEF equ 0x400 |
AC_VERB_SET_COEF_INDEX equ 0x500 |
AC_VERB_SET_CONNECT_SEL equ 0x701 |
AC_VERB_SET_PROC_STATE equ 0x703 |
AC_VERB_SET_SDI_SELECT equ 0x704 |
AC_VERB_SET_POWER_STATE equ 0x705 |
AC_VERB_SET_CHANNEL_STREAMID equ 0x706 |
AC_VERB_SET_PIN_WIDGET_CONTROL equ 0x707 |
AC_VERB_SET_UNSOLICITED_ENABLE equ 0x708 |
AC_VERB_SET_PIN_SENSE equ 0x709 |
AC_VERB_SET_BEEP_CONTROL equ 0x70A |
AC_VERB_SET_EAPD_BTLENABLE equ 0x70C |
AC_VERB_SET_DIGI_CONVERT_1 equ 0x70D |
AC_VERB_SET_DIGI_CONVERT_2 equ 0x70E |
AC_VERB_SET_VOLUME_KNOB_CONTROL equ 0x70F |
AC_VERB_SET_GPIO_DATA equ 0x715 |
AC_VERB_SET_GPIO_MASK equ 0x716 |
AC_VERB_SET_GPIO_DIRECTION equ 0x717 |
AC_VERB_SET_GPIO_WAKE_MASK equ 0x718 |
AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK equ 0x719 |
AC_VERB_SET_GPIO_STICKY_MASK equ 0x71A |
AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 equ 0x71C |
AC_VERB_SET_CONFIG_DEFAULT_BYTES_1 equ 0x71D |
AC_VERB_SET_CONFIG_DEFAULT_BYTES_2 equ 0x71E |
AC_VERB_SET_CONFIG_DEFAULT_BYTES_3 equ 0x71F |
AC_VERB_SET_EAPD equ 0x788 |
AC_VERB_SET_CODEC_RESET equ 0x7FF |
AC_VERB_SET_CVT_CHAN_COUNT equ 0x72D |
AC_VERB_SET_HDMI_DIP_INDEX equ 0x730 |
AC_VERB_SET_HDMI_DIP_DATA equ 0x731 |
AC_VERB_SET_HDMI_DIP_XMIT equ 0x732 |
AC_VERB_SET_HDMI_CP_CTRL equ 0x733 |
AC_VERB_SET_HDMI_CHAN_SLOT equ 0x734 |
; Parameter IDs |
AC_PAR_VENDOR_ID equ 0x00 |
AC_PAR_SUBSYSTEM_ID equ 0x01 |
AC_PAR_REV_ID equ 0x02 |
AC_PAR_NODE_COUNT equ 0x04 |
AC_PAR_FUNCTION_TYPE equ 0x05 |
AC_PAR_AUDIO_FG_CAP equ 0x08 |
AC_PAR_AUDIO_WIDGET_CAP equ 0x09 |
AC_PAR_PCM equ 0x0A |
AC_PAR_STREAM equ 0x0B |
AC_PAR_PIN_CAP equ 0x0C |
AC_PAR_AMP_IN_CAP equ 0x0D |
AC_PAR_CONNLIST_LEN equ 0x0E |
AC_PAR_POWER_STATE equ 0x0F |
AC_PAR_PROC_CAP equ 0x10 |
AC_PAR_GPIO_CAP equ 0x11 |
AC_PAR_AMP_OUT_CAP equ 0x12 |
AC_PAR_VOL_KNB_CAP equ 0x13 |
AC_PAR_HDMI_LPCM_CAP equ 0x20 |
; AC_VERB_PARAMETERS results (32bit) |
; Function Group Type |
AC_FGT_TYPE equ (0xFF shl 0) |
AC_FGT_TYPE_SHIFT equ 0 |
AC_FGT_UNSOL_CAP equ (1 shl 8) |
; Audio Function Group Capabilities |
AC_AFG_OUT_DELAY equ (0xF shl 0) |
AC_AFG_IN_DELAY equ (0xF shl 8) |
AC_AFG_BEEP_GEN equ (1 shl 16) |
; Audio Widget Capabilities |
AC_WCAP_STEREO equ (1 shl 0) ; stereo I/O |
AC_WCAP_IN_AMP equ (1 shl 1) ; AMP-in present |
AC_WCAP_OUT_AMP equ (1 shl 2) ; AMP-out present |
AC_WCAP_AMP_OVRD equ (1 shl 3) ; AMP-parameter override |
AC_WCAP_FORMAT_OVRD equ (1 shl 4) ; format override |
AC_WCAP_STRIPE equ (1 shl 5) ; stripe |
AC_WCAP_PROC_WID equ (1 shl 6) ; Proc Widget |
AC_WCAP_UNSOL_CAP equ (1 shl 7) ; Unsol capable |
AC_WCAP_CONN_LIST equ (1 shl 8) ; connection list |
AC_WCAP_DIGITAL equ (1 shl 9) ; digital I/O |
AC_WCAP_POWER equ (1 shl 10) ; power control |
AC_WCAP_LR_SWAP equ (1 shl 11) ; L/R swap |
AC_WCAP_CP_CAPS equ (1 shl 12) ; content protection |
AC_WCAP_CHAN_CNT_EXT equ (7 shl 13) ; channel count ext |
AC_WCAP_DELAY equ (0xF shl 16) |
AC_WCAP_DELAY_SHIFT equ 16 |
AC_WCAP_TYPE equ (0xF shl 20) |
AC_WCAP_TYPE_SHIFT equ 20 |
; supported PCM rates and bits |
AC_SUPPCM_RATES equ (0xFFF shl 0) |
AC_SUPPCM_BITS_8 equ (1 shl 16) |
AC_SUPPCM_BITS_16 equ (1 shl 17) |
AC_SUPPCM_BITS_20 equ (1 shl 18) |
AC_SUPPCM_BITS_24 equ (1 shl 19) |
AC_SUPPCM_BITS_32 equ (1 shl 20) |
; supported PCM stream format |
AC_SUPFMT_PCM equ (1 shl 0) |
AC_SUPFMT_FLOAT32 equ (1 shl 1) |
AC_SUPFMT_AC3 equ (1 shl 2) |
; GP I/O count |
AC_GPIO_IO_COUNT equ (0xFF shl 0) |
AC_GPIO_O_COUNT equ (0xFF shl 8) |
AC_GPIO_O_COUNT_SHIFT equ 8 |
AC_GPIO_I_COUNT equ (0xFF shl 16) |
AC_GPIO_I_COUNT_SHIFT equ 16 |
AC_GPIO_UNSOLICITED equ (1 shl 30) |
AC_GPIO_WAKE equ (1 shl 31) |
; Converter stream, channel |
AC_CONV_CHANNEL equ (0xF shl 0) |
AC_CONV_STREAM equ (0xF shl 4) |
AC_CONV_STREAM_SHIFT equ 4 |
; Input converter SDI select |
AC_SDI_SELECT equ (0xF shl 0) |
; Unsolicited response control |
AC_UNSOL_TAG equ (0x3F shl 0) |
AC_UNSOL_ENABLED equ (1 shl 7) |
AC_USRSP_EN equ AC_UNSOL_ENABLED |
; Unsolicited responses |
AC_UNSOL_RES_TAG equ (0x3F shl 26) |
AC_UNSOL_RES_TAG_SHIFT equ 26 |
AC_UNSOL_RES_SUBTAG equ (0x1F shl 21) |
AC_UNSOL_RES_SUBTAG_SHIFT equ 21 |
AC_UNSOL_RES_ELDV equ (1 shl 1) ; ELD Data valid (for HDMI) |
AC_UNSOL_RES_PD equ (1 shl 0) ; pinsense detect |
AC_UNSOL_RES_CP_STATE equ (1 shl 1) ; content protection |
AC_UNSOL_RES_CP_READY equ (1 shl 0) ; content protection |
; Pin widget capabilies |
AC_PINCAP_IMP_SENSE equ (1 shl 0) ; impedance sense capable |
AC_PINCAP_TRIG_REQ equ (1 shl 1) ; trigger required |
AC_PINCAP_PRES_DETECT equ (1 shl 2) ; presence detect capable |
AC_PINCAP_HP_DRV equ (1 shl 3) ; headphone drive capable |
AC_PINCAP_OUT equ (1 shl 4) ; output capable |
AC_PINCAP_IN equ (1 shl 5) ; input capable |
AC_PINCAP_BALANCE equ (1 shl 6) ; balanced I/O capable |
; Note: This LR_SWAP pincap is defined in the Realtek ALC883 specification, |
; but is marked reserved in the Intel HDA specification. |
AC_PINCAP_LR_SWAP equ (1 shl 7) ; L/R swap |
; Note: The same bit as LR_SWAP is newly defined as HDMI capability |
; in HD-audio specification |
AC_PINCAP_HDMI equ (1 shl 7) ; HDMI pin |
AC_PINCAP_DP equ (1 shl 24) ; DisplayPort pin, can |
; coexist with AC_PINCAP_HDMI |
AC_PINCAP_VREF equ (0x37 shl 8) |
AC_PINCAP_VREF_SHIFT equ 8 |
AC_PINCAP_EAPD equ (1 shl 16) ; EAPD capable |
AC_PINCAP_HBR equ (1 shl 27) ; High Bit Rate |
; Vref status (used in pin cap) |
AC_PINCAP_VREF_HIZ equ (1 shl 0) ; Hi-Z |
AC_PINCAP_VREF_50 equ (1 shl 1) ; 50% |
AC_PINCAP_VREF_GRD equ (1 shl 2) ; ground |
AC_PINCAP_VREF_80 equ (1 shl 4) ; 80% |
AC_PINCAP_VREF_100 equ (1 shl 5) ; 100% |
; Amplifier capabilities |
AC_AMPCAP_OFFSET equ (0x7F shl 0) ; 0dB offset |
AC_AMPCAP_OFFSET_SHIFT equ 0 |
AC_AMPCAP_NUM_STEPS equ (0x7F shl 8) ; number of steps |
AC_AMPCAP_NUM_STEPS_SHIFT equ 8 |
AC_AMPCAP_STEP_SIZE equ (0x7F shl 16) ; step size 0-32dB |
; in 0.25dB |
AC_AMPCAP_STEP_SIZE_SHIFT equ 16 |
AC_AMPCAP_MUTE equ (1 shl 31) ; mute capable |
AC_AMPCAP_MUTE_SHIFT equ 31 |
; Connection list |
AC_CLIST_LENGTH equ (0x7F shl 0) |
AC_CLIST_LONG equ (1 shl 7) |
; Supported power status |
AC_PWRST_D0SUP equ (1 shl 0) |
AC_PWRST_D1SUP equ (1 shl 1) |
AC_PWRST_D2SUP equ (1 shl 2) |
AC_PWRST_D3SUP equ (1 shl 3) |
AC_PWRST_D3COLDSUP equ (1 shl 4) |
AC_PWRST_S3D3COLDSUP equ (1 shl 29) |
AC_PWRST_CLKSTOP equ (1 shl 30) |
AC_PWRST_EPSS equ (1 shl 31) |
; Power state values |
AC_PWRST_SETTING equ (0xF shl 0) |
AC_PWRST_ACTUAL equ (0xF shl 4) |
AC_PWRST_ACTUAL_SHIFT equ 4 |
AC_PWRST_D0 equ 0x00 |
AC_PWRST_D1 equ 0x01 |
AC_PWRST_D2 equ 0x02 |
AC_PWRST_D3 equ 0x03 |
; Processing capabilies |
AC_PCAP_BENIGN equ (1 shl 0) |
AC_PCAP_NUM_COEF equ (0xFF shl 8) |
AC_PCAP_NUM_COEF_SHIFT equ 8 |
; Volume knobs capabilities |
AC_KNBCAP_NUM_STEPS equ (0x7F shl 0) |
AC_KNBCAP_DELTA equ (1 shl 7) |
; HDMI LPCM capabilities |
AC_LPCMCAP_48K_CP_CHNS equ (0x0F shl 0) ; max channels w/ CP-on |
AC_LPCMCAP_48K_NO_CHNS equ (0x0F shl 4) ; max channels w/o CP-on |
AC_LPCMCAP_48K_20BIT equ (1 shl 8) ; 20b bitrate supported |
AC_LPCMCAP_48K_24BIT equ (1 shl 9) ; 24b bitrate supported |
AC_LPCMCAP_96K_CP_CHNS equ (0x0F shl 10) ; max channels w/ CP-on |
AC_LPCMCAP_96K_NO_CHNS equ (0x0F shl 14) ; max channels w/o CP-on |
AC_LPCMCAP_96K_20BIT equ (1 shl 18) ; 20b bitrate supported |
AC_LPCMCAP_96K_24BIT equ (1 shl 19) ; 24b bitrate supported |
AC_LPCMCAP_192K_CP_CHNS equ (0x0F shl 20) ; max channels w/ CP-on |
AC_LPCMCAP_192K_NO_CHNS equ (0x0F shl 24) ; max channels w/o CP-on |
AC_LPCMCAP_192K_20BIT equ (1 shl 28) ; 20b bitrate supported |
AC_LPCMCAP_192K_24BIT equ (1 shl 29) ; 24b bitrate supported |
AC_LPCMCAP_44K equ (1 shl 30) ; 44.1kHz support |
AC_LPCMCAP_44K_MS equ (1 shl 31) ; 44.1kHz-multiplies support |
; Control Parameters |
; Amp gain/mute |
AC_AMP_MUTE equ (1 shl 7) |
AC_AMP_GAIN equ (0x7F) |
AC_AMP_GET_INDEX equ (0xF shl 0) |
AC_AMP_GET_LEFT equ (1 shl 13) |
AC_AMP_GET_RIGHT equ (0 shl 13) |
AC_AMP_GET_OUTPUT equ (1 shl 15) |
AC_AMP_GET_INPUT equ (0 shl 15) |
AC_AMP_SET_INDEX equ (0xF shl 8) |
AC_AMP_SET_INDEX_SHIFT equ 8 |
AC_AMP_SET_RIGHT equ (1 shl 12) |
AC_AMP_SET_LEFT equ (1 shl 13) |
AC_AMP_SET_INPUT equ (1 shl 14) |
AC_AMP_SET_OUTPUT equ (1 shl 15) |
; DIGITAL1 bits |
AC_DIG1_ENABLE equ (1 shl 0) |
AC_DIG1_V equ (1 shl 1) |
AC_DIG1_VCFG equ (1 shl 2) |
AC_DIG1_EMPHASIS equ (1 shl 3) |
AC_DIG1_COPYRIGHT equ (1 shl 4) |
AC_DIG1_NONAUDIO equ (1 shl 5) |
AC_DIG1_PROFESSIONAL equ (1 shl 6) |
AC_DIG1_LEVEL equ (1 shl 7) |
; DIGITAL2 bits |
AC_DIG2_CC equ (0x7F shl 0) |
; Pin widget control - 8bit |
AC_PINCTL_VREFEN equ (0x7 shl 0) |
AC_PINCTL_VREF_HIZ equ 0 ; Hi-Z |
AC_PINCTL_VREF_50 equ 1 ; 50% |
AC_PINCTL_VREF_GRD equ 2 ; ground |
AC_PINCTL_VREF_80 equ 4 ; 80% |
AC_PINCTL_VREF_100 equ 5 ; 100% |
AC_PINCTL_IN_EN equ (1 shl 5) |
AC_PINCTL_OUT_EN equ (1 shl 6) |
AC_PINCTL_HP_EN equ (1 shl 7) |
; Pin sense - 32bit |
AC_PINSENSE_IMPEDANCE_MASK equ (0x7FFFFFFF) |
AC_PINSENSE_PRESENCE equ (1 shl 31) |
AC_PINSENSE_ELDV equ (1 shl 30) ; ELD valid (HDMI) |
; EAPD/BTL enable - 32bit |
AC_EAPDBTL_BALANCED equ (1 shl 0) |
AC_EAPDBTL_EAPD equ (1 shl 1) |
AC_EAPDBTL_LR_SWAP equ (1 shl 2) |
; HDMI ELD data |
AC_ELDD_ELD_VALID equ (1 shl 31) |
AC_ELDD_ELD_DATA equ 0xFF |
; HDMI DIP size |
AC_DIPSIZE_ELD_BUF equ (1 shl 3) ; ELD buf size of packet size |
AC_DIPSIZE_PACK_IDX equ (0x07 shl 0) ; packet index |
; HDMI DIP index |
AC_DIPIDX_PACK_IDX equ (0x07 shl 5) ; packet idnex |
AC_DIPIDX_BYTE_IDX equ (0x1F shl 0) ; byte index |
; HDMI DIP xmit (transmit) control |
AC_DIPXMIT_MASK equ (0x3 shl 6) |
AC_DIPXMIT_DISABLE equ (0x0 shl 6) ; disable xmit |
AC_DIPXMIT_ONCE equ (0x2 shl 6) ; xmit once then disable |
AC_DIPXMIT_BEST equ (0x3 shl 6) ; best effort |
; HDMI content protection (CP) control |
AC_CPCTRL_CES equ (1 shl 9) ; current encryption state |
AC_CPCTRL_READY equ (1 shl 8) ; ready bit |
AC_CPCTRL_SUBTAG equ (0x1F shl 3) ; subtag for unsol-resp |
AC_CPCTRL_STATE equ (3 shl 0) ; current CP request state |
; Converter channel <-> HDMI slot mapping |
AC_CVTMAP_HDMI_SLOT equ (0xF shl 0) ; HDMI slot number |
AC_CVTMAP_CHAN equ (0xF shl 4) ; converter channel number |
; configuration default - 32bit |
AC_DEFCFG_SEQUENCE equ (0xF shl 0) |
AC_DEFCFG_DEF_ASSOC equ (0xF shl 4) |
AC_DEFCFG_ASSOC_SHIFT equ 4 |
AC_DEFCFG_MISC equ (0xF shl 8) |
AC_DEFCFG_MISC_SHIFT equ 8 |
AC_DEFCFG_MISC_NO_PRESENCE equ (1 shl 0) |
AC_DEFCFG_COLOR equ (0xF shl 12) |
AC_DEFCFG_COLOR_SHIFT equ 12 |
AC_DEFCFG_CONN_TYPE equ (0xF shl 16) |
AC_DEFCFG_CONN_TYPE_SHIFT equ 16 |
AC_DEFCFG_DEVICE equ (0xF shl 20) |
AC_DEFCFG_DEVICE_SHIFT equ 20 |
AC_DEFCFG_LOCATION equ (0x3F shl 24) |
AC_DEFCFG_LOCATION_SHIFT equ 24 |
AC_DEFCFG_PORT_CONN equ (0x3 shl 30) |
AC_DEFCFG_PORT_CONN_SHIFT equ 30 |
; device device types (0x0-0xf) |
AC_JACK_LINE_OUT equ 0x0 |
AC_JACK_SPEAKER equ 0x1 |
AC_JACK_HP_OUT equ 0x2 |
AC_JACK_CD equ 0x3 |
AC_JACK_SPDIF_OUT equ 0x4 |
AC_JACK_DIG_OTHER_OUT equ 0x5 |
AC_JACK_MODEM_LINE_SIDE equ 0x6 |
AC_JACK_MODEM_HAND_SIDE equ 0x7 |
AC_JACK_LINE_IN equ 0x8 |
AC_JACK_AUX equ 0x9 |
AC_JACK_MIC_IN equ 0xA |
AC_JACK_TELEPHONY equ 0xB |
AC_JACK_SPDIF_IN equ 0xC |
AC_JACK_DIG_OTHER_IN equ 0xD |
AC_JACK_OTHER equ 0xF |
; jack connection types (0x0-0xf) |
AC_JACK_CONN_UNKNOWN equ 0x0 |
AC_JACK_CONN_1_8 equ 0x1 |
AC_JACK_CONN_1_4 equ 0x2 |
AC_JACK_CONN_ATAPI equ 0x3 |
AC_JACK_CONN_RCA equ 0x4 |
AC_JACK_CONN_OPTICAL equ 0x5 |
AC_JACK_CONN_OTHER_DIGITAL equ 0x6 |
AC_JACK_CONN_OTHER_ANALOG equ 0x7 |
AC_JACK_CONN_DIN equ 0x8 |
AC_JACK_CONN_XLR equ 0x9 |
AC_JACK_CONN_RJ11 equ 0xA |
AC_JACK_CONN_COMB equ 0xB |
AC_JACK_CONN_OTHER equ 0xF |
; jack colors (0x0-0xf) |
AC_JACK_COLOR_UNKNOWN equ 0x0 |
AC_JACK_COLOR_BLACK equ 0x1 |
AC_JACK_COLOR_GREY equ 0x2 |
AC_JACK_COLOR_BLUE equ 0x3 |
AC_JACK_COLOR_GREEN equ 0x4 |
AC_JACK_COLOR_RED equ 0x5 |
AC_JACK_COLOR_ORANGE equ 0x6 |
AC_JACK_COLOR_YELLOW equ 0x7 |
AC_JACK_COLOR_PURPLE equ 0x8 |
AC_JACK_COLOR_PINK equ 0x9 |
AC_JACK_COLOR_WHITE equ 0xE |
AC_JACK_COLOR_OTHER equ 0xF |
; Jack location (0x0-0x3f) |
; common case |
AC_JACK_LOC_NONE equ 0 |
AC_JACK_LOC_REAR equ 1 |
AC_JACK_LOC_FRONT equ 2 |
AC_JACK_LOC_LEFT equ 3 |
AC_JACK_LOC_RIGHT equ 4 |
AC_JACK_LOC_TOP equ 5 |
AC_JACK_LOC_BOTTOM equ 6 |
; bits 4-5 |
AC_JACK_LOC_EXTERNAL equ 0x00 |
AC_JACK_LOC_INTERNAL equ 0x10 |
AC_JACK_LOC_SEPARATE equ 0x20 |
AC_JACK_LOC_OTHER equ 0x30 |
; external on primary chasis |
AC_JACK_LOC_REAR_PANEL equ 0x07 |
AC_JACK_LOC_DRIVE_BAY equ 0x08 |
; internal |
AC_JACK_LOC_RISER equ 0x17 |
AC_JACK_LOC_HDMI equ 0x18 |
AC_JACK_LOC_ATAPI equ 0x19 |
; others |
AC_JACK_LOC_MOBILE_IN equ 0x37 |
AC_JACK_LOC_MOBILE_OUT equ 0x38 |
; Port connectivity (0-3) |
AC_JACK_PORT_COMPLEX equ 0 |
AC_JACK_PORT_NONE equ 1 |
AC_JACK_PORT_FIXED equ 2 |
AC_JACK_PORT_BOTH equ 3 |
; max. connections to a widget |
HDA_MAX_CONNECTIONS equ 32 |
; max. codec address |
HDA_MAX_CODEC_ADDRESS equ 0x0f |
; max number of PCM devics per card |
HDA_MAX_PCMS equ 10 |
; Structures |
; direction |
HDA_INPUT equ 0x0 |
HDA_OUTPUT equ 0x1 |
struc HDA_VERB |
{ |
.nid dw ? |
.verb dd ? |
.param dd ? |
} |
virtual at 0 |
HDA_VERB HDA_VERB |
end virtual |
; the struct for codec->pin_configs |
struc HDA_PINCFG |
{ |
.nid dw ? |
.reserved dw ? ;Asper + for align purposes |
.cfg dd ? |
.sizeof: |
} |
virtual at 0 |
HDA_PINCFG HDA_PINCFG |
end virtual |
;Asper [ this part is from "hda_local.h" |
;(...) |
; amp value bits |
HDA_AMP_MUTE equ 0x80 |
HDA_AMP_UNMUTE equ 0x00 |
HDA_AMP_VOLMASK equ 0x7F |
;(...) |
; unsolicited event handler |
HDA_UNSOL_QUEUE_SIZE equ 64 |
;struc HDA_BUS_UNSOLICITED |
;{ |
; ; ring buffer |
; .queue: |
; times HDA_UNSOL_QUEUE_SIZE*2 dd ? |
; .rp dd ? |
; .wp dd ? |
; |
; ; workqueue |
; .work dd ?;struct work_struct work; |
; .bus dd ? ;struct hda_bus ;bus |
;}; |
; Helper for automatic ping configuration |
AUTO_PIN_MIC equ 0 |
AUTO_PIN_FRONT_MIC equ 1 |
AUTO_PIN_LINE equ 2 |
AUTO_PIN_FRONT_LINE equ 3 |
AUTO_PIN_CD equ 4 |
AUTO_PIN_AUX equ 5 |
AUTO_PIN_LAST equ 6 |
AUTO_PIN_LINE_OUT equ 0 |
AUTO_PIN_SPEAKER_OUT equ 1 |
AUTO_PIN_HP_OUT equ 2 |
;extern const char *auto_pin_cfg_labels[AUTO_PIN_LAST]; |
AUTO_CFG_MAX_OUTS equ 5 |
;struc AUTO_PIN_CFG |
;{ |
; .line_outs dd ? |
; ; sorted in the order of FrontSurrCLFESide |
; .line_out_pins times AUTO_CFG_MAX_OUTS dw ? |
; .speaker_outs dd ? |
; .speaker_pins times AUTO_CFG_MAX_OUTS dw ? |
; .hp_outs dd ? |
; .line_out_type dd ? ; AUTO_PIN_XXX_OUT |
; .hp_pins times AUTO_CFG_MAX_OUTS dw ? |
; .input_pins times AUTO_PIN_LAST dw ? |
; .dig_outs dd ? |
; .dig_out_pins times 2 dd ? |
; .dig_in_pin dw ? |
; .mono_out_pin dw ? |
; .dig_out_type times 2 dd ? ; HDA_PCM_TYPE_XXX |
; .dig_in_type dd ? ; HDA_PCM_TYPE_XXX |
;} |
;#define get_defcfg_connect(cfg) \ |
; ((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT) |
;#define get_defcfg_association(cfg) \ |
; ((cfg & AC_DEFCFG_DEF_ASSOC) >> AC_DEFCFG_ASSOC_SHIFT) |
;#define get_defcfg_location(cfg) \ |
; ((cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT) |
;#define get_defcfg_sequence(cfg) \ |
; (cfg & AC_DEFCFG_SEQUENCE) |
;#define get_defcfg_device(cfg) \ |
; ((cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT) |
; amp values |
;AMP_IN_MUTE(idx) (0x7080 | ((idx)<<8)) |
;AMP_IN_UNMUTE(idx) (0x7000 | ((idx)<<8)) |
AMP_OUT_MUTE equ 0xb080 |
AMP_OUT_UNMUTE equ 0xb000 |
AMP_OUT_ZERO equ 0xb000 |
; pinctl values |
PIN_IN equ (AC_PINCTL_IN_EN) |
PIN_VREFHIZ equ (AC_PINCTL_IN_EN or AC_PINCTL_VREF_HIZ) |
PIN_VREF50 equ (AC_PINCTL_IN_EN or AC_PINCTL_VREF_50) |
PIN_VREFGRD equ (AC_PINCTL_IN_EN or AC_PINCTL_VREF_GRD) |
PIN_VREF80 equ (AC_PINCTL_IN_EN or AC_PINCTL_VREF_80) |
PIN_VREF100 equ (AC_PINCTL_IN_EN or AC_PINCTL_VREF_100) |
PIN_OUT equ (AC_PINCTL_OUT_EN) |
PIN_HP equ (AC_PINCTL_OUT_EN or AC_PINCTL_HP_EN) |
PIN_HP_AMP equ (AC_PINCTL_HP_EN) |
; get widget capabilities |
;static inline u32 get_wcaps(struct hda_codec *codec, hda_nid_t nid) |
proc get_wcaps stdcall, nid:dword |
push ebx ecx edx |
xor eax, eax |
movzx ebx, [codec.start_nid] |
movzx ecx, [codec.num_nodes] |
mov edx, [nid] |
cmp edx, ebx |
jl .out |
add ecx, ebx |
cmp edx, ecx |
jge .out |
sub edx, ebx |
shl edx, 2 |
add edx, [codec.wcaps] |
mov eax, [edx] |
.out: |
pop edx ecx ebx |
ret |
endp |
; get the widget type from widget capability bits |
;#define get_wcaps_type(wcaps) (((wcaps) & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT) |
proc get_wcaps_type stdcall, wcaps:dword |
mov eax, [wcaps] |
and eax, AC_WCAP_TYPE |
shr eax, AC_WCAP_TYPE_SHIFT |
ret |
endp |
;static inline unsigned int get_wcaps_channels(u32 wcaps) |
proc get_wcaps_channels stdcall, wcaps:dword |
; chans = (wcaps & AC_WCAP_CHAN_CNT_EXT) >> 13; |
; chans = ((chans << 1) | 1) + 1; |
mov eax, [wcaps] |
and eax, AC_WCAP_CHAN_CNT_EXT |
shr eax, 13 |
shl eax, 1 |
or eax, 1 |
inc eax |
ret |
endp |
;Asper ] |
/drivers/audio/intel_hda/IMPORTS.INC |
---|
0,0 → 1,89 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2007. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
macro kernel_export [name]{ |
forward |
if used name |
if DEBUG |
display 'uses: ',`name,#13,#10 |
end if |
extrn name |
end if |
} |
; all exported kernel functions and data |
kernel_export \ |
RegService,\ |
GetService,\ |
ServiceHandler,\ |
AttachIntHandler,\ |
GetIntHandler,\ |
FpuSave,\ |
FpuRestore,\ |
ReservePortArea,\ |
Boot_Log,\ |
\ |
PciApi,\ |
PciRead32,\ |
PciRead16,\ |
PciRead8,\ |
PciWrite8,\ |
PciWrite16,\ |
PciWrite32,\ |
\ |
AllocPage,\ |
AllocPages,\ |
FreePage,\ |
MapPage,\ |
MapSpace,\ |
MapIoMem,\ |
GetPgAddr,\ |
CommitPages,\ |
ReleasePages,\ |
\ |
AllocKernelSpace,\ |
FreeKernelSpace,\ |
KernelAlloc,\ |
KernelFree,\ |
UserAlloc,\ |
UserFree,\ |
Kmalloc,\ |
Kfree,\ |
CreateRingBuffer,\ |
\ |
GetPid,\ |
CreateObject,\ |
DestroyObject,\ |
CreateEvent,\ |
RaiseEvent,\ |
WaitEvent,\ |
DestroyEvent,\ |
ClearEvent,\ |
\ |
LoadCursor,\ |
SelectHwCursor,\ |
SetHwCursor,\ |
HwCursorRestore,\ |
HwCursorCreate,\ |
\ |
SysMsgBoardStr,\ |
SysMsgBoardChar,\ |
GetCurrentTask,\ |
LoadFile,\ |
SendEvent,\ |
SetMouseData,\ |
Sleep,\ |
GetTimerTicks,\ |
\ |
strncat,\ |
strncpy,\ |
strncmp,\ |
strnlen,\ |
strchr,\ |
strrchr,\ |
\ |
LFBAddress |
/drivers/audio/intel_hda/PROC32.INC |
---|
0,0 → 1,268 |
; Macroinstructions for defining and calling procedures |
macro stdcall proc,[arg] ; directly call STDCALL procedure |
{ common |
if ~ arg eq |
reverse |
pushd arg |
common |
end if |
call proc } |
macro invoke proc,[arg] ; indirectly call STDCALL procedure |
{ common |
if ~ arg eq |
reverse |
pushd arg |
common |
end if |
call [proc] } |
macro ccall proc,[arg] ; directly call CDECL procedure |
{ common |
size@ccall = 0 |
if ~ arg eq |
reverse |
pushd arg |
size@ccall = size@ccall+4 |
common |
end if |
call proc |
if size@ccall |
add esp,size@ccall |
end if } |
macro cinvoke proc,[arg] ; indirectly call CDECL procedure |
{ common |
size@ccall = 0 |
if ~ arg eq |
reverse |
pushd arg |
size@ccall = size@ccall+4 |
common |
end if |
call [proc] |
if size@ccall |
add esp,size@ccall |
end if } |
macro proc [args] ; define procedure |
{ common |
match name params, args> |
\{ define@proc name,<params \} } |
prologue@proc equ prologuedef |
macro prologuedef procname,flag,parmbytes,localbytes,reglist |
{ if parmbytes | localbytes |
push ebp |
mov ebp,esp |
if localbytes |
sub esp,localbytes |
end if |
end if |
irps reg, reglist \{ push reg \} } |
epilogue@proc equ epiloguedef |
macro epiloguedef procname,flag,parmbytes,localbytes,reglist |
{ irps reg, reglist \{ reverse pop reg \} |
if parmbytes | localbytes |
leave |
end if |
if flag and 10000b |
retn |
else |
retn parmbytes |
end if } |
macro define@proc name,statement |
{ local params,flag,regs,parmbytes,localbytes,current |
if used name |
name: |
match =stdcall args, statement \{ params equ args |
flag = 11b \} |
match =stdcall, statement \{ params equ |
flag = 11b \} |
match =c args, statement \{ params equ args |
flag = 10001b \} |
match =c, statement \{ params equ |
flag = 10001b \} |
match =params, params \{ params equ statement |
flag = 0 \} |
virtual at ebp+8 |
match =uses reglist=,args, params \{ regs equ reglist |
params equ args \} |
match =regs =uses reglist, regs params \{ regs equ reglist |
params equ \} |
match =regs, regs \{ regs equ \} |
match =,args, params \{ defargs@proc args \} |
match =args@proc args, args@proc params \{ defargs@proc args \} |
parmbytes = $ - (ebp+8) |
end virtual |
name # % = parmbytes/4 |
all@vars equ |
current = 0 |
match prologue:reglist, prologue@proc:<regs> \{ prologue name,flag,parmbytes,localbytes,reglist \} |
macro locals |
\{ virtual at ebp-localbytes+current |
macro label . \\{ deflocal@proc .,:, \\} |
struc db [val] \\{ \common deflocal@proc .,db,val \\} |
struc dw [val] \\{ \common deflocal@proc .,dw,val \\} |
struc dp [val] \\{ \common deflocal@proc .,dp,val \\} |
struc dd [val] \\{ \common deflocal@proc .,dd,val \\} |
struc dt [val] \\{ \common deflocal@proc .,dt,val \\} |
struc dq [val] \\{ \common deflocal@proc .,dq,val \\} |
struc rb cnt \\{ deflocal@proc .,rb cnt, \\} |
struc rw cnt \\{ deflocal@proc .,rw cnt, \\} |
struc rp cnt \\{ deflocal@proc .,rp cnt, \\} |
struc rd cnt \\{ deflocal@proc .,rd cnt, \\} |
struc rt cnt \\{ deflocal@proc .,rt cnt, \\} |
struc rq cnt \\{ deflocal@proc .,rq cnt, \\} \} |
macro endl |
\{ purge label |
restruc db,dw,dp,dd,dt,dq |
restruc rb,rw,rp,rd,rt,rq |
restruc byte,word,dword,pword,tword,qword |
current = $-(ebp-localbytes) |
end virtual \} |
macro ret operand |
\{ match any, operand \\{ retn operand \\} |
match , operand \\{ match epilogue:reglist, epilogue@proc:<regs> |
\\\{ epilogue name,flag,parmbytes,localbytes,reglist \\\} \\} \} |
macro finish@proc \{ localbytes = (((current-1) shr 2)+1) shl 2 |
end if \} } |
macro defargs@proc [arg] |
{ common |
if ~ arg eq |
forward |
local ..arg,current@arg |
match argname:type, arg |
\{ current@arg equ argname |
label ..arg type |
argname equ ..arg |
if dqword eq type |
dd ?,?,?,? |
else if tbyte eq type |
dd ?,?,? |
else if qword eq type | pword eq type |
dd ?,? |
else |
dd ? |
end if \} |
match =current@arg,current@arg |
\{ current@arg equ arg |
arg equ ..arg |
..arg dd ? \} |
common |
args@proc equ current@arg |
forward |
restore current@arg |
common |
end if } |
macro deflocal@proc name,def,[val] |
{ common |
match vars, all@vars \{ all@vars equ all@vars, \} |
all@vars equ all@vars name |
forward |
local ..var,..tmp |
..var def val |
match =?, val \{ ..tmp equ \} |
match any =dup (=?), val \{ ..tmp equ \} |
match tmp : value, ..tmp : val |
\{ tmp: end virtual |
initlocal@proc ..var,def value |
virtual at tmp\} |
common |
match first rest, ..var, \{ name equ first \} } |
macro initlocal@proc name,def |
{ virtual at name |
def |
size@initlocal = $ - name |
end virtual |
position@initlocal = 0 |
while size@initlocal > position@initlocal |
virtual at name |
def |
if size@initlocal - position@initlocal < 2 |
current@initlocal = 1 |
load byte@initlocal byte from name+position@initlocal |
else if size@initlocal - position@initlocal < 4 |
current@initlocal = 2 |
load word@initlocal word from name+position@initlocal |
else |
current@initlocal = 4 |
load dword@initlocal dword from name+position@initlocal |
end if |
end virtual |
if current@initlocal = 1 |
mov byte [name+position@initlocal],byte@initlocal |
else if current@initlocal = 2 |
mov word [name+position@initlocal],word@initlocal |
else |
mov dword [name+position@initlocal],dword@initlocal |
end if |
position@initlocal = position@initlocal + current@initlocal |
end while } |
macro endp |
{ purge ret,locals,endl |
finish@proc |
purge finish@proc |
restore regs@proc |
match all,args@proc \{ restore all \} |
restore args@proc |
match all,all@vars \{ restore all \} } |
macro local [var] |
{ common |
locals |
forward done@local equ |
match varname[count]:vartype, var |
\{ match =BYTE, vartype \\{ varname rb count |
restore done@local \\} |
match =WORD, vartype \\{ varname rw count |
restore done@local \\} |
match =DWORD, vartype \\{ varname rd count |
restore done@local \\} |
match =PWORD, vartype \\{ varname rp count |
restore done@local \\} |
match =QWORD, vartype \\{ varname rq count |
restore done@local \\} |
match =TBYTE, vartype \\{ varname rt count |
restore done@local \\} |
match =DQWORD, vartype \\{ label varname dqword |
rq count+count |
restore done@local \\} |
match , done@local \\{ virtual |
varname vartype |
end virtual |
rb count*sizeof.\#vartype |
restore done@local \\} \} |
match :varname:vartype, done@local:var |
\{ match =BYTE, vartype \\{ varname db ? |
restore done@local \\} |
match =WORD, vartype \\{ varname dw ? |
restore done@local \\} |
match =DWORD, vartype \\{ varname dd ? |
restore done@local \\} |
match =PWORD, vartype \\{ varname dp ? |
restore done@local \\} |
match =QWORD, vartype \\{ varname dq ? |
restore done@local \\} |
match =TBYTE, vartype \\{ varname dt ? |
restore done@local \\} |
match =DQWORD, vartype \\{ label varname dqword |
dq ?,? |
restore done@local \\} |
match , done@local \\{ varname vartype |
restore done@local \\} \} |
match ,done@local |
\{ var |
restore done@local \} |
common |
endl } |
/drivers/audio/intel_hda/hda_generic.inc |
---|
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 |
/drivers/audio/intel_hda/intel_hda.asm |
---|
0,0 → 1,2924 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
format MS COFF |
DEBUG equ 1 |
FDEBUG equ 1 |
DEBUG_IRQ equ 0 |
USE_SINGLE_MODE equ 0 ; 1 = Single mode; 0 = Normal mode. |
TEST_VERSION_NUMBER equ '018b' |
;Asper+ [ |
SDO_TAG equ 1 ;Asper: Output stream tag id (any number except 0) |
SDO_IDX equ 4 ;Asper: Output stream index |
;According to "Intel® I/O Controller Hub 6 (ICH6) High Definition Audio / AC ’97 Programmer’s Reference Manual (PRM) May 2005 Document" |
;and "Intel® I/O Controller Hub 6 (ICH6) Family Datasheet" SDO0=4, |
;but according to "High Definition Audio Specification Revision 1.0a June 17, 2010" SDO0 depends on the number of SDIs. |
SDO_INT equ 1 shl SDO_IDX ;Asper: Output stream interrupt (must be power of 2) |
SDO_OFS equ 0x80+(SDO_IDX*0x20) ;Asper: Output stream offset |
;Asper+ ] |
include 'proc32.inc' |
include 'imports.inc' |
include 'codec_h.inc' |
CURRENT_API equ 0x0100 ;1.00 |
COMPATIBLE_API equ 0x0101 ;1.01 |
API_VERSION equ (COMPATIBLE_API shl 16) or CURRENT_API |
IRQ_REMAP equ 0 |
IRQ_LINE equ 0 |
CPU_FREQ equ 2600d |
; Vendors |
VID_INTEL equ 0x8086 |
VID_NVIDIA equ 0x10DE |
VID_ATI equ 0x1002 |
VID_AMD equ 0x1022 |
VID_VIA equ 0x1006 |
VID_SIS equ 0x1039 |
VID_ULI equ 0x10B9 |
VID_CREATIVE equ 0x1102 |
VID_TERA equ 0x6549 |
VID_RDC equ 0x17F3 |
VID_VMWARE equ 0x15AD |
; Devices |
; Intel |
CTRL_INTEL_SCH2 equ 0x080a |
CTRL_INTEL_HPT equ 0x0c0c |
CTRL_INTEL_CPT equ 0x1c20 |
CTRL_INTEL_PGB equ 0x1d20 |
CTRL_INTEL_PPT1 equ 0x1e20 |
CTRL_INTEL_82801F equ 0x2668 |
CTRL_INTEL_63XXESB equ 0x269a |
CTRL_INTEL_82801G equ 0x27d8 |
CTRL_INTEL_82801H equ 0x284b |
CTRL_INTEL_82801_UNK1 equ 0x2911 |
CTRL_INTEL_82801I equ 0x293e |
CTRL_INTEL_82801_UNK2 equ 0x293f |
CTRL_INTEL_82801JI equ 0x3a3e |
CTRL_INTEL_82801JD equ 0x3a6e |
CTRL_INTEL_PCH equ 0x3b56 |
CTRL_INTEL_PCH2 equ 0x3b57 |
CTRL_INTEL_SCH equ 0x811b |
CTRL_INTEL_LPT equ 0x8c20 |
; Nvidia |
CTRL_NVIDIA_MCP51 equ 0x026c |
CTRL_NVIDIA_MCP55 equ 0x0371 |
CTRL_NVIDIA_MCP61_1 equ 0x03e4 |
CTRL_NVIDIA_MCP61_2 equ 0x03f0 |
CTRL_NVIDIA_MCP65_1 equ 0x044a |
CTRL_NVIDIA_MCP65_2 equ 0x044b |
CTRL_NVIDIA_MCP67_1 equ 0x055c |
CTRL_NVIDIA_MCP67_2 equ 0x055d |
CTRL_NVIDIA_MCP78_1 equ 0x0774 |
CTRL_NVIDIA_MCP78_2 equ 0x0775 |
CTRL_NVIDIA_MCP78_3 equ 0x0776 |
CTRL_NVIDIA_MCP78_4 equ 0x0777 |
CTRL_NVIDIA_MCP73_1 equ 0x07fc |
CTRL_NVIDIA_MCP73_2 equ 0x07fd |
CTRL_NVIDIA_MCP79_1 equ 0x0ac0 |
CTRL_NVIDIA_MCP79_2 equ 0x0ac1 |
CTRL_NVIDIA_MCP79_3 equ 0x0ac2 |
CTRL_NVIDIA_MCP79_4 equ 0x0ac3 |
CTRL_NVIDIA_0BE2 equ 0x0be2 |
CTRL_NVIDIA_0BE3 equ 0x0be3 |
CTRL_NVIDIA_0BE4 equ 0x0be4 |
CTRL_NVIDIA_GT100 equ 0x0be5 |
CTRL_NVIDIA_GT106 equ 0x0be9 |
CTRL_NVIDIA_GT108 equ 0x0bea |
CTRL_NVIDIA_GT104 equ 0x0beb |
CTRL_NVIDIA_GT116 equ 0x0bee |
CTRL_NVIDIA_MCP89_1 equ 0x0d94 |
CTRL_NVIDIA_MCP89_2 equ 0x0d95 |
CTRL_NVIDIA_MCP89_3 equ 0x0d96 |
CTRL_NVIDIA_MCP89_4 equ 0x0d97 |
CTRL_NVIDIA_GF119 equ 0x0e08 |
CTRL_NVIDIA_GF110_1 equ 0x0e09 |
CTRL_NVIDIA_GF110_2 equ 0x0e0c |
; ATI |
CTRL_ATI_SB450 equ 0x437b |
CTRL_ATI_SB600 equ 0x4383 |
; ATI HDMI |
CTRL_ATI_RS600 equ 0x793b |
CTRL_ATI_RS690 equ 0x7919 |
CTRL_ATI_RS780 equ 0x960f |
CTRL_ATI_RS_UNK1 equ 0x970f |
CTRL_ATI_R600 equ 0xaa00 |
CTRL_ATI_RV630 equ 0xaa08 |
CTRL_ATI_RV610 equ 0xaa10 |
CTRL_ATI_RV670 equ 0xaa18 |
CTRL_ATI_RV635 equ 0xaa20 |
CTRL_ATI_RV620 equ 0xaa28 |
CTRL_ATI_RV770 equ 0xaa30 |
CTRL_ATI_RV730 equ 0xaa38 |
CTRL_ATI_RV710 equ 0xaa40 |
CTRL_ATI_RV740 equ 0xaa48 |
; AMD |
CTRL_AMD_HUDSON equ 0x780d |
; VIA |
CTRL_VIA_VT82XX equ 0x3288 |
CTRL_VIA_VT61XX equ 0x9140 |
CTRL_VIA_VT71XX equ 0x9170 |
; SiS |
CTRL_SIS_966 equ 0x7502 |
; ULI |
CTRL_ULI_M5461 equ 0x5461 |
; Creative |
CTRL_CREATIVE_CA0110_IBG equ 0x0009 |
CTRL_CREATIVE_SOUND_CORE3D_1 equ 0x0010 |
CTRL_CREATIVE_SOUND_CORE3D_2 equ 0x0012 |
; Teradici |
CTRL_TERA_UNK1 equ 0x1200 |
; RDC Semiconductor |
CTRL_RDC_R3010 equ 0x3010 |
;VMware |
CTRL_VMWARE_UNK1 equ 0x1977 |
; driver types |
AZX_DRIVER_ICH equ 0 |
AZX_DRIVER_PCH equ 1 |
AZX_DRIVER_SCH equ 2 |
AZX_DRIVER_ATI equ 3 |
AZX_DRIVER_ATIHDMI equ 4 |
AZX_DRIVER_VIA equ 5 |
AZX_DRIVER_SIS equ 6 |
AZX_DRIVER_ULI equ 7 |
AZX_DRIVER_NVIDIA equ 8 |
AZX_DRIVER_TERA equ 9 |
AZX_DRIVER_CTX equ 10 |
AZX_DRIVER_GENERIC equ 11 |
AZX_NUM_DRIVERS equ 12 |
; registers |
ICH6_REG_GCAP equ 0x00 |
ICH6_REG_VMIN equ 0x02 |
ICH6_REG_VMAJ equ 0x03 |
ICH6_REG_OUTPAY equ 0x04 |
ICH6_REG_INPAY equ 0x06 |
ICH6_REG_GCTL equ 0x08 |
ICH6_GCTL_RESET equ (1 shl 0) ; controller reset |
ICH6_GCTL_FCNTRL equ (1 shl 1) ; flush control |
ICH6_GCTL_UNSOL equ (1 shl 8) ; accept unsol. response enable |
ICH6_REG_WAKEEN equ 0x0c |
ICH6_REG_STATESTS equ 0x0e |
ICH6_REG_GSTS equ 0x10 |
ICH6_GSTS_FSTS equ (1 shl 1) ; flush status |
ICH6_REG_INTCTL equ 0x20 |
ICH6_REG_INTSTS equ 0x24 |
ICH6_REG_WALLCLK equ 0x30 ; 24Mhz source |
ICH6_REG_OLD_SSYNC equ 0x34 ; SSYNC for old ICH |
ICH6_REG_SSYNC equ 0x38 |
ICH6_REG_CORBLBASE equ 0x40 |
ICH6_REG_CORBUBASE equ 0x44 |
ICH6_REG_CORBWP equ 0x48 |
ICH6_REG_CORBRP equ 0x4A |
ICH6_CORBRP_RST equ (1 shl 15) ; read pointer reset |
ICH6_REG_CORBCTL equ 0x4c |
ICH6_CORBCTL_RUN equ (1 shl 1) ; enable DMA |
ICH6_CORBCTL_CMEIE equ (1 shl 0) ; enable memory error irq |
ICH6_REG_CORBSTS equ 0x4d |
ICH6_CORBSTS_CMEI equ (1 shl 0) ; memory error indication |
ICH6_REG_CORBSIZE equ 0x4e |
ICH6_REG_RIRBLBASE equ 0x50 |
ICH6_REG_RIRBUBASE equ 0x54 |
ICH6_REG_RIRBWP equ 0x58 |
ICH6_RIRBWP_RST equ (1 shl 15) ; write pointer reset |
ICH6_REG_RINTCNT equ 0x5a |
ICH6_REG_RIRBCTL equ 0x5c |
ICH6_RBCTL_IRQ_EN equ (1 shl 0) ; enable IRQ |
ICH6_RBCTL_DMA_EN equ (1 shl 1) ; enable DMA |
ICH6_RBCTL_OVERRUN_EN equ (1 shl 2) ; enable overrun irq |
ICH6_REG_RIRBSTS equ 0x5d |
ICH6_RBSTS_IRQ equ (1 shl 0) ; response irq |
ICH6_RBSTS_OVERRUN equ (1 shl 2) ; overrun irq |
ICH6_REG_RIRBSIZE equ 0x5e |
ICH6_REG_IC equ 0x60 |
ICH6_REG_IR equ 0x64 |
ICH6_REG_IRS equ 0x68 |
ICH6_IRS_VALID equ 2 |
ICH6_IRS_BUSY equ 1 |
ICH6_REG_DPLBASE equ 0x70 |
ICH6_REG_DPUBASE equ 0x74 |
ICH6_DPLBASE_ENABLE equ 1 ; Enable position buffer |
; SD offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ |
SDI0_SD_OFFSET equ 0x80 |
SDI1_SD_OFFSET equ 0xA0 |
SDI2_SD_OFFSET equ 0xC0 |
SDI3_SD_OFFSET equ 0xE0 |
SDO0_SD_OFFSET equ 0x100 |
SDO1_SD_OFFSET equ 0x120 |
SDO2_SD_OFFSET equ 0X140 |
SDO3_SD_OFFSET equ 0x160 |
; stream register offsets from stream base |
ICH6_REG_SD_CTL equ 0x00 |
ICH6_REG_SD_STS equ 0x03 |
ICH6_REG_SD_LPIB equ 0x04 |
ICH6_REG_SD_CBL equ 0x08 |
ICH6_REG_SD_LVI equ 0x0c |
ICH6_REG_SD_FIFOW equ 0x0e |
ICH6_REG_SD_FIFOSIZE equ 0x10 |
ICH6_REG_SD_FORMAT equ 0x12 |
ICH6_REG_SD_BDLPL equ 0x18 |
ICH6_REG_SD_BDLPU equ 0x1c |
; PCI space |
ICH6_PCIREG_TCSEL equ 0x44 |
; other constants |
ICH6_RIRB_EX_UNSOL_EV equ (1 shl 4) |
; max number of SDs |
MAX_ICH6_DEV equ 8 |
; max number of fragments - we may use more if allocating more pages for BDL |
AZX_MAX_FRAG equ (4096 / (MAX_ICH6_DEV * 16)) |
; max buffer size - no h/w limit, you can increase as you like |
AZX_MAX_BUF_SIZE equ (1024*1024*1024) |
; max number of PCM devices per card |
AZX_MAX_PCMS equ 8 |
; RIRB int mask: overrun[2], response[0] |
RIRB_INT_RESPONSE equ 0x01 |
RIRB_INT_OVERRUN equ 0x04 |
RIRB_INT_MASK equ 0x05 |
; STATESTS int mask: SD2,SD1,SD0 |
STATESTS_INT_MASK equ 0x07 |
AZX_MAX_CODECS equ 4 |
; SD_CTL bits |
SD_CTL_STREAM_RESET equ 0x01 ; stream reset bit |
SD_CTL_DMA_START equ 0x02 ; stream DMA start bit |
SD_CTL_STREAM_TAG_MASK equ (0xf shl 20) |
SD_CTL_STREAM_TAG_SHIFT equ 20 |
; SD_CTL and SD_STS |
SD_INT_DESC_ERR equ 0x10 ; descriptor error interrupt |
SD_INT_FIFO_ERR equ 0x08 ; FIFO error interrupt |
SD_INT_COMPLETE equ 0x04 ; completion interrupt |
SD_INT_MASK equ (SD_INT_DESC_ERR or SD_INT_FIFO_ERR or SD_INT_COMPLETE) |
; SD_STS |
SD_STS_FIFO_READY equ 0x20 ; FIFO ready |
; INTCTL and INTSTS |
ICH6_INT_ALL_STREAM equ 0xff ; all stream interrupts |
ICH6_INT_CTRL_EN equ 0x40000000 ; controller interrupt enable bit |
ICH6_INT_GLOBAL_EN equ 0x80000000 ; global interrupt enable bit |
; GCTL reset bit |
ICH6_GCTL_RESET equ 1 |
; CORB/RIRB control, read/write pointer |
ICH6_RBCTL_DMA_EN equ 0x02 ; enable DMA |
ICH6_RBCTL_IRQ_EN equ 0x01 ; enable IRQ |
ICH6_RBRWP_CLR equ 0x8000 ; read/write pointer clear |
; below are so far hardcoded - should read registers in future |
ICH6_MAX_CORB_ENTRIES equ 256 |
ICH6_MAX_RIRB_ENTRIES equ 256 |
; position fix mode |
POS_FIX_AUTO equ 0 |
POS_FIX_LPIB equ 1 |
POS_FIX_POSBUF equ 2 |
POS_FIX_VIACOMBO equ 4 |
POS_FIX_COMBO equ 8 |
; Defines for ATI HD Audio support in SB450 south bridge |
ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR equ 0x42 |
ATI_SB450_HDAUDIO_ENABLE_SNOOP equ 0x02 |
; Defines for Nvidia HDA support |
NVIDIA_HDA_TRANSREG_ADDR equ 0x4e |
NVIDIA_HDA_ENABLE_COHBITS equ 0x0f |
NVIDIA_HDA_ISTRM_COH equ 0x4d |
NVIDIA_HDA_OSTRM_COH equ 0x4c |
NVIDIA_HDA_ENABLE_COHBIT equ 0x01 |
; Defines for Intel SCH HDA snoop control |
INTEL_SCH_HDA_DEVC equ 0x78 |
INTEL_SCH_HDA_DEVC_NOSNOOP equ (0x1 shl 11) |
; Define IN stream 0 FIFO size offset in VIA controller |
VIA_IN_STREAM0_FIFO_SIZE_OFFSET equ 0x90 |
; Define VIA HD Audio Device ID |
VIA_HDAC_DEVICE_ID equ 0x3288 |
; HD Audio class code |
PCI_CLASS_MULTIMEDIA_HD_AUDIO equ 0x0403 |
SRV_GETVERSION equ 0 |
DEV_PLAY equ 1 |
DEV_STOP equ 2 |
DEV_CALLBACK equ 3 |
DEV_SET_BUFF equ 4 |
DEV_NOTIFY equ 5 |
DEV_SET_MASTERVOL equ 6 |
DEV_GET_MASTERVOL equ 7 |
DEV_GET_INFO equ 8 |
DEV_GET_POS equ 9 |
DEV_SET_CHANNEL_VOLUME equ 10 |
DEV_GET_CHANNEL_VOLUME equ 11 |
;Asper: Non standard system service. For the tests only! [ |
DEV_EXEC_CODEC_CMD equ 100 |
;Asper: Non standard system service. For the tests only! ] |
struc AC_CNTRL ;AC controller base class |
{ .bus dd ? |
.devfn dd ? |
.vendor dw ? |
.dev_id dw ? |
.pci_cmd dd ? |
.pci_stat dd ? |
.ctrl_io_base dd ? |
.ctrl_mem_base dd ? |
.cfg_reg dd ? |
.int_line dd ? |
.vendor_ids dd ? ;vendor id string |
.ctrl_ids dd ? ;hub id string |
.buffer dd ? |
.notify_pos dd ? |
.notify_task dd ? |
.lvi_reg dd ? |
.civ_val dd 1 |
.user_callback dd ? |
.ctrl_read8 dd ? |
.ctrl_read16 dd ? |
.ctrl_read32 dd ? |
.ctrl_write8 dd ? |
.ctrl_write16 dd ? |
.ctrl_write32 dd ? |
;Asper+ [ |
.codec_mask dd ? |
.rb dd ? |
.rirb_rp dw 0 |
.rirb_wp dw 0 |
.corb_rp dw 0 |
.corb_wp dw 0 |
.rirb_cmd dd 0 |
.rirb_res dd 0 |
.rirb_error dd 0 |
.response_reset dd 0 |
.polling_mode db 0 |
.poll_count db 0 |
.posbuf dd ? |
.start_wallclk dd ? ; start + minimum wallclk |
.period_wallclk dd ? ; wallclk for period |
.position_fix db ? |
;Asper+ ] |
} |
struc CODEC ;Audio Chip base class |
{ |
;Asper+ [ |
.addr dd ? ; codec slot index (codec address) |
.afg dd ? ; AFG node id |
.mfg dd ? ; MFG node id |
.function_id dd ? |
.subsystem_id dd ? |
.revision_id dd ? |
.chip_id dw ? |
.vendor_id dw ? |
; widget capabilities cache |
.num_nodes dw ? |
.start_nid dw ? |
.wcaps dd ? |
.init_pins dd ? ; initial (BIOS) pin configurations |
.num_pins dd ? ;Asper + : word is enough, but for align... |
.beeper_nid dw ? |
.pad dw ? |
;Asper+ ] |
.ac_vendor_ids dd ? ;ac vendor id string |
.chip_ids dd ? ;chip model string |
} |
struc CTRL_INFO |
{ .pci_cmd dd ? |
.irq dd ? |
.glob_cntrl dd ? |
.glob_sta dd ? |
.codec_io_base dd ? |
.ctrl_io_base dd ? |
.codec_mem_base dd ? |
.ctrl_mem_base dd ? |
.codec_id dd ? |
} |
struc IOCTL |
{ .handle dd ? |
.io_code dd ? |
.input dd ? |
.inp_size dd ? |
.output dd ? |
.out_size dd ? |
} |
virtual at 0 |
IOCTL IOCTL |
end virtual |
EVENT_NOTIFY equ 0x00000200 |
public START |
public service_proc |
public version |
section '.flat' code readable align 16 |
proc START stdcall, state:dword |
cmp [state], 1 |
jne .stop |
if DEBUG |
mov esi, msgTV |
call SysMsgBoardStr |
mov esi, msgInit |
call SysMsgBoardStr |
end if |
call detect_controller |
test eax, eax |
jz .fail |
mov esi,[ctrl.vendor_ids] |
call SysMsgBoardStr |
mov esi, [ctrl.ctrl_ids] |
call SysMsgBoardStr |
call init_controller |
test eax, eax |
jz .fail |
;Asper This part is from "azx_create" proc. [ |
;(...) |
mov [ctrl.position_fix], POS_FIX_LPIB |
cmp [driver_type], AZX_DRIVER_VIA |
je .set_via_patch |
cmp [driver_type], AZX_DRIVER_ATI |
jne .no_via_patch |
.set_via_patch: |
or [ctrl.position_fix], POS_FIX_VIACOMBO |
.no_via_patch: |
; codec detection |
mov eax, [ctrl.codec_mask] |
test eax, eax |
jnz @f |
if DEBUG |
mov esi, msgNoCodecsFound |
jmp .fail_msg |
else |
jmp .fail |
end if |
@@: |
;Asper ] |
mov esi, msgPrimBuff |
call SysMsgBoardStr |
call create_primary_buff |
mov esi, msgDone |
call SysMsgBoardStr |
if IRQ_REMAP |
pushf |
cli |
mov ebx, [ctrl.int_line] |
in al, 0xA1 |
mov ah, al |
in al, 0x21 |
test ebx, ebx |
jz .skip |
bts ax, bx ;mask old line |
.skip |
bts ax, IRQ_LINE ;mask new ine |
out 0x21, al |
mov al, ah |
out 0xA1, al |
;remap IRQ |
stdcall PciWrite8, 0, 0xF8, 0x61, IRQ_LINE |
mov dx, 0x4d0 ;8259 ELCR1 |
in al, dx |
bts ax, IRQ_LINE |
out dx, al ;set level-triggered mode |
mov [ctrl.int_line], IRQ_LINE |
popf |
mov esi, msgRemap |
call SysMsgBoardStr |
end if |
mov ebx, [ctrl.int_line] |
stdcall AttachIntHandler, ebx, hda_irq, dword 0 |
;Asper This part is from "azx_probe" proc. [ |
call azx_codec_create |
cmp eax, 0 |
jl .fail |
call azx_codec_configure |
cmp eax, 0 |
jl .fail |
;] Asper |
; create PCM streams |
;Asper+ [ |
mov eax, [spec.dac_node] |
if DEBUG |
push eax esi |
mov esi, msgVal |
call SysMsgBoardStr |
stdcall fdword2str, 3 |
call SysMsgBoardStr |
pop esi eax |
end if |
test eax, eax |
jz .fail |
mov ebx, [spec.dac_node+4] |
if DEBUG |
push eax esi |
mov esi, msgVal |
call SysMsgBoardStr |
mov eax, [spec.dac_node+4] |
stdcall fdword2str, 3 |
call SysMsgBoardStr |
pop esi eax |
end if |
test ebx, ebx |
jz @f |
cmp eax, ebx |
je @f |
stdcall hda_codec_setup_stream, ebx, SDO_TAG, 0, 0x11 ; Left & Right channels (Front panel) |
@@: |
stdcall hda_codec_setup_stream, eax, SDO_TAG, 0, 0x11 ; Left & Right channels (Back panel) |
;Asper+ ] |
if USE_SINGLE_MODE |
mov esi, msgSingleMode |
call SysMsgBoardStr |
else |
mov esi, msgNormalMode |
call SysMsgBoardStr |
end if |
.reg: |
stdcall RegService, sz_sound_srv, service_proc |
ret |
.fail: |
if DEBUG |
mov esi, msgFail |
call SysMsgBoardStr |
end if |
xor eax, eax |
ret |
.fail_msg: |
call SysMsgBoardStr |
xor eax, eax |
ret |
.stop: |
call stop |
xor eax, eax |
ret |
endp |
handle equ IOCTL.handle |
io_code equ IOCTL.io_code |
input equ IOCTL.input |
inp_size equ IOCTL.inp_size |
output equ IOCTL.output |
out_size equ IOCTL.out_size |
align 4 |
proc service_proc stdcall, ioctl:dword |
mov edi, [ioctl] |
mov eax, [edi+io_code] |
cmp eax, SRV_GETVERSION |
jne @F |
mov eax, [edi+output] |
cmp [edi+out_size], 4 |
jne .fail |
mov [eax], dword API_VERSION |
xor eax, eax |
ret |
@@: |
cmp eax, DEV_PLAY |
jne @F |
if DEBUG |
mov esi, msgPlay |
call SysMsgBoardStr |
end if |
call play |
xor eax, eax |
ret |
@@: |
cmp eax, DEV_STOP |
jne @F |
if DEBUG |
mov esi, msgStop |
call SysMsgBoardStr |
end if |
call stop |
xor eax, eax |
ret |
@@: |
cmp eax, DEV_CALLBACK |
jne @F |
mov ebx, [edi+input] |
stdcall set_callback, [ebx] |
xor eax, eax |
ret |
@@: |
cmp eax, DEV_SET_MASTERVOL |
jne @F |
mov eax, [edi+input] |
mov eax, [eax] |
call set_master_vol |
xor eax, eax |
ret |
@@: |
cmp eax, DEV_GET_MASTERVOL |
jne @F |
mov ebx, [edi+output] |
stdcall get_master_vol, ebx |
xor eax, eax |
ret |
;@@: |
; cmp eax, DEV_GET_INFO |
; jne @F |
; mov ebx, [edi+output] |
; stdcall get_dev_info, ebx |
; xor eax, eax |
; ret |
@@: |
cmp eax, DEV_GET_POS |
jne @F |
stdcall azx_get_position |
shr eax, 2 |
mov ebx, [edi+output] |
mov [ebx], eax |
xor eax, eax |
ret |
@@: |
; cmp eax, DEV_SET_CHANNEL_VOLUME |
; jne @F |
; if DEBUG |
; mov esi, msgSetChannelVolume |
; call SysMsgBoardStr |
; end if |
; mov ebx, [edi+input] |
; mov cl, byte [ebx] ; cl=channel |
; mov eax, dword [ebx+1] ; eax=volume in Db |
; if DEBUG |
; push eax esi |
; mov esi, msgYAHOO1 |
; call SysMsgBoardStr |
; stdcall fdword2str, 1 |
; call SysMsgBoardStr |
; mov esi, strSemicolon |
; call SysMsgBoardStr |
; movzx eax, cl |
; stdcall fdword2str, 3 |
; call SysMsgBoardStr |
; pop esi eax |
; end if |
; |
; call set_channel_volume |
; xor eax, eax |
; ret |
;@@: |
; cmp eax, DEV_GET_CHANNEL_VOLUME |
; jne @F |
; mov cl, byte [edi+input] ; cl=channel |
; call get_channel_volume |
; mov ebx, [edi+output] |
; mov [ebx], eax |
; xor eax, eax |
; ret |
;@@: |
;Asper: Non standard system service. For the tests only! [ |
@@: |
cmp eax, DEV_EXEC_CODEC_CMD |
jne @f |
mov eax, [edi+input] |
mov eax, [eax] |
stdcall codec_exec_verb, eax |
xor eax, eax |
ret |
@@: |
;Asper: Non standard system service. For the tests only! ] |
.fail: |
or eax, -1 |
ret |
endp |
restore handle |
restore io_code |
restore input |
restore inp_size |
restore output |
restore out_size |
align 4 |
proc hda_irq ;+ |
if DEBUG_IRQ |
push eax esi |
;mov esi, msgIRQ |
;call SysMsgBoardStr |
call GetTimerTicks |
stdcall fdword2str, 2 |
call SysMsgBoardStr |
pop esi eax |
end if |
mov edx, ICH6_REG_INTSTS |
call azx_readl |
test eax, eax |
jnz @f |
ret |
@@: |
mov ebx, eax ; status |
mov eax, SDO_INT |
test ebx, eax |
jz @f |
mov edx, ICH6_REG_SD_STS + SDO_OFS |
call azx_readb |
mov bl, al |
mov al, SD_INT_MASK |
mov edx, ICH6_REG_SD_STS + SDO_OFS |
call azx_writeb |
test bl, SD_INT_COMPLETE |
jz @f |
mov eax, [ctrl.civ_val] |
inc eax |
and eax, 4-1 ;2-1 |
mov [ctrl.civ_val], eax |
mov ebx, dword [buff_list+eax*4] |
cmp [ctrl.user_callback], 0 |
je @f |
stdcall [ctrl.user_callback], ebx |
@@: |
; clear rirb int |
mov edx, ICH6_REG_RIRBSTS |
call azx_readb |
test al, RIRB_INT_MASK |
jz .l1 |
test al, RIRB_INT_RESPONSE |
jz .l2 |
cmp byte [driver_type], AZX_DRIVER_CTX |
jne @f |
mov eax, 80 ; wait 80 us |
call StallExec |
@@: |
call azx_update_rirb |
.l2: |
mov al, RIRB_INT_MASK |
mov edx, ICH6_REG_RIRBSTS |
call azx_writeb |
.l1: |
;if 0 |
; clear state status int |
mov edx, ICH6_REG_STATESTS |
call azx_readb |
test al, 0x04 |
jz @f |
mov al, 0x04 |
mov edx, ICH6_REG_STATESTS |
call azx_writeb |
@@: |
;end if |
or eax, 1 |
ret |
endp |
align 4 |
proc create_primary_buff |
stdcall KernelAlloc, 4096 |
mov [ctrl.posbuf], eax |
stdcall KernelAlloc, 0x10000 ;0x8000 |
mov [ctrl.buffer], eax |
mov edi, eax |
mov ecx, 0x10000/4 ;0x8000/4 |
xor eax, eax |
cld |
rep stosd |
stdcall KernelAlloc, 4096 |
mov [pcmout_bdl], eax |
mov edi, eax |
mov ecx, 4096/4 |
xor eax, eax |
cld |
rep stosd |
; reset BDL address |
xor eax, eax |
mov edx, ICH6_REG_SD_BDLPL + SDO_OFS |
call azx_writel |
xor eax, eax |
mov edx, ICH6_REG_SD_BDLPU + SDO_OFS |
call azx_writel |
; program the initial BDL entries |
mov eax, [ctrl.buffer] |
mov ebx, eax |
call GetPgAddr |
and ebx, 0xFFF |
add eax, ebx |
mov ebx, 0x4000 ;buffer size |
mov ecx, 8 ;number of periods |
mov edi, [pcmout_bdl] ;pcmout_bdl |
.next_period: |
push eax ecx |
mov ecx, 4 ;2 ;number of bdl in a period |
.next_bdl: |
; program the address field of the BDL entry |
mov dword [edi], eax |
mov dword [edi+4], 0 |
; program the size field of the BDL entry |
mov dword [edi+8], ebx |
; program the IOC to enable interrupt when buffer completes |
mov dword [edi+12], 0x01 |
add eax, ebx |
add edi, 16 |
dec ecx |
jnz .next_bdl |
pop ecx eax |
dec ecx |
jnz .next_period |
mov edi, buff_list |
mov eax, [ctrl.buffer] |
mov ecx, 4 ;2 |
@@: |
mov [edi], eax |
mov [edi+8], eax |
mov [edi+16], eax |
mov [edi+24], eax |
mov [edi+32], eax |
mov [edi+40], eax |
mov [edi+48], eax |
mov [edi+56], eax |
add eax, ebx |
add edi, 4 |
loop @B |
; wallclk has 24Mhz clock source |
mov [ctrl.period_wallclk], ((0x4000 * 24000) / 48000) * 1000 |
;-call azx_stream_reset |
call azx_setup_controller |
ret |
endp |
align 4 |
proc detect_controller |
locals |
last_bus dd ? |
bus dd ? |
devfn dd ? |
endl |
xor eax, eax |
mov [bus], eax |
inc eax |
call PciApi |
cmp eax, -1 |
je .err |
mov [last_bus], eax |
.next_bus: |
and [devfn], 0 |
.next_dev: |
stdcall PciRead32, [bus], [devfn], dword 0 |
test eax, eax |
jz .next |
cmp eax, -1 |
je .next |
mov edi, devices |
@@: |
mov ebx, [edi] |
test ebx, ebx |
jz .next |
cmp eax, ebx |
je .found |
add edi, 12 |
jmp @B |
.next: |
inc [devfn] |
cmp [devfn], 256 |
jb .next_dev |
mov eax, [bus] |
inc eax |
mov [bus], eax |
cmp eax, [last_bus] |
jna .next_bus |
xor eax, eax |
ret |
.found: |
mov ebx, [bus] |
mov [ctrl.bus], ebx |
mov ecx, [devfn] |
mov [ctrl.devfn], ecx |
mov edx, eax |
and edx, 0xFFFF |
mov [ctrl.vendor], dx |
shr eax, 16 |
mov [ctrl.dev_id], ax |
mov ebx, [edi+4] |
mov [ctrl.ctrl_ids], ebx |
cmp edx, VID_INTEL |
jne @F |
mov [ctrl.vendor_ids], msg_Intel |
jmp .ok |
@@: |
cmp edx, VID_NVIDIA |
jne @F |
mov [ctrl.vendor_ids], msg_NVidia |
jmp .ok |
@@: |
cmp edx, VID_ATI |
jne @F |
cmp eax, 0x4383 |
jg .ati_hdmi |
mov [ctrl.vendor_ids], msg_ATI |
jmp .ok |
.ati_hdmi: |
mov [ctrl.vendor_ids], msg_ATI_HDMI |
jmp .ok |
@@: |
cmp edx, VID_AMD |
jne @F |
mov [ctrl.vendor_ids], msg_AMD |
jmp .ok |
@@: |
cmp edx, VID_VIA |
jne @F |
mov [ctrl.vendor_ids], msg_VIA |
jmp .ok |
@@: |
cmp edx, VID_SIS |
jne @F |
mov [ctrl.vendor_ids], msg_SIS |
jmp .ok |
@@: |
cmp edx, VID_ULI |
jne @F |
mov [ctrl.vendor_ids], msg_ULI |
jmp .ok |
@@: |
cmp edx, VID_TERA |
jne @F |
mov [ctrl.vendor_ids], msg_TERA |
jmp .ok |
@@: |
cmp edx, VID_CREATIVE |
jne @F |
mov [ctrl.vendor_ids], msg_CREATIVE |
jmp .ok |
@@: |
cmp edx, VID_RDC |
jne @F |
mov [ctrl.vendor_ids], msg_RDC |
jmp .ok |
@@: |
cmp edx, VID_VMWARE |
jne @F |
mov [ctrl.vendor_ids], msg_VMWARE |
jmp .ok |
@@: |
.err: |
xor eax, eax |
mov [ctrl.vendor_ids], eax ;something wrong ? |
mov [driver_type], -1 |
ret |
.ok: |
mov ebx, [edi+8] |
mov [driver_type], ebx |
ret |
endp |
align 4 |
proc init_controller |
stdcall PciRead32, [ctrl.bus], [ctrl.devfn], dword 4 |
test eax, 0x4 ; Test Master bit |
jnz @f |
or eax, 0x4 ; Set Master bit |
stdcall PciWrite32, [ctrl.bus], [ctrl.devfn], dword 4, eax |
stdcall PciRead32, [ctrl.bus], [ctrl.devfn], dword 4 |
@@: |
mov ebx, eax |
and eax, 0xFFFF |
mov [ctrl.pci_cmd], eax |
shr ebx, 16 |
mov [ctrl.pci_stat], ebx |
mov esi, msgPciCmd |
call SysMsgBoardStr |
stdcall fdword2str, 2 |
call SysMsgBoardStr |
mov esi, msgPciStat |
call SysMsgBoardStr |
mov eax, [ctrl.pci_stat] |
stdcall fdword2str, 2 |
call SysMsgBoardStr |
mov esi, msgHDALowMMIo |
call SysMsgBoardStr |
stdcall PciRead32, [ctrl.bus], [ctrl.devfn], dword 0x10 |
stdcall fdword2str, 2 |
call SysMsgBoardStr |
and eax, 0xFFFFC000 |
mov [ctrl.ctrl_mem_base], eax |
mov esi, msgHDAUpMMIo |
call SysMsgBoardStr |
stdcall PciRead32, [ctrl.bus], [ctrl.devfn], dword 0x14 |
;-mov [ctrl.hda_upper_mem_base], eax |
stdcall fdword2str, 2 |
call SysMsgBoardStr |
.default: |
stdcall PciRead32, [ctrl.bus], [ctrl.devfn], dword 0x3C |
and eax, 0xFF |
@@: |
mov [ctrl.int_line], eax |
mov [ctrl.user_callback], 0 |
call set_HDA |
;Asper This is from "azx_create" proc. [ |
xor eax, eax |
mov edx, ICH6_REG_GCAP |
call azx_readw |
if DEBUG |
mov esi, msgGCap |
call SysMsgBoardStr |
stdcall fdword2str, 2 |
call SysMsgBoardStr |
end if |
; allocate CORB/RIRB |
call azx_alloc_cmd_io |
; initialize chip |
call azx_init_pci |
xor eax, eax |
call azx_init_chip |
;] Asper |
xor eax, eax |
inc eax |
ret |
endp |
PG_SW equ 0x003 |
PG_NOCACHE equ 0x018 |
align 4 |
proc set_HDA |
stdcall MapIoMem,[ctrl.ctrl_mem_base],0x1000,PG_SW+PG_NOCACHE |
mov [ctrl.ctrl_mem_base], eax |
ret |
endp |
; in: eax - fullreset_flag |
; |
; reset codec link |
align 4 |
proc reset_controller |
locals |
counter dd ? |
endl |
test eax, eax |
jz .skip |
; clear STATESTS |
mov eax, STATESTS_INT_MASK |
mov edx, ICH6_REG_STATESTS |
call azx_writeb |
; reset controller |
mov edx, ICH6_REG_GCTL |
call azx_readl |
mov ebx, ICH6_GCTL_RESET |
xor ebx, -1 |
and eax, ebx |
mov edx, ICH6_REG_GCTL |
call azx_writel |
mov [counter], 50 ; total 50*100 us = 0.5s |
.wait0: |
mov edx, ICH6_REG_GCTL |
call azx_readb |
test eax, eax |
jz @f |
mov eax, 100 ; wait 100 us |
call StallExec |
dec [counter] |
jnz .wait0 |
@@: |
; delay for >= 100us for codec PLL to settle per spec |
; Rev 0.9 section 5.5.1 |
mov eax, 100 ; wait 100 us |
call StallExec |
; Bring controller out of reset |
mov edx, ICH6_REG_GCTL |
call azx_readb |
or eax, ICH6_GCTL_RESET |
mov edx, ICH6_REG_GCTL |
call azx_writeb |
mov [counter], 50 ; total 50*100 us = 0.5s |
.wait1: |
mov edx, ICH6_REG_GCTL |
call azx_readb |
test eax, eax |
jnz @f |
mov eax, 100 ; wait 100 us |
call StallExec |
dec [counter] |
jnz .wait1 |
@@: |
; Brent Chartrand said to wait >= 540us for codecs to intialize |
mov eax, 540 ; wait 540 us |
call StallExec |
.skip: |
; check to see if controller is ready |
mov edx, ICH6_REG_GCTL |
call azx_readb |
test eax, eax |
jz .fail |
; Accept unsolicited responses |
if USE_SINGLE_MODE |
else |
;UNSUPPORTED YET! [ |
; mov edx, ICH6_REG_GCTL |
; call azx_readl |
; or eax, ICH6_GCTL_UNSOL |
; mov edx, ICH6_REG_GCTL |
; call azx_writel |
;UNSUPPORTED YET! ] |
end if |
; detect codecs |
mov eax, [ctrl.codec_mask] |
test ax, ax |
jnz @f |
mov edx, ICH6_REG_STATESTS |
call azx_readw |
mov [ctrl.codec_mask], eax |
if DEBUG |
mov esi, msgCodecMask |
call SysMsgBoardStr |
stdcall fdword2str, 2 |
call SysMsgBoardStr |
end if |
@@: |
.ok: |
clc |
ret |
.fail: |
if DEBUG |
mov esi, msgHDARFail |
call SysMsgBoardStr |
end if |
stc |
ret |
endp |
align 4 |
play: |
mov edx, ICH6_REG_WALLCLK |
call azx_readl |
mov [ctrl.start_wallclk], eax |
call azx_stream_start |
xor eax, eax |
ret |
align 4 |
stop: |
;* call azx_stream_stop ;Asper: Hangs system |
;R push ebx ecx edx |
;R ; stop DMA |
;R mov edx, ICH6_REG_SD_CTL |
;R call azx_sd_readb |
;R mov bl, SD_CTL_DMA_START or SD_INT_MASK |
;R xor bl, -1 |
;R and al, bl |
;R mov edx, ICH6_REG_SD_CTL |
;R call azx_sd_writeb |
;R mov edx, ICH6_REG_SD_STS |
;R mov al, SD_INT_MASK |
;R call azx_sd_writeb ; to be sure |
; disable SIE |
;N mov edx, ICH6_REG_INTCTL |
;N call azx_readb |
;N mov bl, SDO_INT ;shl azx_dev->index |
;N xor bl, -1 |
;N and al, bl |
;N mov edx, ICH6_REG_INTCTL |
;N call azx_writeb |
; int timeout = 5000; |
; while (azx_sd_readb(azx_dev, SD_CTL) & SD_CTL_DMA_START && --timeout) ; |
;Asper: Hangs system [ |
;* mov ecx, 5000 |
;* .l1: |
;* mov edx, ICH6_REG_SD_CTL |
;* call azx_sd_readb |
;* test al, SD_CTL_DMA_START |
;* jz @f |
;* dec ecx |
;* jnz .l1 |
;* @@: |
;* |
;* pop edx ecx ebx |
;Asper ] |
xor eax, eax |
ret |
;align 4 |
;proc get_dev_info stdcall, p_info:dword |
; virtual at esi |
; CTRL_INFO CTRL_INFO |
; end virtual |
; |
; mov esi, [p_info] |
; mov eax, [ctrl.int_line] |
; mov bx, [ctrl.dev_id] |
; shl ebx, 16 |
; and bx, [ctrl.vendor] |
; mov ecx, [ctrl.pci_cmd] |
; mov edx, [ctrl.codec_mem_base] ;[ctrl.hda_lower_mem_base] |
; mov edi, [ctrl.ctrl_mem_base] ;[ctrl.hda_upper_mem_base] |
; |
; mov [CTRL_INFO.irq], eax |
; mov [CTRL_INFO.codec_id], ebx |
; mov [CTRL_INFO.pci_cmd], ecx |
; mov [CTRL_INFO.codec_mem_base], edx |
; mov [CTRL_INFO.ctrl_mem_base], edi |
; |
; xor eax, eax |
; mov [CTRL_INFO.codec_io_base], eax |
; mov [CTRL_INFO.ctrl_io_base], eax |
; mov [CTRL_INFO.glob_cntrl], eax |
; mov [CTRL_INFO.glob_sta], eax |
; ret |
;endp |
align 4 |
proc set_callback stdcall, handler:dword |
mov eax, [handler] |
mov [ctrl.user_callback], eax |
ret |
endp |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; Interface for HD codec ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; CORB / RIRB interface ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;; |
proc azx_alloc_cmd_io |
push eax ecx edx |
; single page (at least 4096 bytes) must suffice for both ringbuffers |
stdcall KernelAlloc, 4096 |
mov [ctrl.rb], eax |
mov edi, eax |
mov ecx, 4096/4 |
xor eax, eax |
cld |
rep stosd |
pop edx ecx eax |
ret |
endp |
proc azx_init_cmd_io |
pusha |
; CORB set up |
mov eax, [ctrl.rb] |
mov ebx, eax |
call GetPgAddr |
and ebx, 0xFFF |
add eax, ebx |
push eax ; save corb address |
mov edx, ICH6_REG_CORBLBASE |
call azx_writel |
xor eax, eax |
mov edx, ICH6_REG_CORBUBASE |
call azx_writel |
; set the corb size to 256 entries (ULI requires explicitly) |
mov al, 0x02 |
mov edx, ICH6_REG_CORBSIZE |
call azx_writeb |
; set the corb write pointer to 0 |
xor ax, ax |
mov edx, ICH6_REG_CORBWP |
call azx_writew |
; reset the corb hw read pointer |
mov ax, ICH6_CORBRP_RST |
mov edx, ICH6_REG_CORBRP |
call azx_writew |
; enable corb dma |
mov al, ICH6_CORBCTL_RUN |
mov edx, ICH6_REG_CORBCTL |
call azx_writeb |
; RIRB set up |
mov [ctrl.rirb_rp], 0 |
mov [ctrl.rirb_wp], 0 |
mov [ctrl.rirb_cmd], 0 |
pop eax ; restore corb address |
add eax, 2048 |
mov edx, ICH6_REG_RIRBLBASE |
call azx_writel |
xor eax, eax |
mov edx, ICH6_REG_RIRBUBASE |
call azx_writel |
; set the rirb size to 256 entries (ULI requires explicitly) |
mov al, 0x02 |
mov edx, ICH6_REG_RIRBSIZE |
call azx_writeb |
; reset the rirb hw write pointer |
mov ax, ICH6_RIRBWP_RST |
mov edx, ICH6_REG_RIRBWP |
call azx_writew |
; set N=1, get RIRB response interrupt for new entry |
xor ax, ax |
cmp byte [driver_type], AZX_DRIVER_CTX |
jne @f |
mov ax, 0xC0-1 |
@@: |
inc ax |
mov edx, ICH6_REG_RINTCNT |
call azx_writew |
; enable rirb dma and response irq |
mov al, ICH6_RBCTL_DMA_EN or ICH6_RBCTL_IRQ_EN |
mov edx, ICH6_REG_RIRBCTL |
call azx_writeb |
popa |
ret |
endp |
proc azx_free_cmd_io |
push eax edx |
; disable ringbuffer DMAs |
xor al, al |
mov edx, ICH6_REG_RIRBCTL |
call azx_writeb |
mov edx, ICH6_REG_CORBCTL |
call azx_writeb |
pop edx eax |
ret |
endp |
; send a command |
proc azx_corb_send_cmd stdcall, val:dword |
push edx edi |
xor eax, eax |
; add command to corb |
mov edx, ICH6_REG_CORBWP |
call azx_readb |
inc al |
inc dword [ctrl.rirb_cmd] |
mov edi, dword [ctrl.rb] |
push eax |
shl eax, 2 ;wp=wp*sizeof(corb entry)=wp*4 |
add edi, eax |
mov eax, dword [val] |
stosd |
pop eax |
mov edx, ICH6_REG_CORBWP |
call azx_writel |
pop edi edx |
xor eax, eax ;Asper+ |
ret |
endp |
; retrieve RIRB entry - called from interrupt handler |
proc azx_update_rirb |
pusha |
xor eax, eax |
mov edx, ICH6_REG_RIRBWP |
call azx_readb ;call azx_readw |
cmp ax, [ctrl.rirb_wp] |
je .done |
mov [ctrl.rirb_wp], ax |
mov bx, [ctrl.rirb_rp] |
.l1: |
cmp bx, [ctrl.rirb_wp] |
je .l3 |
inc bl |
.l2: |
cmp bx, ICH6_MAX_RIRB_ENTRIES |
jl @f |
sub bx, ICH6_MAX_RIRB_ENTRIES |
jmp .l2 |
@@: |
movzx edx, bx |
shl edx, 1 + 2 ; an RIRB entry is 8-bytes |
mov esi, dword [ctrl.rb] |
add esi, 2048 |
add esi, edx |
lodsd ; res |
mov edx, eax |
lodsd ; res_ex |
test eax, ICH6_RIRB_EX_UNSOL_EV |
jz @f |
stdcall snd_hda_queue_unsol_event, edx, eax |
jmp .l1 |
@@: |
mov ecx, [ctrl.rirb_cmd] |
test ecx, ecx |
jz @f |
mov [ctrl.rirb_res], edx |
dec dword [ctrl.rirb_cmd] |
jmp .l1 |
@@: |
if DEBUG |
push esi |
mov esi, msgSpuriousResponce |
call SysMsgBoardStr |
pop esi |
end if |
jmp .l1 |
.l3: |
mov [ctrl.rirb_rp], bx |
.done: |
popa |
ret |
endp |
; receive a response |
proc azx_rirb_get_response |
locals |
do_poll db 0 |
endl |
push ebx ecx edx |
.again: |
mov ecx, 1000;+1000 |
.next_try: |
mov al, [ctrl.polling_mode] |
test al, al |
jnz .poll |
mov ah, [do_poll] |
test ah, ah |
jz @f |
.poll: |
call azx_update_rirb |
@@: |
mov eax, [ctrl.rirb_cmd] |
test eax, eax |
jnz .l1 |
mov [ctrl.rirb_error], 0 |
mov al, [do_poll] |
test al, al |
jnz @f |
mov [ctrl.poll_count], 0 |
@@: |
mov eax, [ctrl.rirb_res] ; the last value |
jmp .out |
.l1: |
push eax |
mov eax, 2000 ; temporary workaround |
call StallExec |
pop eax |
dec ecx |
jnz .next_try |
.no_next_try: |
mov al, [ctrl.polling_mode] |
test al, al |
jnz .no_poll |
mov al, [ctrl.poll_count] |
cmp al, 2 |
jge .poll_count_overflow |
if DEBUG |
push eax esi |
mov esi, msgGetResponceTimeout |
call SysMsgBoardStr |
mov esi, msgPollingCodecOnce |
call SysMsgBoardStr |
pop esi eax |
end if |
mov [do_poll], 1 |
inc [ctrl.poll_count] |
jmp .again |
.poll_count_overflow: |
if DEBUG |
push eax esi |
mov esi, msgGetResponceTimeout |
call SysMsgBoardStr |
mov esi, msgSwitchToPollMode |
call SysMsgBoardStr |
pop esi eax |
end if |
mov [ctrl.polling_mode], 1 |
jmp .again |
.no_poll: |
mov al, [ctrl.polling_mode] |
test al, al |
jz @f |
mov eax, -1 |
jmp .out |
@@: |
; a fatal communication error; need either to reset or to fallback |
; to the single_cmd mode |
mov [ctrl.rirb_error], 1 |
;Asper~ -? [ |
mov [ctrl.response_reset], 1 |
mov eax, -1 ; give a chance to retry |
jmp .out |
;Asper~ -? ] |
;-? mov [ctrl.single_cmd], 1 |
mov [ctrl.response_reset], 0 |
; release CORB/RIRB |
call azx_free_cmd_io |
; disable unsolicited responses |
mov edx, ICH6_REG_GCTL |
call azx_readl |
mov ebx, ICH6_GCTL_UNSOL |
xor ebx, -1 |
and eax, ebx |
mov edx, ICH6_REG_GCTL |
call azx_writel |
mov eax, -1 |
.out: |
pop edx ecx ebx |
ret |
endp |
; |
; Use the single immediate command instead of CORB/RIRB for simplicity |
; |
; Note: according to Intel, this is not preferred use. The command was |
; intended for the BIOS only, and may get confused with unsolicited |
; responses. So, we shouldn't use it for normal operation from the |
; driver. |
; I left the codes, however, for debugging/testing purposes. |
; |
; receive a response |
proc azx_single_wait_for_response |
push ecx edx esi |
mov ecx, 50 |
.l1: |
test ecx, ecx |
jz .timeout |
; check IRV busy bit |
mov edx, ICH6_REG_IRS |
call azx_readw |
test ax, ICH6_IRS_VALID |
jz @f |
; reuse rirb.res as the response return value |
mov edx, ICH6_REG_IR |
call azx_readl |
mov [ctrl.rirb_res], eax |
pop esi edx ecx |
xor eax, eax |
ret |
@@: |
xor eax, eax |
inc eax |
call StallExec |
dec ecx |
jmp .l1 |
.timeout: |
if DEBUG |
xor eax, eax |
mov edx, ICH6_REG_IRS |
call azx_readw |
mov esi, msgGetResponceTimeout |
call SysMsgBoardStr |
mov esi, msgIRS |
call SysMsgBoardStr |
stdcall fdword2str, 2 |
call SysMsgBoardStr |
end if |
pop esi edx ecx |
mov eax, -1 |
mov [ctrl.rirb_res], eax |
ret |
endp |
; send a command |
proc azx_single_send_cmd stdcall, val:dword |
push ecx edx esi |
mov ecx, 50 |
.l1: |
test ecx, ecx |
jz .timeout |
; check ICB busy bit |
mov edx, ICH6_REG_IRS |
call azx_readw |
test ax, ICH6_IRS_BUSY |
jnz @f |
; Clear IRV valid bit |
mov edx, ICH6_REG_IRS |
call azx_readw |
or ax, ICH6_IRS_VALID |
mov edx, ICH6_REG_IRS |
call azx_writew |
mov eax, dword [val] |
mov edx, ICH6_REG_IC |
call azx_writel |
mov edx, ICH6_REG_IRS |
call azx_readw |
or ax, ICH6_IRS_BUSY |
mov edx, ICH6_REG_IRS |
call azx_writew |
stdcall azx_single_wait_for_response |
pop esi edx ecx |
ret |
@@: |
dec ecx |
jmp .l1 |
.timeout: |
if DEBUG |
xor eax, eax |
mov edx, ICH6_REG_IRS |
call azx_readw |
mov esi, msgSendCmdTimeout |
call SysMsgBoardStr |
stdcall fdword2str, 2 |
call SysMsgBoardStr |
mov esi, msgVal |
call SysMsgBoardStr |
mov eax, dword [val] |
stdcall fdword2str, 2 |
call SysMsgBoardStr |
end if |
pop esi edx ecx |
mov eax, -1 |
ret |
endp |
; receive a response |
proc azx_single_get_response |
mov eax, [ctrl.rirb_res] |
ret |
endp |
; |
; The below are the main callbacks from hda_codec. |
; |
; They are just the skeleton to call sub-callbacks according to the |
; current setting of chip->single_cmd. |
; |
; send a command |
proc azx_send_cmd stdcall, val:dword |
if USE_SINGLE_MODE |
stdcall azx_single_send_cmd, [val] |
else |
stdcall azx_corb_send_cmd, [val] |
end if |
ret |
endp |
; get a response |
proc azx_get_response |
if USE_SINGLE_MODE |
call azx_single_get_response |
else |
call azx_rirb_get_response |
end if |
ret |
endp |
;;;;;;;;;;;;;;;;;;;;;;;; |
;; Lowlevel interface ;; |
;;;;;;;;;;;;;;;;;;;;;;;; |
; enable interrupts |
proc azx_int_enable |
push eax edx |
; enable controller CIE and GIE |
mov edx, ICH6_REG_INTCTL |
call azx_readl |
or eax, ICH6_INT_CTRL_EN or ICH6_INT_GLOBAL_EN |
mov edx, ICH6_REG_INTCTL |
call azx_writel |
pop edx eax |
ret |
endp |
; disable interrupts |
proc azx_int_disable |
push eax ebx edx |
; disable interrupts in stream descriptor |
mov edx, ICH6_REG_SD_CTL + SDO_OFS |
call azx_readb |
mov bl, SD_INT_MASK |
xor bl, -1 |
and al, bl |
mov edx, ICH6_REG_SD_CTL + SDO_OFS |
call azx_writeb |
; disable SIE for all streams |
xor al, al |
mov edx, ICH6_REG_INTCTL |
call azx_writeb |
; disable controller CIE and GIE |
mov edx, ICH6_REG_INTCTL |
call azx_readl |
mov ebx, ICH6_INT_CTRL_EN or ICH6_INT_GLOBAL_EN |
xor ebx, -1 |
and eax, ebx |
call azx_writel |
pop edx ebx eax |
ret |
endp |
; clear interrupts |
proc azx_int_clear |
push eax edx |
; clear stream status |
mov al, SD_INT_MASK |
mov edx, ICH6_REG_SD_STS + SDO_OFS |
call azx_writeb |
; clear STATESTS |
mov al, STATESTS_INT_MASK |
mov edx, ICH6_REG_STATESTS |
call azx_writeb |
; clear rirb status |
mov al, RIRB_INT_MASK |
mov edx, ICH6_REG_RIRBSTS |
call azx_writeb |
; clear int status |
mov eax, ICH6_INT_CTRL_EN or ICH6_INT_ALL_STREAM |
mov edx, ICH6_REG_INTSTS |
call azx_writel |
pop edx eax |
ret |
endp |
; start a stream |
proc azx_stream_start |
push eax edx |
; enable SIE |
mov edx, ICH6_REG_INTCTL |
call azx_readl |
or eax, 0xC0000000 ;Asper+ |
or eax, SDO_INT ; Asper: output stream interrupt index |
mov edx, ICH6_REG_INTCTL |
call azx_writel |
; set DMA start and interrupt mask |
mov edx, ICH6_REG_SD_CTL + SDO_OFS |
call azx_readb |
or al, SD_CTL_DMA_START or SD_INT_MASK |
mov edx, ICH6_REG_SD_CTL + SDO_OFS |
call azx_writeb |
pop edx eax |
ret |
endp |
; stop DMA |
proc azx_stream_clear |
push eax ebx edx |
mov edx, ICH6_REG_SD_CTL + SDO_OFS |
call azx_readb |
mov bl, SD_CTL_DMA_START or SD_INT_MASK |
xor bl, -1 |
and al, bl |
mov edx, ICH6_REG_SD_CTL + SDO_OFS |
call azx_writeb |
mov al, SD_INT_MASK |
mov edx, ICH6_REG_SD_STS + SDO_OFS |
call azx_writeb |
pop edx ebx eax |
ret |
endp |
; stop a stream |
proc azx_stream_stop |
push eax ebx edx |
call azx_stream_clear |
; disable SIE |
mov edx, ICH6_REG_INTCTL |
call azx_readl |
mov ebx, (SDO_INT) |
xor ebx, -1 |
and eax, ebx |
mov edx, ICH6_REG_INTCTL |
call azx_writel |
pop edx ebx eax |
ret |
endp |
; |
;in: eax = full_reset |
; |
; initialize the chip |
proc azx_init_chip |
push eax |
; reset controller |
mov eax, 1 ;full reset |
call reset_controller |
; initialize interrupts |
call azx_int_clear |
call azx_int_enable |
; initialize the codec command I/O |
if USE_SINGLE_MODE |
else |
call azx_init_cmd_io |
end if |
; program the position buffer |
mov eax, dword [ctrl.posbuf] |
mov ebx, eax |
call GetPgAddr |
and ebx, 0xFFF |
add eax, ebx |
mov edx, ICH6_REG_DPLBASE |
call azx_writel |
xor eax, eax |
mov edx, ICH6_REG_DPUBASE |
call azx_writel |
pop eax |
ret |
endp |
; initialize the PCI registers |
; update bits in a PCI register byte |
proc update_pci_byte stdcall, reg:dword, mask:dword, val:dword |
push ax bx |
stdcall PciRead8, [ctrl.bus], [ctrl.devfn], [reg] |
mov bl, byte [mask] |
mov bh, bl |
xor bl, -1 |
and al, bl |
shr bx, 8 |
and bl, byte [val] |
or al, bl |
stdcall PciWrite8, [ctrl.bus], [ctrl.devfn], [reg], eax |
pop bx ax |
ret |
endp |
proc azx_init_pci |
; Clear bits 0-2 of PCI register TCSEL (at offset 0x44) |
; TCSEL == Traffic Class Select Register, which sets PCI express QOS |
; Ensuring these bits are 0 clears playback static on some HD Audio |
; codecs |
push eax |
stdcall update_pci_byte, ICH6_PCIREG_TCSEL, 0x07, 0 |
mov eax, [driver_type] |
cmp eax, AZX_DRIVER_ATI |
jne @f |
; For ATI SB450 azalia HD audio, we need to enable snoop |
stdcall update_pci_byte, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, 0x07, ATI_SB450_HDAUDIO_ENABLE_SNOOP |
jmp .done |
@@: |
cmp eax, AZX_DRIVER_NVIDIA |
jne @f |
; For NVIDIA HDA, enable snoop |
stdcall update_pci_byte, NVIDIA_HDA_TRANSREG_ADDR, 0x0f, NVIDIA_HDA_ENABLE_COHBITS |
stdcall update_pci_byte, NVIDIA_HDA_ISTRM_COH, 0x01, NVIDIA_HDA_ENABLE_COHBIT |
stdcall update_pci_byte, NVIDIA_HDA_OSTRM_COH, 0x01, NVIDIA_HDA_ENABLE_COHBIT |
jmp .done |
@@: |
cmp eax, AZX_DRIVER_SCH |
je .l1 |
cmp eax, AZX_DRIVER_PCH |
jne @f |
.l1: |
stdcall PciRead16, [ctrl.bus], [ctrl.devfn], dword INTEL_SCH_HDA_DEVC |
test ax, INTEL_SCH_HDA_DEVC_NOSNOOP |
jz @f |
push ebx |
mov ebx, INTEL_SCH_HDA_DEVC_NOSNOOP |
xor ebx, -1 |
and eax, ebx |
pop ebx |
stdcall PciWrite16, [ctrl.bus], [ctrl.devfn], dword INTEL_SCH_HDA_DEVC, eax |
stdcall PciRead16, [ctrl.bus], [ctrl.devfn], dword INTEL_SCH_HDA_DEVC |
if DEBUG |
push esi |
mov esi, msgHDASnoopDisabled |
call SysMsgBoardStr |
mov esi, msg_OK |
test ax, INTEL_SCH_HDA_DEVC_NOSNOOP |
jz .snoop_ok |
mov esi, msg_Fail |
.snoop_ok: |
call SysMsgBoardStr |
pop esi |
end if |
@@: |
.done: |
pop eax |
ret |
endp |
; reset stream |
proc azx_stream_reset |
push eax ebx ecx edx |
call azx_stream_clear |
mov edx, ICH6_REG_SD_CTL + SDO_OFS |
call azx_readb |
or al, SD_CTL_STREAM_RESET |
mov edx, ICH6_REG_SD_CTL + SDO_OFS |
call azx_writeb |
mov eax, 3 |
call StallExec |
mov ecx, 300 |
.l1: |
mov edx, ICH6_REG_SD_CTL + SDO_OFS |
call azx_readb |
test al, SD_CTL_STREAM_RESET |
jnz @f |
dec ecx |
jnz .l1 |
@@: |
mov bl, SD_CTL_STREAM_RESET |
xor bl, -1 |
and al, bl |
mov edx, ICH6_REG_SD_CTL + SDO_OFS |
call azx_writeb |
mov eax, 3 |
call StallExec |
mov ecx, 300 |
; waiting for hardware to report that the stream is out of reset |
.l2: |
mov edx, ICH6_REG_SD_CTL + SDO_OFS |
call azx_readb |
test al, SD_CTL_STREAM_RESET |
jnz @f |
dec ecx |
jnz .l2 |
@@: |
; reset first position - may not be synced with hw at this time |
mov edx, [ctrl.posbuf] |
mov dword [edx], 0 |
pop edx ecx ebx eax |
ret |
endp |
; set up the SD for streaming |
proc azx_setup_controller |
push eax ebx ecx edx |
; make sure the run bit is zero for SD |
call azx_stream_clear |
; program the stream_tag |
mov edx, ICH6_REG_SD_CTL + SDO_OFS |
call azx_readl |
mov ecx, SD_CTL_STREAM_TAG_MASK |
xor ecx, -1 |
and eax, ecx |
mov ecx, SDO_TAG |
shl ecx, SD_CTL_STREAM_TAG_SHIFT |
or eax, ecx |
; Asper stream_tag = SDO_TAG |
mov edx, ICH6_REG_SD_CTL + SDO_OFS |
call azx_writel |
; program the length of samples in cyclic buffer |
mov eax, 0x4000*32 |
mov edx, ICH6_REG_SD_CBL + SDO_OFS |
call azx_writel |
; program the stream format |
; this value needs to be the same as the one programmed |
mov ax, 0x11 |
mov edx, ICH6_REG_SD_FORMAT + SDO_OFS |
call azx_writew |
; program the stream LVI (last valid index) of the BDL |
mov eax, 32-1 ;4-1 ;2-1 |
mov [ctrl.lvi_reg], eax |
mov edx, ICH6_REG_SD_LVI + SDO_OFS |
call azx_writew |
; program the BDL address |
; lower BDL address |
mov eax, [pcmout_bdl] |
mov ebx, eax |
call GetPgAddr |
and ebx, 0xFFF |
add eax, ebx |
mov edx, ICH6_REG_SD_BDLPL + SDO_OFS |
call azx_writel |
; upper BDL address |
xor eax, eax ;upper_32bit(azx_dev->bdl_addr) |
mov edx, ICH6_REG_SD_BDLPU + SDO_OFS |
call azx_writel |
; enable the position buffer |
cmp [ctrl.position_fix], POS_FIX_LPIB |
jz @f |
mov edx, ICH6_REG_DPLBASE |
call azx_readl |
and eax, ICH6_DPLBASE_ENABLE |
jnz @f |
mov eax, dword [ctrl.posbuf] |
mov ebx, eax |
call GetPgAddr |
and ebx, 0xFFF |
add eax, ebx |
or eax, ICH6_DPLBASE_ENABLE |
mov edx, ICH6_REG_DPLBASE |
call azx_writel |
@@: |
; set the interrupt enable bits in the descriptor control register |
mov edx, ICH6_REG_SD_CTL + SDO_OFS |
call azx_readl |
or eax, SD_INT_MASK |
mov edx, ICH6_REG_SD_CTL + SDO_OFS |
call azx_writel |
pop edx ecx ebx eax |
ret |
endp |
;(...) |
; Probe the given codec address |
proc probe_codec, addr:dword |
push edx |
mov eax, [addr] |
shl eax, 28 |
mov edx, (AC_NODE_ROOT shl 20) or (AC_VERB_PARAMETERS shl 8) or AC_PAR_VENDOR_ID |
or eax, edx |
stdcall azx_send_cmd, eax |
stdcall azx_get_response |
cmp eax, -1 |
je .out |
mov eax, [addr] |
mov [codec.addr], eax ;Asper+ |
if DEBUG |
push esi |
mov esi, msgCodecOK |
call SysMsgBoardStr |
mov esi, msgCAd |
call SysMsgBoardStr |
stdcall fdword2str, 3 |
call SysMsgBoardStr |
pop esi |
end if |
xor eax, eax |
.out: |
pop edx |
ret |
endp |
proc azx_bus_reset |
call azx_stop_chip |
call azx_init_chip |
endp |
; Codec initialization |
proc azx_codec_create |
push ebx ecx edx |
;(...) |
; First try to probe all given codec slots |
; Asper: We asume for now that max slots for codecs = 4 |
xor ecx, ecx |
xor edx, edx |
inc edx |
.next_slot: |
test edx, [ctrl.codec_mask] |
jz @f |
stdcall probe_codec, ecx |
test eax, eax |
jz .init ;@f |
; Some BIOSen give you wrong codec addresses that don't exist |
if DEBUG |
mov esi, msgCodecError |
call SysMsgBoardStr |
end if |
mov ebx, edx |
xor ebx, -1 |
and [ctrl.codec_mask], ebx |
; More badly, accessing to a non-existing |
; codec often screws up the controller chip, |
; and disturbs the further communications. |
; Thus if an error occurs during probing, |
; better to reset the controller chip to |
; get back to the sanity state. |
;call azx_bus_reset |
@@: |
shl edx, 1 |
inc ecx |
; if USE_FIRST_CODEC |
; cmp ecx, 1 |
; else |
cmp ecx, 3 |
; end if |
jl .next_slot |
mov eax, -1 |
jmp .out |
.init: |
stdcall snd_hda_codec_init |
xor eax, eax |
.out: |
pop edx ecx ebx |
ret |
endp |
proc azx_codec_configure |
;(...) |
call snd_hda_codec_configure |
ret |
endp |
proc azx_get_position |
test [ctrl.position_fix], POS_FIX_LPIB |
jz @f |
; read LPIB |
mov edx, ICH6_REG_SD_LPIB + SDO_OFS |
call azx_readl |
jmp .out |
@@: |
test [ctrl.position_fix], POS_FIX_VIACOMBO |
jz @f |
; call azx_get_via_position |
; jmp .out |
@@: |
; use the position buffer |
push edx |
mov edx, dword [ctrl.posbuf] |
mov eax, dword [edx] |
pop edx |
.out: |
cmp eax, 0x4000 ; bufsize |
jl @f |
xor eax, eax |
@@: |
ret |
endp |
proc azx_stop_chip |
push eax edx |
; disable interrupts |
call azx_int_disable |
call azx_int_clear |
; disable CORB/RIRB |
call azx_free_cmd_io |
; disable position buffer |
xor eax, eax |
mov edx, ICH6_REG_DPLBASE |
call azx_writel |
mov edx, ICH6_REG_DPUBASE |
call azx_writel |
pop edx eax |
ret |
endp |
; in: eax = volume (-10000 - 0) |
align 4 |
set_master_vol: |
mov ecx, 3 |
call set_channel_volume |
ret |
; out: [pvol] = volume (-10000 - 0) |
align 4 |
proc get_master_vol stdcall, pvol:dword |
xor ecx, ecx |
call get_channel_volume |
mov ebx, [pvol] |
mov [ebx], eax |
xor eax, eax |
ret |
endp |
; in: ecx = channel mask (1 - Left; 2 - Right; 3-Both) |
; eax = volume (-10000 - 0) |
align 4 |
set_channel_volume: |
push eax ebx ecx edx |
mov ebx, [volume.maxDb] |
neg eax |
if 0;DEBUG ;YAHOO |
push eax esi |
mov esi, msgNewVolume |
call SysMsgBoardStr |
stdcall fdword2str, 2 |
call SysMsgBoardStr |
mov esi, msgMaxVolume |
call SysMsgBoardStr |
mov eax, ebx |
stdcall fdword2str, 2 |
call SysMsgBoardStr |
pop esi eax |
end if |
test ebx, ebx |
jz .err_out |
cmp eax, 0 |
jg @f |
xor eax, eax |
jmp .set |
@@: |
cmp eax, ebx |
jl .set |
mov eax, ebx |
.set: |
;cdq |
xor edx, edx |
shl eax, 2 |
mov ebx, 100 |
div bx |
mov bl, [volume.step_size] |
div bl |
mov edx, [volume.out_amp_node] |
test edx, edx |
jz .out |
movzx ebx, [edx+HDA_GNODE.nid] |
test ecx, 1 ; Left channel ? |
jz @f |
stdcall put_volume_mute, ebx, 0, HDA_OUTPUT, 0, eax |
@@: |
test ecx, 2 ; Right channel ? |
jz .out |
stdcall put_volume_mute, ebx, 1, HDA_OUTPUT, 0, eax |
.out: |
pop edx ecx ebx eax |
ret |
.err_out: |
if 0;DEBUG ;YAHOO |
push esi |
mov esi, emsgNoVolCtrl |
call SysMsgBoardStr |
pop esi |
end if |
jmp .out |
; in: ecx = channel (1 - Left; 2 - Right) |
; out: eax = volume (-10000 - 0) |
align 4 |
get_channel_volume: |
push ebx ecx edx |
cmp ecx, 2 |
jg .out |
dec cl |
xor eax, eax |
mov edx, [volume.out_amp_node] |
test edx, edx |
jz .out |
movzx ebx, [edx+HDA_GNODE.nid] |
stdcall get_volume_mute, ebx, ecx, HDA_OUTPUT, 0 |
mov cl, [volume.step_size] |
mul cl |
mov cx, 100 |
mul cx |
shr eax, 2 ; *0.25 |
neg eax |
.out: |
pop edx ecx ebx |
ret |
; in: ecx = delay |
udelay: |
push eax ecx edx |
test ecx, ecx |
jnz @f |
inc ecx |
@@: |
mov eax, ecx |
mov cx, 500 |
mul cl |
mov ecx, edx |
shl ecx, 16 |
or ecx, eax |
@@: |
xor eax, eax |
cpuid |
dec ecx |
jz @b |
pop edx ecx eax |
ret |
align 4 |
proc StallExec |
push ecx |
push edx |
push ebx |
push eax |
mov ecx, CPU_FREQ |
mul ecx |
mov ebx, eax ;low |
mov ecx, edx ;high |
rdtsc |
add ebx, eax |
adc ecx,edx |
@@: |
rdtsc |
sub eax, ebx |
sbb edx, ecx |
js @B |
pop eax |
pop ebx |
pop edx |
pop ecx |
ret |
endp |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
; MEMORY MAPPED IO (os depended) ; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
proc azx_readb |
add edx, [ctrl.ctrl_mem_base] |
mov al, [edx] |
ret |
endp |
align 4 |
proc azx_readw |
add edx, [ctrl.ctrl_mem_base] |
mov ax, [edx] |
ret |
endp |
align 4 |
proc azx_readl |
add edx, [ctrl.ctrl_mem_base] |
mov eax, [edx] |
ret |
endp |
align 4 |
proc azx_writeb |
add edx, [ctrl.ctrl_mem_base] |
mov [edx], al |
ret |
endp |
align 4 |
proc azx_writew |
add edx, [ctrl.ctrl_mem_base] |
mov [edx], ax |
ret |
endp |
align 4 |
proc azx_writel |
add edx, [ctrl.ctrl_mem_base] |
mov [edx], eax |
ret |
endp |
;_______ |
;Asper remember to add this functions: |
proc snd_hda_queue_unsol_event stdcall, par1:dword, par2:dword |
if DEBUG |
push esi |
mov esi, msgUnsolEvent |
call SysMsgBoardStr |
pop esi |
end if |
ret |
endp |
;... |
align 4 |
proc fdword2str stdcall, flags:dword ; bit 0 - skipLeadZeroes; bit 1 - newLine; other bits undefined |
push eax ebx ecx |
mov esi, hex_buff |
mov ecx, -8 |
push eax |
@@: |
rol eax, 4 |
mov ebx, eax |
and ebx, 0x0F |
mov bl, [ebx+hexletters] |
mov [8+esi+ecx], bl |
inc ecx |
jnz @B |
pop eax |
mov dword [esi+8], 0 |
test [flags], 0x2 ; new line ? |
jz .no_newline |
mov dword [esi+8], 0x00000A0D |
.no_newline: |
push eax |
test [flags], 0x1 ; skip zero bits ? |
jz .no_skipz |
mov ecx, 8 |
@@: |
test eax, 0xF0000000 |
jnz .skipz_done |
rol eax, 4 |
inc esi |
dec ecx |
jnz @b |
dec esi |
.skipz_done: |
.no_skipz: |
pop eax |
pop ecx ebx eax |
ret |
endp |
hexletters db '0123456789ABCDEF' |
hex_buff db 8 dup(0),13,10,0,0 |
include "codec.inc" |
include "hda_generic.inc" |
align 4 |
devices: |
; Intel |
dd (CTRL_INTEL_SCH2 shl 16)+VID_INTEL,msg_INTEL_SCH2, AZX_DRIVER_SCH |
dd (CTRL_INTEL_HPT shl 16)+VID_INTEL,msg_INTEL_HPT, AZX_DRIVER_SCH |
dd (CTRL_INTEL_CPT shl 16)+VID_INTEL,msg_INTEL_CPT, AZX_DRIVER_PCH |
dd (CTRL_INTEL_PGB shl 16)+VID_INTEL,msg_INTEL_PGB, AZX_DRIVER_PCH |
dd (CTRL_INTEL_PPT1 shl 16)+VID_INTEL,msg_INTEL_PPT1, AZX_DRIVER_PCH |
dd (CTRL_INTEL_82801F shl 16)+VID_INTEL,msg_INTEL_82801F, AZX_DRIVER_ICH |
dd (CTRL_INTEL_63XXESB shl 16)+VID_INTEL,msg_INTEL_63XXESB, AZX_DRIVER_ICH |
dd (CTRL_INTEL_82801G shl 16)+VID_INTEL,msg_INTEL_82801G, AZX_DRIVER_ICH |
dd (CTRL_INTEL_82801H shl 16)+VID_INTEL,msg_INTEL_82801H, AZX_DRIVER_ICH |
dd (CTRL_INTEL_82801_UNK1 shl 16)+VID_INTEL,msg_INTEL_82801_UNK1, AZX_DRIVER_ICH |
dd (CTRL_INTEL_82801I shl 16)+VID_INTEL,msg_INTEL_82801I, AZX_DRIVER_ICH |
dd (CTRL_INTEL_82801_UNK2 shl 16)+VID_INTEL,msg_INTEL_82801_UNK2, AZX_DRIVER_ICH |
dd (CTRL_INTEL_82801JI shl 16)+VID_INTEL,msg_INTEL_82801JI, AZX_DRIVER_ICH |
dd (CTRL_INTEL_82801JD shl 16)+VID_INTEL,msg_INTEL_82801JD, AZX_DRIVER_ICH |
dd (CTRL_INTEL_PCH shl 16)+VID_INTEL,msg_INTEL_PCH, AZX_DRIVER_PCH |
dd (CTRL_INTEL_PCH2 shl 16)+VID_INTEL,msg_INTEL_PCH2, AZX_DRIVER_PCH |
dd (CTRL_INTEL_SCH shl 16)+VID_INTEL,msg_INTEL_SCH, AZX_DRIVER_SCH |
dd (CTRL_INTEL_LPT shl 16)+VID_INTEL,msg_INTEL_LPT, AZX_DRIVER_PCH |
; Nvidia |
dd (CTRL_NVIDIA_MCP51 shl 16)+VID_NVIDIA,msg_NVIDIA_MCP51, AZX_DRIVER_NVIDIA |
dd (CTRL_NVIDIA_MCP55 shl 16)+VID_NVIDIA,msg_NVIDIA_MCP55, AZX_DRIVER_NVIDIA |
dd (CTRL_NVIDIA_MCP61_1 shl 16)+VID_NVIDIA,msg_NVIDIA_MCP61, AZX_DRIVER_NVIDIA |
dd (CTRL_NVIDIA_MCP61_2 shl 16)+VID_NVIDIA,msg_NVIDIA_MCP61, AZX_DRIVER_NVIDIA |
dd (CTRL_NVIDIA_MCP65_1 shl 16)+VID_NVIDIA,msg_NVIDIA_MCP65, AZX_DRIVER_NVIDIA |
dd (CTRL_NVIDIA_MCP65_2 shl 16)+VID_NVIDIA,msg_NVIDIA_MCP65, AZX_DRIVER_NVIDIA |
dd (CTRL_NVIDIA_MCP67_1 shl 16)+VID_NVIDIA,msg_NVIDIA_MCP67, AZX_DRIVER_NVIDIA |
dd (CTRL_NVIDIA_MCP67_2 shl 16)+VID_NVIDIA,msg_NVIDIA_MCP67, AZX_DRIVER_NVIDIA |
dd (CTRL_NVIDIA_MCP73_1 shl 16)+VID_NVIDIA,msg_NVIDIA_MCP73, AZX_DRIVER_NVIDIA |
dd (CTRL_NVIDIA_MCP73_2 shl 16)+VID_NVIDIA,msg_NVIDIA_MCP73, AZX_DRIVER_NVIDIA |
dd (CTRL_NVIDIA_MCP78_1 shl 16)+VID_NVIDIA,msg_NVIDIA_MCP78, AZX_DRIVER_NVIDIA |
dd (CTRL_NVIDIA_MCP78_2 shl 16)+VID_NVIDIA,msg_NVIDIA_MCP78, AZX_DRIVER_NVIDIA |
dd (CTRL_NVIDIA_MCP78_3 shl 16)+VID_NVIDIA,msg_NVIDIA_MCP78, AZX_DRIVER_NVIDIA |
dd (CTRL_NVIDIA_MCP78_4 shl 16)+VID_NVIDIA,msg_NVIDIA_MCP78, AZX_DRIVER_NVIDIA |
dd (CTRL_NVIDIA_MCP79_1 shl 16)+VID_NVIDIA,msg_NVIDIA_MCP79, AZX_DRIVER_NVIDIA |
dd (CTRL_NVIDIA_MCP79_2 shl 16)+VID_NVIDIA,msg_NVIDIA_MCP79, AZX_DRIVER_NVIDIA |
dd (CTRL_NVIDIA_MCP79_3 shl 16)+VID_NVIDIA,msg_NVIDIA_MCP79, AZX_DRIVER_NVIDIA |
dd (CTRL_NVIDIA_MCP79_4 shl 16)+VID_NVIDIA,msg_NVIDIA_MCP79, AZX_DRIVER_NVIDIA |
dd (CTRL_NVIDIA_0BE2 shl 16)+VID_NVIDIA,msg_NVIDIA_0BE2, AZX_DRIVER_NVIDIA |
dd (CTRL_NVIDIA_0BE3 shl 16)+VID_NVIDIA,msg_NVIDIA_0BE3, AZX_DRIVER_NVIDIA |
dd (CTRL_NVIDIA_0BE4 shl 16)+VID_NVIDIA,msg_NVIDIA_0BE4, AZX_DRIVER_NVIDIA |
dd (CTRL_NVIDIA_GT100 shl 16)+VID_NVIDIA,msg_NVIDIA_GT100, AZX_DRIVER_NVIDIA |
dd (CTRL_NVIDIA_GT106 shl 16)+VID_NVIDIA,msg_NVIDIA_GT106, AZX_DRIVER_NVIDIA |
dd (CTRL_NVIDIA_GT108 shl 16)+VID_NVIDIA,msg_NVIDIA_GT108, AZX_DRIVER_NVIDIA |
dd (CTRL_NVIDIA_GT104 shl 16)+VID_NVIDIA,msg_NVIDIA_GT104, AZX_DRIVER_NVIDIA |
dd (CTRL_NVIDIA_GT116 shl 16)+VID_NVIDIA,msg_NVIDIA_GT116, AZX_DRIVER_NVIDIA |
dd (CTRL_NVIDIA_MCP89_1 shl 16)+VID_NVIDIA,msg_NVIDIA_MCP89, AZX_DRIVER_NVIDIA |
dd (CTRL_NVIDIA_MCP89_2 shl 16)+VID_NVIDIA,msg_NVIDIA_MCP89, AZX_DRIVER_NVIDIA |
dd (CTRL_NVIDIA_MCP89_3 shl 16)+VID_NVIDIA,msg_NVIDIA_MCP89, AZX_DRIVER_NVIDIA |
dd (CTRL_NVIDIA_MCP89_4 shl 16)+VID_NVIDIA,msg_NVIDIA_MCP89, AZX_DRIVER_NVIDIA |
dd (CTRL_NVIDIA_GF119 shl 16)+VID_NVIDIA,msg_NVIDIA_GF119, AZX_DRIVER_NVIDIA |
dd (CTRL_NVIDIA_GF110_1 shl 16)+VID_NVIDIA,msg_NVIDIA_GF110, AZX_DRIVER_NVIDIA |
dd (CTRL_NVIDIA_GF110_2 shl 16)+VID_NVIDIA,msg_NVIDIA_GF110, AZX_DRIVER_NVIDIA |
; ATI |
dd (CTRL_ATI_SB450 shl 16)+VID_ATI,msg_ATI_SB450, AZX_DRIVER_ATI |
dd (CTRL_ATI_SB600 shl 16)+VID_ATI,msg_ATI_SB600, AZX_DRIVER_ATI |
dd (CTRL_ATI_RS600 shl 16)+VID_ATI,msg_ATI_RS600, AZX_DRIVER_ATIHDMI |
dd (CTRL_ATI_RS690 shl 16)+VID_ATI,msg_ATI_RS690, AZX_DRIVER_ATIHDMI |
dd (CTRL_ATI_RS780 shl 16)+VID_ATI,msg_ATI_RS780, AZX_DRIVER_ATIHDMI |
dd (CTRL_ATI_RS_UNK1 shl 16)+VID_ATI,msg_ATI_RS_UNK1, AZX_DRIVER_ATIHDMI |
dd (CTRL_ATI_R600 shl 16)+VID_ATI,msg_ATI_R600, AZX_DRIVER_ATIHDMI |
dd (CTRL_ATI_RV610 shl 16)+VID_ATI,msg_ATI_RV610, AZX_DRIVER_ATIHDMI |
dd (CTRL_ATI_RV620 shl 16)+VID_ATI,msg_ATI_RV620, AZX_DRIVER_ATIHDMI |
dd (CTRL_ATI_RV630 shl 16)+VID_ATI,msg_ATI_RV630, AZX_DRIVER_ATIHDMI |
dd (CTRL_ATI_RV635 shl 16)+VID_ATI,msg_ATI_RV635, AZX_DRIVER_ATIHDMI |
dd (CTRL_ATI_RV670 shl 16)+VID_ATI,msg_ATI_RV670, AZX_DRIVER_ATIHDMI |
dd (CTRL_ATI_RV710 shl 16)+VID_ATI,msg_ATI_RV710, AZX_DRIVER_ATIHDMI |
dd (CTRL_ATI_RV730 shl 16)+VID_ATI,msg_ATI_RV730, AZX_DRIVER_ATIHDMI |
dd (CTRL_ATI_RV740 shl 16)+VID_ATI,msg_ATI_RV740, AZX_DRIVER_ATIHDMI |
dd (CTRL_ATI_RV770 shl 16)+VID_ATI,msg_ATI_RV770, AZX_DRIVER_ATIHDMI |
; AMD |
dd (CTRL_AMD_HUDSON shl 16)+VID_AMD,msg_AMD_HUDSON, AZX_DRIVER_GENERIC |
; VIA |
dd (CTRL_VIA_VT82XX shl 16)+VID_VIA,msg_VIA_VT82XX, AZX_DRIVER_VIA |
dd (CTRL_VIA_VT61XX shl 16)+VID_VIA,msg_VIA_VT61XX, AZX_DRIVER_GENERIC |
dd (CTRL_VIA_VT71XX shl 16)+VID_VIA,msg_VIA_VT71XX, AZX_DRIVER_GENERIC |
; SiS |
dd (CTRL_SIS_966 shl 16)+VID_SIS,msg_SIS_966, AZX_DRIVER_SIS |
; ULI |
dd (CTRL_ULI_M5461 shl 16)+VID_ULI,msg_ULI_M5461, AZX_DRIVER_ULI |
; Teradici |
dd (CTRL_TERA_UNK1 shl 16)+VID_ULI,msg_TERA_UNK1, AZX_DRIVER_TERA |
; Creative |
dd (CTRL_CREATIVE_CA0110_IBG shl 16)+VID_CREATIVE,msg_CREATIVE_CA0110_IBG, AZX_DRIVER_CTX |
dd (CTRL_CREATIVE_SOUND_CORE3D_1 shl 16)+VID_CREATIVE,msg_CREATIVE_SOUND_CORE3D, AZX_DRIVER_GENERIC |
dd (CTRL_CREATIVE_SOUND_CORE3D_2 shl 16)+VID_CREATIVE,msg_CREATIVE_SOUND_CORE3D, AZX_DRIVER_GENERIC |
; RDC Semiconductor |
dd (CTRL_RDC_R3010 shl 16)+VID_RDC,msg_RDC_R3010, AZX_DRIVER_GENERIC |
; VMware |
dd (CTRL_VMWARE_UNK1 shl 16)+VID_VMWARE,msg_VMWARE_UNK1, AZX_DRIVER_GENERIC |
dd 0 ;terminator |
version dd (5 shl 16) or (API_VERSION and 0xFFFF) |
msg_Intel db 'Intel ',0 |
msg_INTEL_CPT db 'Cougar Point',13,10,0 |
msg_INTEL_PGB db 'Patsburg',13,10,0 |
msg_INTEL_PPT1 db 'Panther Point',13,10,0 |
msg_INTEL_LPT db 'Lynx Point',13,10,0 |
msg_INTEL_HPT db 'Haswell',13,10,0 |
msg_INTEL_82801F db '82801F',13,10,0 |
msg_INTEL_63XXESB db '631x/632xESB',13,10,0 |
msg_INTEL_82801G db '82801G', 13,10,0 |
msg_INTEL_82801H db '82801H', 13,10,0 |
msg_INTEL_82801I db '82801I', 13,10,0 |
msg_INTEL_82801JI db '82801JI',13,10,0 |
msg_INTEL_82801JD db '82801JD',13,10,0 |
msg_INTEL_PCH db 'PCH',13,10,0 |
msg_INTEL_PCH2 db 'PCH2',13,10,0 |
msg_INTEL_SCH db 'Poulsbo',13,10,0 |
msg_INTEL_SCH2 db 'Oaktrail',13,10,0 |
msg_INTEL_82801_UNK1 db '82801_UNK1', 13,10,0 |
msg_INTEL_82801_UNK2 db '82801_UNK2', 13,10,0 |
msg_NVidia db 'NVidia ',0 |
msg_NVIDIA_MCP51 db 'MCP51', 13,10,0 |
msg_NVIDIA_MCP55 db 'MCP55', 13,10,0 |
msg_NVIDIA_MCP61 db 'MCP61', 13,10,0 |
msg_NVIDIA_MCP65 db 'MCP65', 13,10,0 |
msg_NVIDIA_MCP67 db 'MCP67', 13,10,0 |
msg_NVIDIA_MCP73 db 'MCP73', 13,10,0 |
msg_NVIDIA_MCP78 db 'MCP78', 13,10,0 |
msg_NVIDIA_MCP79 db 'MCP79', 13,10,0 |
msg_NVIDIA_MCP89 db 'MCP89', 13,10,0 |
msg_NVIDIA_0BE2 db '(0x0be2)', 13,10,0 |
msg_NVIDIA_0BE3 db '(0x0be3)', 13,10,0 |
msg_NVIDIA_0BE4 db '(0x0be4)', 13,10,0 |
msg_NVIDIA_GT100 db 'GT100', 13,10,0 |
msg_NVIDIA_GT104 db 'GT104', 13,10,0 |
msg_NVIDIA_GT106 db 'GT106', 13,10,0 |
msg_NVIDIA_GT108 db 'GT108', 13,10,0 |
msg_NVIDIA_GT116 db 'GT116', 13,10,0 |
msg_NVIDIA_GF119 db 'GF119', 13,10,0 |
msg_NVIDIA_GF110 db 'GF110', 13,10,0 |
msg_ATI db 'ATI ',0 |
msg_ATI_SB450 db 'SB450', 13,10,0 |
msg_ATI_SB600 db 'SB600', 13,10,0 |
msg_ATI_HDMI db 'ATI HDMI ',0 |
msg_ATI_RS600 db 'RS600', 13,10,0 |
msg_ATI_RS690 db 'RS690', 13,10,0 |
msg_ATI_RS780 db 'RS780', 13,10,0 |
msg_ATI_RS_UNK1 db 'RS_UNK1', 13,10,0 |
msg_ATI_R600 db 'R600', 13,10,0 |
msg_ATI_RV610 db 'RV610', 13,10,0 |
msg_ATI_RV620 db 'RV620', 13,10,0 |
msg_ATI_RV630 db 'RV630', 13,10,0 |
msg_ATI_RV635 db 'RV635', 13,10,0 |
msg_ATI_RV670 db 'RV670', 13,10,0 |
msg_ATI_RV710 db 'RV710', 13,10,0 |
msg_ATI_RV730 db 'RV730', 13,10,0 |
msg_ATI_RV740 db 'RV740', 13,10,0 |
msg_ATI_RV770 db 'RV770', 13,10,0 |
msg_AMD db 'AMD ',0 |
msg_AMD_HUDSON db 'Hudson', 13,10,0 |
msg_VIA db 'VIA ',0 |
msg_VIA_VT82XX db 'VT8251/8237A', 13,10,0 |
msg_VIA_VT61XX db 'GFX VT6122/VX11', 13,10,0 |
msg_VIA_VT71XX db 'GFX VT7122/VX900', 13,10,0 |
msg_SIS db 'SIS ',0 |
msg_SIS_966 db '966', 13,10,0 |
msg_ULI db 'ULI ',0 |
msg_ULI_M5461 db 'M5461', 13,10,0 |
msg_TERA db 'Teradici ',0 |
msg_TERA_UNK1 db 'UNK1', 13,10,0 |
msg_CREATIVE db 'Creative ',0 |
msg_CREATIVE_CA0110_IBG db 'CA0110-IBG',13,10,0 ;SB X-Fi Xtreme Audio |
msg_CREATIVE_SOUND_CORE3D db 'Sound Core3D' |
msg_RDC db 'RDC ',0 |
msg_RDC_R3010 db 'R3010', 13,10,0 |
msg_VMWARE db 'VMware ',0 |
msg_VMWARE_UNK1 db 'UNK1', 13,10,0 |
szKernel db 'KERNEL',0 |
sz_sound_srv db 'SOUND',0 |
msgInit db 'detect hardware...',13,10,0 |
msgFail db 'device not found',13,10,0 |
msgAttchIRQ db 'IRQ line not supported', 13,10,0 |
msgInvIRQ db 'IRQ line not assigned or invalid', 13,10,0 |
msgPlay db 'start play', 13,10,0 |
msgStop db 'stop play', 13,10,0 |
msgSetChannelVolume db 'Set Channel Volume', 13,10,0 |
msgIRQ db 'HDA IRQ', 13,10,0 |
msgInitCtrl db 'init controller',13,10,0 |
msgPrimBuff db 'create primary buffer ...',0 |
msgDone db 'done',13,10,0 |
msgRemap db 'Remap IRQ',13,10,0 |
msgOk db 'service installed',13,10,0 |
msgCold db 'cold reset',13,10,0 |
msgHDARFail db 'controller not ready',13,10,0 |
msgCFail db 'codec not ready',13,10,0 |
msgResetOk db 'reset complete',13,10,0 |
msgPciCmd db 'PCI command ',0 |
msgPciStat db 'PCI status ',0 |
msgHDALowMMIo db 'lower mmio base ',0 |
msgHDAUpMMIo db 'upper mmio base ',0 |
msgIrqMap db 'HDA irq map as ',0 |
;Asper [ |
if DEBUG |
msgCodecMask db 'codec_mask = ',0 |
msgNoCodecsFound db 'no codecs found!',13,10,0 |
msgHDASnoopDisabled db 'HDA snoop disabled, enabling ... ',0 |
msg_OK db 'OK',13,10,0 |
msg_Fail db 'Failed',13,10,0 |
msgSpuriousResponce db 'spurious responce ',0 |
emsgInvalidAFGSubtree db 'Invalid AFG subtree',13,10,0 |
emsgConnListNotAvailable db 'connection list not available for ',0 |
msgUnmuteOut db 'UNMUTE OUT: NID=',0 |
msgUnmuteIn db 'UNMUTE IN: NID=',0 |
msgGetResponceTimeout db 'get_response timeout: ',0 |
msgVal db ' val=',0 |
emsgBusResetFatalComm db 'resetting BUS due to fatal communication error',13,10,0 |
msgCodecOK db 'codec probed OK',13,10,0 |
msgCodecError db 'codec probe error disabling it...',13,10,0 |
emsgNoAFGorMFGFound db 'no AFG or MFG node found',13,10,0 |
emsgNoMem db 'hda_codec: cannot malloc',13,10,0 |
msgConnect db 'CONNECT: NID=',0 |
msgIdx db ' IDX=',0 |
msgSkipDigitalOutNode db 'Skip Digital OUT node ',0 |
msgAudOutFound db 'AUD_OUT found ',0 |
emsgNoParserAvailable db 'No codec parser is available',13,10,0 |
emsgNoProperOutputPathFound db 'hda_generic: no proper output path found',13,10,0 |
emsgInvConnList db 'hda_codec: invalid CONNECT_LIST verb ',0 |
emsgInvDepRangeVal db 'hda_codec: invalid dep_range_val ',0 |
emsgTooManyConns db 'Too many connections',13,10,0 |
emsgNoVolCtrl db 'No volume control',13,10,0 |
msgHDACodecSetupStream db 'hda_codec_setup_stream: NID=',0 |
msgStream db 'stream=',0 |
msgChannel db 'channel=',0 |
msgFormat db 'format=',0 |
msgPollingCodecOnce db 'polling the codec once',13,10,0 ;Asper~ |
msgSwitchToPollMode db 'switching to polling mode',13,10,0 ;Asper~ |
msgUnsolEvent db 'Unsolicited event!',13,10,0 |
strSemicolon db ':',0 |
msgSETUP_FG_NODES db 'Setup FG nodes = start_nid:total_nodes = ',0 |
msgFG_TYPE db 'FG type = ',0 |
msgPinCfgs db 'Pin configurations:',13,10,0 |
msgWCaps db 'Widget capabilities:',13,10,0 |
msgCAd db 'CAd = ',0 |
msgTCSEL db 'PCI TCSEL ',0 |
msgTV db 'HDA test version ',TEST_VERSION_NUMBER,13,10,0 |
msgGCap db 'GCAP = ',0 |
end if |
if USE_SINGLE_MODE |
msgSingleMode db 'Single mode !',13,10,0 |
msgIRS db 'IRS=',0 |
msgSendCmdTimeout db 'send_cmd timeout: IRS=',0 |
else |
msgNormalMode db 'Normal mode !',13,10,0 |
end if |
if DEBUG |
msgYAHOO2 db 'YAHOO2: ',0 |
msgMaxVolume db 'MaxVolume: ',0 |
msgNewVolume db 'NewVolume: ',0 |
msgVerbQuery db 'Q: ',0 |
msgVerbAnswer db 'A: ',0 |
msgPin_Nid db 'Pin Nid = ',0 |
msgPin_Ctl db 'Pin Control = ',0 |
msgPin_Caps db 'Pin Capabilities = ',0 |
msgDef_Cfg db 'Pin def_cfg = ',0 |
msgAmp_Out_Caps db 'Pin Amp Out caps = ',0 |
msgAmpVal db 'Amp val = ',0 |
msgEnableEAPD db 'Enable EAPD: NID=',0 |
msgBeeperNid db 'Beeper found: NID=',0 |
msgBeeperValue db 'Beeper initial value: ',0 |
msgBeepNow db 'Beep!',13,10,0 |
end if |
;] Asper |
section '.data' data readable writable align 16 |
codec CODEC |
ctrl AC_CNTRL |
;Asper: BDL must be aligned to 128 according to HDA specification. |
pcmout_bdl rd 1 |
buff_list rd 32 |
driver_type rd 1 |