Subversion Repositories Kolibri OS

Compare Revisions

Ignore whitespace Rev 3082 → Rev 3083

/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