forked from KolibriOS/kolibrios
kolibri-acpi:update
git-svn-id: svn://kolibrios.org@4423 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
parent
a461856fa1
commit
3ed9acd41a
293
kernel/branches/Kolibri-acpi/blkdev/bd_drv.inc
Normal file
293
kernel/branches/Kolibri-acpi/blkdev/bd_drv.inc
Normal file
@ -0,0 +1,293 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision: 4420 $
|
||||
|
||||
|
||||
; Access through BIOS by diamond
|
||||
iglobal
|
||||
align 4
|
||||
bd_callbacks:
|
||||
dd bd_callbacks.end - bd_callbacks ; strucsize
|
||||
dd 0 ; no close function
|
||||
dd 0 ; no closemedia function
|
||||
dd bd_querymedia
|
||||
dd bd_read_interface
|
||||
dd bd_write_interface
|
||||
dd 0 ; no flush function
|
||||
dd 0 ; use default cache size
|
||||
.end:
|
||||
endg
|
||||
|
||||
proc bd_read_interface stdcall uses edi, \
|
||||
userdata, buffer, startsector:qword, numsectors
|
||||
; userdata = old [hdpos] = 80h + index in NumBiosDisks
|
||||
; buffer = pointer to buffer for data
|
||||
; startsector = 64-bit start sector
|
||||
; numsectors = pointer to number of sectors on input,
|
||||
; must be filled with number of sectors really read
|
||||
locals
|
||||
sectors_todo dd ?
|
||||
endl
|
||||
; 1. Initialize number of sectors: get number of requested sectors
|
||||
; and say that no sectors were read yet.
|
||||
mov ecx, [numsectors]
|
||||
mov eax, [ecx]
|
||||
mov dword [ecx], 0
|
||||
mov [sectors_todo], eax
|
||||
; 2. Acquire the global lock.
|
||||
mov ecx, ide_mutex
|
||||
call mutex_lock
|
||||
; 3. Convert parameters to the form suitable for worker procedures.
|
||||
; Underlying procedures do not know about 64-bit sectors.
|
||||
; Worker procedures use global variables and edi for [buffer].
|
||||
cmp dword [startsector+4], 0
|
||||
jnz .fail
|
||||
and [hd_error], 0
|
||||
mov eax, [userdata]
|
||||
mov [hdpos], eax
|
||||
mov eax, dword [startsector]
|
||||
mov edi, [buffer]
|
||||
; 4. Worker procedures take one sectors per time, so loop over all sectors to read.
|
||||
.sectors_loop:
|
||||
call bd_read
|
||||
cmp [hd_error], 0
|
||||
jnz .fail
|
||||
mov ecx, [numsectors]
|
||||
inc dword [ecx] ; one more sector is read
|
||||
dec [sectors_todo]
|
||||
jz .done
|
||||
inc eax
|
||||
jnz .sectors_loop
|
||||
; 5. Loop is done, either due to error or because everything is done.
|
||||
; Release the global lock and return the corresponding status.
|
||||
.fail:
|
||||
mov ecx, ide_mutex
|
||||
call mutex_unlock
|
||||
or eax, -1
|
||||
ret
|
||||
.done:
|
||||
mov ecx, ide_mutex
|
||||
call mutex_unlock
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
|
||||
proc bd_write_interface stdcall uses esi edi, \
|
||||
userdata, buffer, startsector:qword, numsectors
|
||||
; userdata = old [hdpos] = 80h + index in NumBiosDisks
|
||||
; buffer = pointer to buffer with data
|
||||
; startsector = 64-bit start sector
|
||||
; numsectors = pointer to number of sectors on input,
|
||||
; must be filled with number of sectors really written
|
||||
locals
|
||||
sectors_todo dd ?
|
||||
endl
|
||||
; 1. Initialize number of sectors: get number of requested sectors
|
||||
; and say that no sectors were read yet.
|
||||
mov ecx, [numsectors]
|
||||
mov eax, [ecx]
|
||||
mov dword [ecx], 0
|
||||
mov [sectors_todo], eax
|
||||
; 2. Acquire the global lock.
|
||||
mov ecx, ide_mutex
|
||||
call mutex_lock
|
||||
; 3. Convert parameters to the form suitable for worker procedures.
|
||||
; Underlying procedures do not know about 64-bit sectors.
|
||||
; Worker procedures use global variables and esi for [buffer].
|
||||
cmp dword [startsector+4], 0
|
||||
jnz .fail
|
||||
and [hd_error], 0
|
||||
mov eax, [userdata]
|
||||
mov [hdpos], eax
|
||||
mov esi, [buffer]
|
||||
lea edi, [startsector]
|
||||
mov [cache_chain_ptr], edi
|
||||
; 4. Worker procedures take max 16 sectors per time,
|
||||
; loop until all sectors will be processed.
|
||||
.sectors_loop:
|
||||
mov ecx, 16
|
||||
cmp ecx, [sectors_todo]
|
||||
jbe @f
|
||||
mov ecx, [sectors_todo]
|
||||
@@:
|
||||
mov [cache_chain_size], cl
|
||||
call bd_write_cache_chain
|
||||
cmp [hd_error], 0
|
||||
jnz .fail
|
||||
movzx ecx, [cache_chain_size]
|
||||
mov eax, [numsectors]
|
||||
add [eax], ecx
|
||||
sub [sectors_todo], ecx
|
||||
jz .done
|
||||
add [edi], ecx
|
||||
jc .fail
|
||||
shl ecx, 9
|
||||
add esi, ecx
|
||||
jmp .sectors_loop
|
||||
; 5. Loop is done, either due to error or because everything is done.
|
||||
; Release the global lock and return the corresponding status.
|
||||
.fail:
|
||||
mov ecx, ide_mutex
|
||||
call mutex_unlock
|
||||
or eax, -1
|
||||
ret
|
||||
.done:
|
||||
mov ecx, ide_mutex
|
||||
call mutex_unlock
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
|
||||
; This is a stub.
|
||||
proc bd_querymedia stdcall, hd_data, mediainfo
|
||||
mov eax, [mediainfo]
|
||||
mov [eax+DISKMEDIAINFO.Flags], 0
|
||||
mov [eax+DISKMEDIAINFO.SectorSize], 512
|
||||
or dword [eax+DISKMEDIAINFO.Capacity], 0xFFFFFFFF
|
||||
or dword [eax+DISKMEDIAINFO.Capacity+4], 0xFFFFFFFF
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
; \begin{diamond}
|
||||
uglobal
|
||||
bios_hdpos dd 0 ; 0 is invalid value for [hdpos]
|
||||
bios_cur_sector dd ?
|
||||
bios_read_len dd ?
|
||||
endg
|
||||
;-----------------------------------------------------------------------------
|
||||
align 4
|
||||
bd_read:
|
||||
push eax
|
||||
push edx
|
||||
mov edx, [bios_hdpos]
|
||||
cmp edx, [hdpos]
|
||||
jne .notread
|
||||
mov edx, [bios_cur_sector]
|
||||
cmp eax, edx
|
||||
jb .notread
|
||||
add edx, [bios_read_len]
|
||||
dec edx
|
||||
cmp eax, edx
|
||||
ja .notread
|
||||
sub eax, [bios_cur_sector]
|
||||
shl eax, 9
|
||||
add eax, (OS_BASE+0x9A000)
|
||||
push ecx esi
|
||||
mov esi, eax
|
||||
mov ecx, 512/4
|
||||
cld
|
||||
rep movsd
|
||||
pop esi ecx
|
||||
pop edx
|
||||
pop eax
|
||||
ret
|
||||
.notread:
|
||||
push ecx
|
||||
mov dl, 42h
|
||||
mov ecx, 16
|
||||
call int13_call
|
||||
pop ecx
|
||||
test eax, eax
|
||||
jnz .v86err
|
||||
test edx, edx
|
||||
jz .readerr
|
||||
mov [bios_read_len], edx
|
||||
mov edx, [hdpos]
|
||||
mov [bios_hdpos], edx
|
||||
pop edx
|
||||
pop eax
|
||||
mov [bios_cur_sector], eax
|
||||
jmp bd_read
|
||||
.readerr:
|
||||
.v86err:
|
||||
mov [hd_error], 1
|
||||
jmp hd_read_error
|
||||
;-----------------------------------------------------------------------------
|
||||
align 4
|
||||
bd_write_cache_chain:
|
||||
pusha
|
||||
mov edi, OS_BASE + 0x9A000
|
||||
movzx ecx, [cache_chain_size]
|
||||
push ecx
|
||||
shl ecx, 9-2
|
||||
rep movsd
|
||||
pop ecx
|
||||
mov dl, 43h
|
||||
mov eax, [cache_chain_ptr]
|
||||
mov eax, [eax]
|
||||
call int13_call
|
||||
test eax, eax
|
||||
jnz .v86err
|
||||
cmp edx, ecx
|
||||
jnz .writeerr
|
||||
popa
|
||||
ret
|
||||
.v86err:
|
||||
.writeerr:
|
||||
popa
|
||||
mov [hd_error], 1
|
||||
jmp hd_write_error
|
||||
;-----------------------------------------------------------------------------
|
||||
uglobal
|
||||
int13_regs_in rb sizeof.v86_regs
|
||||
int13_regs_out rb sizeof.v86_regs
|
||||
endg
|
||||
;-----------------------------------------------------------------------------
|
||||
align 4
|
||||
int13_call:
|
||||
; Because this code uses fixed addresses,
|
||||
; it can not be run simultaniously by many threads.
|
||||
; In current implementation it is protected by common mutex 'ide_status'
|
||||
mov word [OS_BASE + 510h], 10h ; packet length
|
||||
mov word [OS_BASE + 512h], cx ; number of sectors
|
||||
mov dword [OS_BASE + 514h], 9A000000h ; buffer 9A00:0000
|
||||
mov dword [OS_BASE + 518h], eax
|
||||
and dword [OS_BASE + 51Ch], 0
|
||||
push ebx ecx esi edi
|
||||
mov ebx, int13_regs_in
|
||||
mov edi, ebx
|
||||
mov ecx, sizeof.v86_regs/4
|
||||
xor eax, eax
|
||||
rep stosd
|
||||
mov byte [ebx+v86_regs.eax+1], dl
|
||||
mov eax, [hdpos]
|
||||
lea eax, [BiosDisksData+(eax-80h)*4]
|
||||
mov dl, [eax]
|
||||
mov byte [ebx+v86_regs.edx], dl
|
||||
movzx edx, byte [eax+1]
|
||||
; mov dl, 5
|
||||
test edx, edx
|
||||
jnz .hasirq
|
||||
dec edx
|
||||
jmp @f
|
||||
.hasirq:
|
||||
pushad
|
||||
stdcall enable_irq, edx
|
||||
popad
|
||||
@@:
|
||||
mov word [ebx+v86_regs.esi], 510h
|
||||
mov word [ebx+v86_regs.ss], 9000h
|
||||
mov word [ebx+v86_regs.esp], 0A000h
|
||||
mov word [ebx+v86_regs.eip], 500h
|
||||
mov [ebx+v86_regs.eflags], 20200h
|
||||
mov esi, [sys_v86_machine]
|
||||
mov ecx, 0x502
|
||||
push fs
|
||||
call v86_start
|
||||
pop fs
|
||||
and [bios_hdpos], 0
|
||||
pop edi esi ecx ebx
|
||||
movzx edx, byte [OS_BASE + 512h]
|
||||
test byte [int13_regs_out+v86_regs.eflags], 1
|
||||
jnz @f
|
||||
mov edx, ecx
|
||||
@@:
|
||||
ret
|
||||
; \end{diamond}
|
@ -10,7 +10,6 @@ $Revision$
|
||||
|
||||
; Low-level driver for HDD access
|
||||
; DMA support by Mario79
|
||||
; Access through BIOS by diamond
|
||||
; LBA48 support by Mario79
|
||||
;-----------------------------------------------------------------------------
|
||||
struct HD_DATA
|
||||
@ -32,17 +31,6 @@ ide_callbacks:
|
||||
dd 0 ; use default cache size
|
||||
.end:
|
||||
|
||||
bd_callbacks:
|
||||
dd bd_callbacks.end - bd_callbacks ; strucsize
|
||||
dd 0 ; no close function
|
||||
dd 0 ; no closemedia function
|
||||
dd bd_querymedia
|
||||
dd bd_read_interface
|
||||
dd bd_write_interface
|
||||
dd 0 ; no flush function
|
||||
dd 0 ; use default cache size
|
||||
.end:
|
||||
|
||||
hd0_data HD_DATA ?, 0, 1
|
||||
hd1_data HD_DATA ?, 0x10, 2
|
||||
hd2_data HD_DATA ?, 0, 3
|
||||
@ -112,6 +100,22 @@ endl
|
||||
ja .nodma
|
||||
cmp [dma_hdd], 1
|
||||
jnz .nodma
|
||||
;--------------------------------------
|
||||
push eax
|
||||
mov eax, [hd_address_table]
|
||||
cmp [hdbase], eax ; 0x1F0
|
||||
pop eax
|
||||
jnz @f
|
||||
|
||||
test [DRIVE_DATA+1], byte 10100000b
|
||||
jnz .nodma
|
||||
|
||||
jmp .dma
|
||||
@@:
|
||||
test [DRIVE_DATA+1], byte 1010b
|
||||
jnz .nodma
|
||||
.dma:
|
||||
;--------------------------------------
|
||||
call hd_read_dma
|
||||
jmp @f
|
||||
.nodma:
|
||||
@ -204,6 +208,22 @@ endl
|
||||
jae .nodma
|
||||
cmp [dma_hdd], 1
|
||||
jnz .nodma
|
||||
;--------------------------------------
|
||||
push eax
|
||||
mov eax, [hd_address_table]
|
||||
cmp [hdbase], eax ; 0x1F0
|
||||
pop eax
|
||||
jnz @f
|
||||
|
||||
test [DRIVE_DATA+1], byte 10100000b
|
||||
jnz .nodma
|
||||
|
||||
jmp .dma
|
||||
@@:
|
||||
test [DRIVE_DATA+1], byte 1010b
|
||||
jnz .nodma
|
||||
.dma:
|
||||
;--------------------------------------
|
||||
call cache_write_dma
|
||||
jmp .common
|
||||
.nodma:
|
||||
@ -251,137 +271,6 @@ proc ide_querymedia stdcall, hd_data, mediainfo
|
||||
ret
|
||||
endp
|
||||
|
||||
proc bd_read_interface stdcall uses edi, \
|
||||
userdata, buffer, startsector:qword, numsectors
|
||||
; userdata = old [hdpos] = 80h + index in NumBiosDisks
|
||||
; buffer = pointer to buffer for data
|
||||
; startsector = 64-bit start sector
|
||||
; numsectors = pointer to number of sectors on input,
|
||||
; must be filled with number of sectors really read
|
||||
locals
|
||||
sectors_todo dd ?
|
||||
endl
|
||||
; 1. Initialize number of sectors: get number of requested sectors
|
||||
; and say that no sectors were read yet.
|
||||
mov ecx, [numsectors]
|
||||
mov eax, [ecx]
|
||||
mov dword [ecx], 0
|
||||
mov [sectors_todo], eax
|
||||
; 2. Acquire the global lock.
|
||||
mov ecx, ide_mutex
|
||||
call mutex_lock
|
||||
; 3. Convert parameters to the form suitable for worker procedures.
|
||||
; Underlying procedures do not know about 64-bit sectors.
|
||||
; Worker procedures use global variables and edi for [buffer].
|
||||
cmp dword [startsector+4], 0
|
||||
jnz .fail
|
||||
and [hd_error], 0
|
||||
mov eax, [userdata]
|
||||
mov [hdpos], eax
|
||||
mov eax, dword [startsector]
|
||||
mov edi, [buffer]
|
||||
; 4. Worker procedures take one sectors per time, so loop over all sectors to read.
|
||||
.sectors_loop:
|
||||
call bd_read
|
||||
cmp [hd_error], 0
|
||||
jnz .fail
|
||||
mov ecx, [numsectors]
|
||||
inc dword [ecx] ; one more sector is read
|
||||
dec [sectors_todo]
|
||||
jz .done
|
||||
inc eax
|
||||
jnz .sectors_loop
|
||||
; 5. Loop is done, either due to error or because everything is done.
|
||||
; Release the global lock and return the corresponding status.
|
||||
.fail:
|
||||
mov ecx, ide_mutex
|
||||
call mutex_unlock
|
||||
or eax, -1
|
||||
ret
|
||||
.done:
|
||||
mov ecx, ide_mutex
|
||||
call mutex_unlock
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
|
||||
proc bd_write_interface stdcall uses esi edi, \
|
||||
userdata, buffer, startsector:qword, numsectors
|
||||
; userdata = old [hdpos] = 80h + index in NumBiosDisks
|
||||
; buffer = pointer to buffer with data
|
||||
; startsector = 64-bit start sector
|
||||
; numsectors = pointer to number of sectors on input,
|
||||
; must be filled with number of sectors really written
|
||||
locals
|
||||
sectors_todo dd ?
|
||||
endl
|
||||
; 1. Initialize number of sectors: get number of requested sectors
|
||||
; and say that no sectors were read yet.
|
||||
mov ecx, [numsectors]
|
||||
mov eax, [ecx]
|
||||
mov dword [ecx], 0
|
||||
mov [sectors_todo], eax
|
||||
; 2. Acquire the global lock.
|
||||
mov ecx, ide_mutex
|
||||
call mutex_lock
|
||||
; 3. Convert parameters to the form suitable for worker procedures.
|
||||
; Underlying procedures do not know about 64-bit sectors.
|
||||
; Worker procedures use global variables and esi for [buffer].
|
||||
cmp dword [startsector+4], 0
|
||||
jnz .fail
|
||||
and [hd_error], 0
|
||||
mov eax, [userdata]
|
||||
mov [hdpos], eax
|
||||
mov esi, [buffer]
|
||||
lea edi, [startsector]
|
||||
mov [cache_chain_ptr], edi
|
||||
; 4. Worker procedures take max 16 sectors per time,
|
||||
; loop until all sectors will be processed.
|
||||
.sectors_loop:
|
||||
mov ecx, 16
|
||||
cmp ecx, [sectors_todo]
|
||||
jbe @f
|
||||
mov ecx, [sectors_todo]
|
||||
@@:
|
||||
mov [cache_chain_size], cl
|
||||
call bd_write_cache_chain
|
||||
cmp [hd_error], 0
|
||||
jnz .fail
|
||||
movzx ecx, [cache_chain_size]
|
||||
mov eax, [numsectors]
|
||||
add [eax], ecx
|
||||
sub [sectors_todo], ecx
|
||||
jz .done
|
||||
add [edi], ecx
|
||||
jc .fail
|
||||
shl ecx, 9
|
||||
add esi, ecx
|
||||
jmp .sectors_loop
|
||||
; 5. Loop is done, either due to error or because everything is done.
|
||||
; Release the global lock and return the corresponding status.
|
||||
.fail:
|
||||
mov ecx, ide_mutex
|
||||
call mutex_unlock
|
||||
or eax, -1
|
||||
ret
|
||||
.done:
|
||||
mov ecx, ide_mutex
|
||||
call mutex_unlock
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
|
||||
; This is a stub.
|
||||
proc bd_querymedia stdcall, hd_data, mediainfo
|
||||
mov eax, [mediainfo]
|
||||
mov [eax+DISKMEDIAINFO.Flags], 0
|
||||
mov [eax+DISKMEDIAINFO.SectorSize], 512
|
||||
or dword [eax+DISKMEDIAINFO.Capacity], 0xFFFFFFFF
|
||||
or dword [eax+DISKMEDIAINFO.Capacity+4], 0xFFFFFFFF
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
align 4
|
||||
; input: eax = sector, edi -> buffer
|
||||
@ -803,23 +692,37 @@ IDE_irq_14_handler:
|
||||
pushfd
|
||||
cli
|
||||
pushad
|
||||
; clear Bus Master IDE Command register
|
||||
mov [IDE_common_irq_param], 0
|
||||
mov dx, [IDEContrRegsBaseAddr]
|
||||
mov al, 0
|
||||
out dx, al
|
||||
; test whether it is our interrupt?
|
||||
add edx, 2
|
||||
in al, dx
|
||||
test al, 100b
|
||||
jz @f
|
||||
; clear Bus Master IDE Status register
|
||||
; clear Interrupt bit
|
||||
add edx, 2
|
||||
mov al, 4 ; 100b
|
||||
out dx, al
|
||||
|
||||
; clear Bus Master IDE Command register
|
||||
sub edx, 2
|
||||
xor eax, eax
|
||||
out dx, al
|
||||
; read status register and remove the interrupt request
|
||||
mov edx, [hdbase]
|
||||
add edx, 0x7
|
||||
in al, dx
|
||||
popad
|
||||
popfd
|
||||
mov al, 1
|
||||
ret
|
||||
;--------------------------------------
|
||||
align 4
|
||||
@@:
|
||||
popad
|
||||
popfd
|
||||
;--------------------------------------
|
||||
align 4
|
||||
.exit:
|
||||
mov al, 1
|
||||
mov al, 0
|
||||
ret
|
||||
;-----------------------------------------------------------------------------
|
||||
align 4
|
||||
@ -830,24 +733,38 @@ IDE_irq_15_handler:
|
||||
pushfd
|
||||
cli
|
||||
pushad
|
||||
; clear Bus Master IDE Command register
|
||||
mov [IDE_common_irq_param], 0
|
||||
mov dx, [IDEContrRegsBaseAddr]
|
||||
add dx, 8
|
||||
mov al, 0
|
||||
out dx, al
|
||||
; test whether it is our interrupt?
|
||||
add edx, 2
|
||||
in al, dx
|
||||
test al, 100b
|
||||
jz @f
|
||||
; clear Bus Master IDE Status register
|
||||
; clear Interrupt bit
|
||||
add edx, 2
|
||||
mov al, 4 ; 100b
|
||||
out dx, al
|
||||
|
||||
; clear Bus Master IDE Command register
|
||||
sub edx, 2
|
||||
mov al, 0
|
||||
out dx, al
|
||||
; read status register and remove the interrupt request
|
||||
mov edx, [hdbase]
|
||||
add edx, 0x7
|
||||
in al, dx
|
||||
popad
|
||||
popfd
|
||||
mov al, 1
|
||||
ret
|
||||
;--------------------------------------
|
||||
align 4
|
||||
@@:
|
||||
popad
|
||||
popfd
|
||||
;--------------------------------------
|
||||
align 4
|
||||
.exit:
|
||||
mov al, 1
|
||||
mov al, 0
|
||||
ret
|
||||
;-----------------------------------------------------------------------------
|
||||
align 4
|
||||
@ -858,32 +775,46 @@ IDE_common_irq_handler:
|
||||
pushfd
|
||||
cli
|
||||
pushad
|
||||
; clear Bus Master IDE Command register
|
||||
xor ebx, ebx
|
||||
mov dx, [IDEContrRegsBaseAddr]
|
||||
mov eax, IDE_common_irq_param
|
||||
cmp [eax], irq14_num
|
||||
mov [eax], bl
|
||||
xor eax, eax
|
||||
je @f
|
||||
|
||||
add dx, 8
|
||||
;--------------------------------------
|
||||
align 4
|
||||
@@:
|
||||
out dx, al
|
||||
; test whether it is our interrupt?
|
||||
add edx, 2
|
||||
in al, dx
|
||||
test al, 100b
|
||||
jz @f
|
||||
; clear Bus Master IDE Status register
|
||||
; clear Interrupt bit
|
||||
add edx, 2
|
||||
mov al, 4 ; 100b
|
||||
out dx, al
|
||||
|
||||
; clear Bus Master IDE Command register
|
||||
sub edx, 2
|
||||
xor eax, eax
|
||||
out dx, al
|
||||
; read status register and remove the interrupt request
|
||||
mov edx, [hdbase]
|
||||
add edx, 0x7
|
||||
in al, dx
|
||||
popad
|
||||
popfd
|
||||
mov al, 1
|
||||
ret
|
||||
;--------------------------------------
|
||||
align 4
|
||||
@@:
|
||||
popad
|
||||
popfd
|
||||
;--------------------------------------
|
||||
align 4
|
||||
.exit:
|
||||
mov al, 1
|
||||
mov al, 0
|
||||
ret
|
||||
;-----------------------------------------------------------------------------
|
||||
align 4
|
||||
@ -1252,139 +1183,3 @@ IDE_BAR2_val dw ?
|
||||
IDE_BAR3_val dw ?
|
||||
endg
|
||||
;-----------------------------------------------------------------------------
|
||||
; \begin{diamond}
|
||||
uglobal
|
||||
bios_hdpos dd 0 ; 0 is invalid value for [hdpos]
|
||||
bios_cur_sector dd ?
|
||||
bios_read_len dd ?
|
||||
endg
|
||||
;-----------------------------------------------------------------------------
|
||||
align 4
|
||||
bd_read:
|
||||
push eax
|
||||
push edx
|
||||
mov edx, [bios_hdpos]
|
||||
cmp edx, [hdpos]
|
||||
jne .notread
|
||||
mov edx, [bios_cur_sector]
|
||||
cmp eax, edx
|
||||
jb .notread
|
||||
add edx, [bios_read_len]
|
||||
dec edx
|
||||
cmp eax, edx
|
||||
ja .notread
|
||||
sub eax, [bios_cur_sector]
|
||||
shl eax, 9
|
||||
add eax, (OS_BASE+0x9A000)
|
||||
push ecx esi
|
||||
mov esi, eax
|
||||
mov ecx, 512/4
|
||||
cld
|
||||
rep movsd
|
||||
pop esi ecx
|
||||
pop edx
|
||||
pop eax
|
||||
ret
|
||||
.notread:
|
||||
push ecx
|
||||
mov dl, 42h
|
||||
mov ecx, 16
|
||||
call int13_call
|
||||
pop ecx
|
||||
test eax, eax
|
||||
jnz .v86err
|
||||
test edx, edx
|
||||
jz .readerr
|
||||
mov [bios_read_len], edx
|
||||
mov edx, [hdpos]
|
||||
mov [bios_hdpos], edx
|
||||
pop edx
|
||||
pop eax
|
||||
mov [bios_cur_sector], eax
|
||||
jmp bd_read
|
||||
.readerr:
|
||||
.v86err:
|
||||
mov [hd_error], 1
|
||||
jmp hd_read_error
|
||||
;-----------------------------------------------------------------------------
|
||||
align 4
|
||||
bd_write_cache_chain:
|
||||
pusha
|
||||
mov edi, OS_BASE + 0x9A000
|
||||
movzx ecx, [cache_chain_size]
|
||||
push ecx
|
||||
shl ecx, 9-2
|
||||
rep movsd
|
||||
pop ecx
|
||||
mov dl, 43h
|
||||
mov eax, [cache_chain_ptr]
|
||||
mov eax, [eax]
|
||||
call int13_call
|
||||
test eax, eax
|
||||
jnz .v86err
|
||||
cmp edx, ecx
|
||||
jnz .writeerr
|
||||
popa
|
||||
ret
|
||||
.v86err:
|
||||
.writeerr:
|
||||
popa
|
||||
mov [hd_error], 1
|
||||
jmp hd_write_error
|
||||
;-----------------------------------------------------------------------------
|
||||
uglobal
|
||||
int13_regs_in rb sizeof.v86_regs
|
||||
int13_regs_out rb sizeof.v86_regs
|
||||
endg
|
||||
;-----------------------------------------------------------------------------
|
||||
align 4
|
||||
int13_call:
|
||||
; Because this code uses fixed addresses,
|
||||
; it can not be run simultaniously by many threads.
|
||||
; In current implementation it is protected by common mutex 'ide_status'
|
||||
mov word [OS_BASE + 510h], 10h ; packet length
|
||||
mov word [OS_BASE + 512h], cx ; number of sectors
|
||||
mov dword [OS_BASE + 514h], 9A000000h ; buffer 9A00:0000
|
||||
mov dword [OS_BASE + 518h], eax
|
||||
and dword [OS_BASE + 51Ch], 0
|
||||
push ebx ecx esi edi
|
||||
mov ebx, int13_regs_in
|
||||
mov edi, ebx
|
||||
mov ecx, sizeof.v86_regs/4
|
||||
xor eax, eax
|
||||
rep stosd
|
||||
mov byte [ebx+v86_regs.eax+1], dl
|
||||
mov eax, [hdpos]
|
||||
lea eax, [BiosDisksData+(eax-80h)*4]
|
||||
mov dl, [eax]
|
||||
mov byte [ebx+v86_regs.edx], dl
|
||||
movzx edx, byte [eax+1]
|
||||
; mov dl, 5
|
||||
test edx, edx
|
||||
jnz .hasirq
|
||||
dec edx
|
||||
jmp @f
|
||||
.hasirq:
|
||||
pushad
|
||||
stdcall enable_irq, edx
|
||||
popad
|
||||
@@:
|
||||
mov word [ebx+v86_regs.esi], 510h
|
||||
mov word [ebx+v86_regs.ss], 9000h
|
||||
mov word [ebx+v86_regs.esp], 0A000h
|
||||
mov word [ebx+v86_regs.eip], 500h
|
||||
mov [ebx+v86_regs.eflags], 20200h
|
||||
mov esi, [sys_v86_machine]
|
||||
mov ecx, 0x502
|
||||
push fs
|
||||
call v86_start
|
||||
pop fs
|
||||
and [bios_hdpos], 0
|
||||
pop edi esi ecx ebx
|
||||
movzx edx, byte [OS_BASE + 512h]
|
||||
test byte [int13_regs_out+v86_regs.eflags], 1
|
||||
jnz @f
|
||||
mov edx, ecx
|
||||
@@:
|
||||
ret
|
||||
; \end{diamond}
|
||||
|
@ -432,14 +432,14 @@ sayerr:
|
||||
mov [es:BOOT_IDE_PI_16], cx
|
||||
xor si, si ; device index = 0
|
||||
int 0x1A
|
||||
jnc .found
|
||||
jnc .found_1
|
||||
; c) class 1, subclass 1, programming interface 0x85
|
||||
mov ax, 0xB103
|
||||
mov ecx, 1*10000h + 1*100h + 0x85
|
||||
mov [es:BOOT_IDE_PI_16], cx
|
||||
xor si, si ; device index = 0
|
||||
int 0x1A
|
||||
jnc .found
|
||||
jnc .found_1
|
||||
; d) class 1, subclass 1, programming interface 0x8A
|
||||
; This is a Parallel IDE Controller which uses IRQs 14 and 15.
|
||||
mov ax, 0xB103
|
||||
@ -447,7 +447,7 @@ sayerr:
|
||||
mov [es:BOOT_IDE_PI_16], cx
|
||||
xor si, si ; device index = 0
|
||||
int 0x1A
|
||||
jnc .found ; Parallel IDE Controller
|
||||
jnc .found_1 ; Parallel IDE Controller
|
||||
; Controller not found!
|
||||
xor ax, ax
|
||||
mov [es:BOOT_IDE_PI_16], ax
|
||||
|
446
kernel/branches/Kolibri-acpi/bus/usb/common.inc
Normal file
446
kernel/branches/Kolibri-acpi/bus/usb/common.inc
Normal file
@ -0,0 +1,446 @@
|
||||
; Constants and structures that are shared between different parts of
|
||||
; USB subsystem and *HCI drivers.
|
||||
|
||||
; =============================================================================
|
||||
; ================================= Constants =================================
|
||||
; =============================================================================
|
||||
; Version of all structures related to host controllers.
|
||||
; Must be the same in kernel and *hci-drivers.
|
||||
USBHC_VERSION = 1
|
||||
|
||||
; USB device must have at least 100ms of stable power before initializing can
|
||||
; proceed; one timer tick is 10ms, so enforce delay in 10 ticks
|
||||
USB_CONNECT_DELAY = 10
|
||||
; USB requires at least 10 ms for reset signalling. Normally, this is one timer
|
||||
; tick. However, it is possible that we start reset signalling in the end of
|
||||
; interval between timer ticks and then we test time in the start of the next
|
||||
; interval; in this case, the delta between [timer_ticks] is 1, but the real
|
||||
; time passed is significantly less than 10 ms. To avoid this, we add an extra
|
||||
; tick; this guarantees that at least 10 ms have passed.
|
||||
USB_RESET_TIME = 2
|
||||
; USB requires at least 10 ms of reset recovery, a delay between reset
|
||||
; signalling and any commands to device. Add an extra tick for the same reasons
|
||||
; as with the previous constant.
|
||||
USB_RESET_RECOVERY_TIME = 2
|
||||
|
||||
; USB pipe types
|
||||
CONTROL_PIPE = 0
|
||||
ISOCHRONOUS_PIPE = 1
|
||||
BULK_PIPE = 2
|
||||
INTERRUPT_PIPE = 3
|
||||
|
||||
; Status codes for transfer callbacks.
|
||||
; Taken from OHCI as most verbose controller in this sense.
|
||||
USB_STATUS_OK = 0 ; no error
|
||||
USB_STATUS_CRC = 1 ; CRC error
|
||||
USB_STATUS_BITSTUFF = 2 ; bit stuffing violation
|
||||
USB_STATUS_TOGGLE = 3 ; data toggle mismatch
|
||||
USB_STATUS_STALL = 4 ; device returned STALL
|
||||
USB_STATUS_NORESPONSE = 5 ; device not responding
|
||||
USB_STATUS_PIDCHECK = 6 ; invalid PID check bits
|
||||
USB_STATUS_WRONGPID = 7 ; unexpected PID value
|
||||
USB_STATUS_OVERRUN = 8 ; too many data from endpoint
|
||||
USB_STATUS_UNDERRUN = 9 ; too few data from endpoint
|
||||
USB_STATUS_BUFOVERRUN = 12 ; overflow of internal controller buffer
|
||||
USB_STATUS_BUFUNDERRUN = 13 ; underflow of internal controller buffer
|
||||
USB_STATUS_CLOSED = 16 ; pipe closed
|
||||
; either explicitly with USBClosePipe
|
||||
; or implicitly due to device disconnect
|
||||
|
||||
; Possible speeds of USB devices
|
||||
USB_SPEED_FS = 0 ; full-speed
|
||||
USB_SPEED_LS = 1 ; low-speed
|
||||
USB_SPEED_HS = 2 ; high-speed
|
||||
|
||||
; flags for usb_pipe.Flags
|
||||
USB_FLAG_CLOSED = 1 ; pipe is closed, no new transfers
|
||||
; pipe is closed, return error instead of submitting any new transfer
|
||||
USB_FLAG_CAN_FREE = 2
|
||||
; pipe is closed via explicit call to USBClosePipe, so it can be freed without
|
||||
; any driver notification; if this flag is not set, then the pipe is closed due
|
||||
; to device disconnect, so it must remain valid until return from disconnect
|
||||
; callback provided by the driver
|
||||
USB_FLAG_EXTRA_WAIT = 4
|
||||
; The pipe was in wait list, while another event occured;
|
||||
; when the first wait will be done, reinsert the pipe to wait list
|
||||
USB_FLAG_CLOSED_BIT = 0 ; USB_FLAG_CLOSED = 1 shl USB_FLAG_CLOSED_BIT
|
||||
|
||||
; =============================================================================
|
||||
; ================================ Structures =================================
|
||||
; =============================================================================
|
||||
|
||||
; Description of controller-specific data and functions.
|
||||
struct usb_hardware_func
|
||||
Version dd ? ; must be USBHC_VERSION
|
||||
ID dd ? ; '*HCI'
|
||||
DataSize dd ? ; sizeof(*hci_controller)
|
||||
BeforeInit dd ?
|
||||
; Early initialization: take ownership from BIOS.
|
||||
; in: [ebp-4] = (bus shl 8) + devfn
|
||||
Init dd ?
|
||||
; Initialize controller-specific part of controller data.
|
||||
; in: eax -> *hci_controller to initialize, [ebp-4] = (bus shl 8) + devfn
|
||||
; out: eax = 0 <=> failed, otherwise eax -> usb_controller
|
||||
ProcessDeferred dd ?
|
||||
; Called regularly from the main loop of USB thread
|
||||
; (either due to timeout from a previous call, or due to explicit wakeup).
|
||||
; in: esi -> usb_controller
|
||||
; out: eax = maximum timeout for next call (-1 = infinity)
|
||||
SetDeviceAddress dd ?
|
||||
; in: esi -> usb_controller, ebx -> usb_pipe, cl = address
|
||||
GetDeviceAddress dd ?
|
||||
; in: esi -> usb_controller, ebx -> usb_pipe
|
||||
; out: eax = address
|
||||
PortDisable dd ?
|
||||
; Disable the given port in the root hub.
|
||||
; in: esi -> usb_controller, ecx = port (zero-based)
|
||||
InitiateReset dd ?
|
||||
; Start reset signalling on the given port.
|
||||
; in: esi -> usb_controller, ecx = port (zero-based)
|
||||
SetEndpointPacketSize dd ?
|
||||
; in: esi -> usb_controller, ebx -> usb_pipe, ecx = packet size
|
||||
AllocPipe dd ?
|
||||
; out: eax = pointer to allocated usb_pipe
|
||||
FreePipe dd ?
|
||||
; void stdcall with one argument = pointer to previously allocated usb_pipe
|
||||
InitPipe dd ?
|
||||
; in: edi -> usb_pipe for target, ecx -> usb_pipe for config pipe,
|
||||
; esi -> usb_controller, eax -> usb_gtd for the first TD,
|
||||
; [ebp+12] = endpoint, [ebp+16] = maxpacket, [ebp+20] = type
|
||||
UnlinkPipe dd ?
|
||||
; esi -> usb_controller, ebx -> usb_pipe
|
||||
AllocTD dd ?
|
||||
; out: eax = pointer to allocated usb_gtd
|
||||
FreeTD dd ?
|
||||
; void stdcall with one argument = pointer to previously allocated usb_gtd
|
||||
AllocTransfer dd ?
|
||||
; Allocate and initialize one stage of a transfer.
|
||||
; ebx -> usb_pipe, other parameters are passed through the stack:
|
||||
; buffer,size = data to transfer
|
||||
; flags = same as in usb_open_pipe:
|
||||
; bit 0 = allow short transfer, other bits reserved
|
||||
; td = pointer to the current end-of-queue descriptor
|
||||
; direction =
|
||||
; 0000b for normal transfers,
|
||||
; 1000b for control SETUP transfer,
|
||||
; 1101b for control OUT transfer,
|
||||
; 1110b for control IN transfer
|
||||
; returns eax = pointer to the new end-of-queue descriptor
|
||||
; (not included in the queue itself) or 0 on error
|
||||
InsertTransfer dd ?
|
||||
; Activate previously initialized transfer (maybe with multiple stages).
|
||||
; esi -> usb_controller, ebx -> usb_pipe,
|
||||
; [esp+4] -> first usb_gtd for the transfer,
|
||||
; ecx -> last descriptor for the transfer
|
||||
NewDevice dd ?
|
||||
; Initiate configuration of a new device (create pseudo-pipe describing that
|
||||
; device and call usb_new_device).
|
||||
; esi -> usb_controller, eax = speed (one of USB_SPEED_* constants).
|
||||
ends
|
||||
|
||||
; pointers to kernel API functions that are called from *HCI-drivers
|
||||
struct usbhc_func
|
||||
usb_process_gtd dd ?
|
||||
usb_init_static_endpoint dd ?
|
||||
usb_wakeup_if_needed dd ?
|
||||
usb_subscribe_control dd ?
|
||||
usb_subscription_done dd ?
|
||||
usb_allocate_common dd ?
|
||||
usb_free_common dd ?
|
||||
usb_td_to_virt dd ?
|
||||
usb_init_transfer dd ?
|
||||
usb_undo_tds dd ?
|
||||
usb_test_pending_port dd ?
|
||||
usb_get_tt dd ?
|
||||
usb_get_tt_think_time dd ?
|
||||
usb_new_device dd ?
|
||||
usb_disconnect_stage2 dd ?
|
||||
usb_process_wait_lists dd ?
|
||||
usb_unlink_td dd ?
|
||||
usb_is_final_packet dd ?
|
||||
usb_find_ehci_companion dd ?
|
||||
ends
|
||||
|
||||
; Controller descriptor.
|
||||
; This structure represents the common (controller-independent) part
|
||||
; of a controller for the USB code. The corresponding controller-dependent
|
||||
; part *hci_controller is located immediately before usb_controller.
|
||||
struct usb_controller
|
||||
; Two following fields organize all controllers in the global linked list.
|
||||
Next dd ?
|
||||
Prev dd ?
|
||||
HardwareFunc dd ?
|
||||
; Pointer to usb_hardware_func structure with controller-specific functions.
|
||||
NumPorts dd ?
|
||||
; Number of ports in the root hub.
|
||||
PCICoordinates dd ?
|
||||
; Device:function and bus number from PCI.
|
||||
;
|
||||
; The hardware is allowed to cache some data from hardware structures.
|
||||
; Regular operations are designed considering this,
|
||||
; but sometimes it is required to wait for synchronization of hardware cache
|
||||
; with modified structures in memory.
|
||||
; The code keeps two queues of pipes waiting for synchronization,
|
||||
; one for asynchronous (bulk/control) pipes, one for periodic pipes, hardware
|
||||
; cache is invalidated under different conditions for those types.
|
||||
; Both queues are organized in the same way, as single-linked lists.
|
||||
; There are three special positions: the head of list (new pipes are added
|
||||
; here), the first pipe to be synchronized at the current iteration,
|
||||
; the tail of list (all pipes starting from here are synchronized).
|
||||
WaitPipeListAsync dd ?
|
||||
WaitPipeListPeriodic dd ?
|
||||
; List heads.
|
||||
WaitPipeRequestAsync dd ?
|
||||
WaitPipeRequestPeriodic dd ?
|
||||
; Pending request to hardware to refresh cache for items from WaitPipeList*.
|
||||
; (Pointers to some items in WaitPipeList* or NULLs).
|
||||
ReadyPipeHeadAsync dd ?
|
||||
ReadyPipeHeadPeriodic dd ?
|
||||
; Items of RemovingList* which were released by hardware and are ready
|
||||
; for further processing.
|
||||
; (Pointers to some items in WaitPipeList* or NULLs).
|
||||
NewConnected dd ?
|
||||
; bit mask of recently connected ports of the root hub,
|
||||
; bit set = a device was recently connected to the corresponding port;
|
||||
; after USB_CONNECT_DELAY ticks of stable status these ports are moved to
|
||||
; PendingPorts
|
||||
NewDisconnected dd ?
|
||||
; bit mask of disconnected ports of the root hub,
|
||||
; bit set = a device in the corresponding port was disconnected,
|
||||
; disconnect processing is required.
|
||||
PendingPorts dd ?
|
||||
; bit mask of ports which are ready to be initialized
|
||||
ControlLock MUTEX ?
|
||||
; mutex which guards all operations with control queue
|
||||
BulkLock MUTEX ?
|
||||
; mutex which guards all operations with bulk queue
|
||||
PeriodicLock MUTEX ?
|
||||
; mutex which guards all operations with periodic queues
|
||||
WaitSpinlock:
|
||||
; spinlock guarding WaitPipeRequest/ReadyPipeHead (but not WaitPipeList)
|
||||
StartWaitFrame dd ?
|
||||
; USB frame number when WaitPipeRequest* was registered.
|
||||
ResettingHub dd ?
|
||||
; Pointer to usb_hub responsible for the currently resetting port, if any.
|
||||
; NULL for the root hub.
|
||||
ResettingPort db ?
|
||||
; Port that is currently resetting, 0-based.
|
||||
ResettingSpeed db ?
|
||||
; Speed of currently resetting device.
|
||||
ResettingStatus db ?
|
||||
; Status of port reset. 0 = no port is resetting, -1 = reset failed,
|
||||
; 1 = reset in progress, 2 = reset recovery in progress.
|
||||
rb 1 ; alignment
|
||||
ResetTime dd ?
|
||||
; Time when reset signalling or reset recovery has been started.
|
||||
SetAddressBuffer rb 8
|
||||
; Buffer for USB control command SET_ADDRESS.
|
||||
ExistingAddresses rd 128/32
|
||||
; Bitmask for 128 bits; bit i is cleared <=> address i is free for allocating
|
||||
; for new devices. Bit 0 is always set.
|
||||
ConnectedTime rd 16
|
||||
; Time, in timer ticks, when the port i has signalled the connect event.
|
||||
; Valid only if bit i in NewConnected is set.
|
||||
DevicesByPort rd 16
|
||||
; Pointer to usb_pipe for zero endpoint (which serves as device handle)
|
||||
; for each port.
|
||||
ends
|
||||
|
||||
; Pipe descriptor.
|
||||
; * An USB pipe is described by two structures, for hardware and for software.
|
||||
; * This is the software part. The hardware part is defined in a driver
|
||||
; of the corresponding controller.
|
||||
; * The hardware part is located immediately before usb_pipe,
|
||||
; both are allocated at once by controller-specific code
|
||||
; (it knows the total length, which depends on the hardware part).
|
||||
struct usb_pipe
|
||||
Controller dd ?
|
||||
; Pointer to usb_controller structure corresponding to this pipe.
|
||||
; Must be the first dword after hardware part, see *hci_new_device.
|
||||
;
|
||||
; Every endpoint is included into one of processing lists:
|
||||
; * Bulk list contains all Bulk endpoints.
|
||||
; * Control list contains all Control endpoints.
|
||||
; * Several Periodic lists serve Interrupt endpoints with different interval.
|
||||
; - There are N=2^n "leaf" periodic lists for N ms interval, one is processed
|
||||
; in the frames 0,N,2N,..., another is processed in the frames
|
||||
; 1,1+N,1+2N,... and so on. The hardware starts processing of periodic
|
||||
; endpoints in every frame from the list identified by lower n bits of the
|
||||
; frame number; the addresses of these N lists are written to the
|
||||
; controller data area during the initialization.
|
||||
; - We assume that n=5, N=32 to simplify the code and compact the data.
|
||||
; OHCI works in this way. UHCI and EHCI actually have n=10, N=1024,
|
||||
; but this is an overkill for interrupt endpoints; the large value of N is
|
||||
; useful only for isochronous transfers in UHCI and EHCI. UHCI/EHCI code
|
||||
; initializes "leaf" lists k,k+32,k+64,...,k+(1024-32) to the same value,
|
||||
; giving essentially N=32.
|
||||
; This restriction means that the actual maximum interval of polling any
|
||||
; interrupt endpoint is 32ms, which seems to be a reasonable value.
|
||||
; - Similarly, there are 16 lists for 16-ms interval, 8 lists for 8-ms
|
||||
; interval and so on. Finally, there is one list for 1ms interval. Their
|
||||
; addresses are not directly known to the controller.
|
||||
; - The hardware serves endpoints following a physical link from the hardware
|
||||
; part.
|
||||
; - The hardware links are organized as follows. If the list item is not the
|
||||
; last, it's hardware link points to the next item. The hardware link of
|
||||
; the last item points to the first item of the "next" list.
|
||||
; - The "next" list for k-th and (k+M)-th periodic lists for interval 2M ms
|
||||
; is the k-th periodic list for interval M ms, M >= 1. In this scheme,
|
||||
; if two "previous" lists are served in the frames k,k+2M,k+4M,...
|
||||
; and k+M,k+3M,k+5M,... correspondingly, the "next" list is served in
|
||||
; the frames k,k+M,k+2M,k+3M,k+4M,k+5M,..., which is exactly what we want.
|
||||
; - The links between Periodic, Control, Bulk lists and the processing of
|
||||
; Isochronous endpoints are controller-specific.
|
||||
; * The head of every processing list is a static entry which does not
|
||||
; correspond to any real pipe. It is described by usb_static_ep
|
||||
; structure, not usb_pipe. For OHCI and UHCI, sizeof.usb_static_ep plus
|
||||
; sizeof hardware part is 20h, the total number of lists is
|
||||
; 32+16+8+4+2+1+1+1 = 65, so all these structures fit in one page,
|
||||
; leaving space for other data. This is another reason for 32ms limit.
|
||||
; * Static endpoint descriptors are kept in *hci_controller structure.
|
||||
; * All items in every processing list, including the static head, are
|
||||
; organized in a double-linked list using .NextVirt and .PrevVirt fields.
|
||||
; * [[item.NextVirt].PrevVirt] = [[item.PrevVirt].NextVirt] for all items.
|
||||
NextVirt dd ?
|
||||
; Next endpoint in the processing list.
|
||||
; See also PrevVirt field and the description before NextVirt field.
|
||||
PrevVirt dd ?
|
||||
; Previous endpoint in the processing list.
|
||||
; See also NextVirt field and the description before NextVirt field.
|
||||
;
|
||||
; Every pipe has the associated transfer queue, that is, the double-linked
|
||||
; list of Transfer Descriptors aka TD. For Control, Bulk and Interrupt
|
||||
; endpoints this list consists of usb_gtd structures
|
||||
; (GTD = General Transfer Descriptors), for Isochronous endpoints
|
||||
; this list consists of usb_itd structures, which are not developed yet.
|
||||
; The pipe needs to know only the last TD; the first TD can be
|
||||
; obtained as [[pipe.LastTD].NextVirt].
|
||||
LastTD dd ?
|
||||
; Last TD in the transfer queue.
|
||||
;
|
||||
; All opened pipes corresponding to the same physical device are organized in
|
||||
; the double-linked list using .NextSibling and .PrevSibling fields.
|
||||
; The head of this list is kept in usb_device_data structure (OpenedPipeList).
|
||||
; This list is used when the device is disconnected and all pipes for the
|
||||
; device should be closed.
|
||||
; Also, all pipes closed due to disconnect must remain valid at least until
|
||||
; driver-provided disconnect function returns; all should-be-freed-but-not-now
|
||||
; pipes for one device are organized in another double-linked list with
|
||||
; the head in usb_device_data.ClosedPipeList; this list uses the same link
|
||||
; fields, one pipe can never be in both lists.
|
||||
NextSibling dd ?
|
||||
; Next pipe for the physical device.
|
||||
PrevSibling dd ?
|
||||
; Previous pipe for the physical device.
|
||||
;
|
||||
; When hardware part of pipe is changed, some time is needed before further
|
||||
; actions so that hardware reacts on this change. During that time,
|
||||
; all changed pipes are organized in single-linked list with the head
|
||||
; usb_controller.WaitPipeList* and link field NextWait.
|
||||
; Currently there are two possible reasons to change:
|
||||
; change of address/packet size in initial configuration,
|
||||
; close of the pipe. They are distinguished by USB_FLAG_CLOSED.
|
||||
NextWait dd ?
|
||||
Lock MUTEX
|
||||
; Mutex that guards operations with transfer queue for this pipe.
|
||||
Type db ?
|
||||
; Type of pipe, one of {CONTROL,ISOCHRONOUS,BULK,INTERRUPT}_PIPE.
|
||||
Flags db ?
|
||||
; Combination of flags, USB_FLAG_*.
|
||||
rb 2 ; dword alignment
|
||||
DeviceData dd ?
|
||||
; Pointer to usb_device_data, common for all pipes for one device.
|
||||
ends
|
||||
|
||||
; This structure describes the static head of every list of pipes.
|
||||
struct usb_static_ep
|
||||
; software fields
|
||||
Bandwidth dd ?
|
||||
; valid only for interrupt/isochronous USB1 lists
|
||||
; The offsets of the following two fields must be the same in this structure
|
||||
; and in usb_pipe.
|
||||
NextVirt dd ?
|
||||
PrevVirt dd ?
|
||||
ends
|
||||
|
||||
; This structure represents one transfer descriptor
|
||||
; ('g' stands for "general" as opposed to isochronous usb_itd).
|
||||
; Note that one transfer can have several descriptors:
|
||||
; a control transfer has three stages.
|
||||
; Additionally, every controller has a limit on transfer length with
|
||||
; one descriptor (packet size for UHCI, 1K for OHCI, 4K for EHCI),
|
||||
; large transfers must be split into individual packets according to that limit.
|
||||
struct usb_gtd
|
||||
Callback dd ?
|
||||
; Zero for intermediate descriptors, pointer to callback function
|
||||
; for final descriptor. See the docs for description of the callback.
|
||||
UserData dd ?
|
||||
; Dword which is passed to Callback as is, not used by USB code itself.
|
||||
; Two following fields organize all descriptors for one pipe in
|
||||
; the linked list.
|
||||
NextVirt dd ?
|
||||
PrevVirt dd ?
|
||||
Pipe dd ?
|
||||
; Pointer to the parent usb_pipe.
|
||||
Buffer dd ?
|
||||
; Pointer to data for this descriptor.
|
||||
Length dd ?
|
||||
; Length of data for this descriptor.
|
||||
ends
|
||||
|
||||
; Interface-specific data. Several interfaces of one device can operate
|
||||
; independently, each is controlled by some driver and is identified by
|
||||
; some driver-specific data passed as is to the driver.
|
||||
struct usb_interface_data
|
||||
DriverData dd ?
|
||||
; Passed as is to the driver.
|
||||
DriverFunc dd ?
|
||||
; Pointer to USBSRV structure for the driver.
|
||||
ends
|
||||
|
||||
; Device-specific data.
|
||||
struct usb_device_data
|
||||
PipeListLock MUTEX
|
||||
; Lock guarding OpenedPipeList. Must be the first item of the structure,
|
||||
; the code passes pointer to usb_device_data as is to mutex_lock/unlock.
|
||||
OpenedPipeList rd 2
|
||||
; List of all opened pipes for the device.
|
||||
; Used when the device is disconnected, so all pipes should be closed.
|
||||
ClosedPipeList rd 2
|
||||
; List of all closed, but still valid pipes for the device.
|
||||
; A pipe closed with USBClosePipe is just deallocated,
|
||||
; but a pipe closed due to disconnect must remain valid until driver-provided
|
||||
; disconnect handler returns; this list links all such pipes to deallocate them
|
||||
; after disconnect processing.
|
||||
NumPipes dd ?
|
||||
; Number of not-yet-closed pipes.
|
||||
Hub dd ?
|
||||
; NULL if connected to the root hub, pointer to usb_hub otherwise.
|
||||
TTHub dd ?
|
||||
; Pointer to usb_hub for (the) hub with Transaction Translator for the device,
|
||||
; NULL if the device operates in the same speed as the controller.
|
||||
Port db ?
|
||||
; Port on the hub, zero-based.
|
||||
TTPort db ?
|
||||
; Port on the TTHub, zero-based.
|
||||
DeviceDescrSize db ?
|
||||
; Size of device descriptor.
|
||||
Speed db ?
|
||||
; Device speed, one of USB_SPEED_*.
|
||||
NumInterfaces dd ?
|
||||
; Number of interfaces.
|
||||
ConfigDataSize dd ?
|
||||
; Total size of data associated with the configuration descriptor
|
||||
; (including the configuration descriptor itself).
|
||||
Interfaces dd ?
|
||||
; Offset from the beginning of this structure to Interfaces field.
|
||||
; Variable-length fields:
|
||||
; DeviceDescriptor:
|
||||
; device descriptor starts here
|
||||
; ConfigDescriptor = DeviceDescriptor + DeviceDescrSize
|
||||
; configuration descriptor with all associated data
|
||||
; Interfaces = ALIGN_UP(ConfigDescriptor + ConfigDataSize, 4)
|
||||
; array of NumInterfaces elements of type usb_interface_data
|
||||
ends
|
||||
|
||||
usb_device_data.DeviceDescriptor = sizeof.usb_device_data
|
File diff suppressed because it is too large
Load Diff
@ -1,238 +1,33 @@
|
||||
; USB Host Controller support code: hardware-independent part,
|
||||
; common for all controller types.
|
||||
|
||||
; =============================================================================
|
||||
; ================================= Constants =================================
|
||||
; =============================================================================
|
||||
; USB device must have at least 100ms of stable power before initializing can
|
||||
; proceed; one timer tick is 10ms, so enforce delay in 10 ticks
|
||||
USB_CONNECT_DELAY = 10
|
||||
; USB requires at least 10 ms for reset signalling. Normally, this is one timer
|
||||
; tick. However, it is possible that we start reset signalling in the end of
|
||||
; interval between timer ticks and then we test time in the start of the next
|
||||
; interval; in this case, the delta between [timer_ticks] is 1, but the real
|
||||
; time passed is significantly less than 10 ms. To avoid this, we add an extra
|
||||
; tick; this guarantees that at least 10 ms have passed.
|
||||
USB_RESET_TIME = 2
|
||||
; USB requires at least 10 ms of reset recovery, a delay between reset
|
||||
; signalling and any commands to device. Add an extra tick for the same reasons
|
||||
; as with the previous constant.
|
||||
USB_RESET_RECOVERY_TIME = 2
|
||||
|
||||
; =============================================================================
|
||||
; ================================ Structures =================================
|
||||
; =============================================================================
|
||||
; Controller descriptor.
|
||||
; This structure represents the common (controller-independent) part
|
||||
; of a controller for the USB code. The corresponding controller-dependent
|
||||
; part *hci_controller is located immediately before usb_controller.
|
||||
struct usb_controller
|
||||
; Two following fields organize all controllers in the global linked list.
|
||||
Next dd ?
|
||||
Prev dd ?
|
||||
HardwareFunc dd ?
|
||||
; Pointer to usb_hardware_func structure with controller-specific functions.
|
||||
NumPorts dd ?
|
||||
; Number of ports in the root hub.
|
||||
SetAddressBuffer rb 8
|
||||
; Buffer for USB control command SET_ADDRESS.
|
||||
ExistingAddresses rd 128/32
|
||||
; Bitmask for 128 bits; bit i is cleared <=> address i is free for allocating
|
||||
; for new devices. Bit 0 is always set.
|
||||
;
|
||||
; The hardware is allowed to cache some data from hardware structures.
|
||||
; Regular operations are designed considering this,
|
||||
; but sometimes it is required to wait for synchronization of hardware cache
|
||||
; with modified structures in memory.
|
||||
; The code keeps two queues of pipes waiting for synchronization,
|
||||
; one for asynchronous (bulk/control) pipes, one for periodic pipes, hardware
|
||||
; cache is invalidated under different conditions for those types.
|
||||
; Both queues are organized in the same way, as single-linked lists.
|
||||
; There are three special positions: the head of list (new pipes are added
|
||||
; here), the first pipe to be synchronized at the current iteration,
|
||||
; the tail of list (all pipes starting from here are synchronized).
|
||||
WaitPipeListAsync dd ?
|
||||
WaitPipeListPeriodic dd ?
|
||||
; List heads.
|
||||
WaitPipeRequestAsync dd ?
|
||||
WaitPipeRequestPeriodic dd ?
|
||||
; Pending request to hardware to refresh cache for items from WaitPipeList*.
|
||||
; (Pointers to some items in WaitPipeList* or NULLs).
|
||||
ReadyPipeHeadAsync dd ?
|
||||
ReadyPipeHeadPeriodic dd ?
|
||||
; Items of RemovingList* which were released by hardware and are ready
|
||||
; for further processing.
|
||||
; (Pointers to some items in WaitPipeList* or NULLs).
|
||||
NewConnected dd ?
|
||||
; bit mask of recently connected ports of the root hub,
|
||||
; bit set = a device was recently connected to the corresponding port;
|
||||
; after USB_CONNECT_DELAY ticks of stable status these ports are moved to
|
||||
; PendingPorts
|
||||
NewDisconnected dd ?
|
||||
; bit mask of disconnected ports of the root hub,
|
||||
; bit set = a device in the corresponding port was disconnected,
|
||||
; disconnect processing is required.
|
||||
PendingPorts dd ?
|
||||
; bit mask of ports which are ready to be initialized
|
||||
ControlLock MUTEX ?
|
||||
; mutex which guards all operations with control queue
|
||||
BulkLock MUTEX ?
|
||||
; mutex which guards all operations with bulk queue
|
||||
PeriodicLock MUTEX ?
|
||||
; mutex which guards all operations with periodic queues
|
||||
WaitSpinlock:
|
||||
; spinlock guarding WaitPipeRequest/ReadyPipeHead (but not WaitPipeList)
|
||||
StartWaitFrame dd ?
|
||||
; USB frame number when WaitPipeRequest* was registered.
|
||||
ResettingHub dd ?
|
||||
; Pointer to usb_hub responsible for the currently resetting port, if any.
|
||||
; NULL for the root hub.
|
||||
ResettingPort db ?
|
||||
; Port that is currently resetting, 0-based.
|
||||
ResettingSpeed db ?
|
||||
; Speed of currently resetting device.
|
||||
ResettingStatus db ?
|
||||
; Status of port reset. 0 = no port is resetting, -1 = reset failed,
|
||||
; 1 = reset in progress, 2 = reset recovery in progress.
|
||||
rb 1 ; alignment
|
||||
ResetTime dd ?
|
||||
; Time when reset signalling or reset recovery has been started.
|
||||
ConnectedTime rd 16
|
||||
; Time, in timer ticks, when the port i has signalled the connect event.
|
||||
; Valid only if bit i in NewConnected is set.
|
||||
DevicesByPort rd 16
|
||||
; Pointer to usb_pipe for zero endpoint (which serves as device handle)
|
||||
; for each port.
|
||||
ends
|
||||
|
||||
; Interface-specific data. Several interfaces of one device can operate
|
||||
; independently, each is controlled by some driver and is identified by
|
||||
; some driver-specific data passed as is to the driver.
|
||||
struct usb_interface_data
|
||||
DriverData dd ?
|
||||
; Passed as is to the driver.
|
||||
DriverFunc dd ?
|
||||
; Pointer to USBSRV structure for the driver.
|
||||
ends
|
||||
|
||||
; Device-specific data.
|
||||
struct usb_device_data
|
||||
PipeListLock MUTEX
|
||||
; Lock guarding OpenedPipeList. Must be the first item of the structure,
|
||||
; the code passes pointer to usb_device_data as is to mutex_lock/unlock.
|
||||
OpenedPipeList rd 2
|
||||
; List of all opened pipes for the device.
|
||||
; Used when the device is disconnected, so all pipes should be closed.
|
||||
ClosedPipeList rd 2
|
||||
; List of all closed, but still valid pipes for the device.
|
||||
; A pipe closed with USBClosePipe is just deallocated,
|
||||
; but a pipe closed due to disconnect must remain valid until driver-provided
|
||||
; disconnect handler returns; this list links all such pipes to deallocate them
|
||||
; after disconnect processing.
|
||||
NumPipes dd ?
|
||||
; Number of not-yet-closed pipes.
|
||||
Hub dd ?
|
||||
; NULL if connected to the root hub, pointer to usb_hub otherwise.
|
||||
TTHub dd ?
|
||||
; Pointer to usb_hub for (the) hub with Transaction Translator for the device,
|
||||
; NULL if the device operates in the same speed as the controller.
|
||||
Port db ?
|
||||
; Port on the hub, zero-based.
|
||||
TTPort db ?
|
||||
; Port on the TTHub, zero-based.
|
||||
DeviceDescrSize db ?
|
||||
; Size of device descriptor.
|
||||
Speed db ?
|
||||
; Device speed, one of USB_SPEED_*.
|
||||
NumInterfaces dd ?
|
||||
; Number of interfaces.
|
||||
ConfigDataSize dd ?
|
||||
; Total size of data associated with the configuration descriptor
|
||||
; (including the configuration descriptor itself).
|
||||
Interfaces dd ?
|
||||
; Offset from the beginning of this structure to Interfaces field.
|
||||
; Variable-length fields:
|
||||
; DeviceDescriptor:
|
||||
; device descriptor starts here
|
||||
; ConfigDescriptor = DeviceDescriptor + DeviceDescrSize
|
||||
; configuration descriptor with all associated data
|
||||
; Interfaces = ALIGN_UP(ConfigDescriptor + ConfigDataSize, 4)
|
||||
; array of NumInterfaces elements of type usb_interface_data
|
||||
ends
|
||||
|
||||
usb_device_data.DeviceDescriptor = sizeof.usb_device_data
|
||||
|
||||
; Description of controller-specific data and functions.
|
||||
struct usb_hardware_func
|
||||
ID dd ? ; '*HCI'
|
||||
DataSize dd ? ; sizeof(*hci_controller)
|
||||
Init dd ?
|
||||
; Initialize controller-specific part of controller data.
|
||||
; in: eax -> *hci_controller to initialize, [ebp-4] = (bus shl 8) + devfn
|
||||
; out: eax = 0 <=> failed, otherwise eax -> usb_controller
|
||||
ProcessDeferred dd ?
|
||||
; Called regularly from the main loop of USB thread
|
||||
; (either due to timeout from a previous call, or due to explicit wakeup).
|
||||
; in: esi -> usb_controller
|
||||
; out: eax = maximum timeout for next call (-1 = infinity)
|
||||
SetDeviceAddress dd ?
|
||||
; in: esi -> usb_controller, ebx -> usb_pipe, cl = address
|
||||
GetDeviceAddress dd ?
|
||||
; in: esi -> usb_controller, ebx -> usb_pipe
|
||||
; out: eax = address
|
||||
PortDisable dd ?
|
||||
; Disable the given port in the root hub.
|
||||
; in: esi -> usb_controller, ecx = port (zero-based)
|
||||
InitiateReset dd ?
|
||||
; Start reset signalling on the given port.
|
||||
; in: esi -> usb_controller, ecx = port (zero-based)
|
||||
SetEndpointPacketSize dd ?
|
||||
; in: esi -> usb_controller, ebx -> usb_pipe, ecx = packet size
|
||||
AllocPipe dd ?
|
||||
; out: eax = pointer to allocated usb_pipe
|
||||
FreePipe dd ?
|
||||
; void stdcall with one argument = pointer to previously allocated usb_pipe
|
||||
InitPipe dd ?
|
||||
; in: edi -> usb_pipe for target, ecx -> usb_pipe for config pipe,
|
||||
; esi -> usb_controller, eax -> usb_gtd for the first TD,
|
||||
; [ebp+12] = endpoint, [ebp+16] = maxpacket, [ebp+20] = type
|
||||
UnlinkPipe dd ?
|
||||
; esi -> usb_controller, ebx -> usb_pipe
|
||||
AllocTD dd ?
|
||||
; out: eax = pointer to allocated usb_gtd
|
||||
FreeTD dd ?
|
||||
; void stdcall with one argument = pointer to previously allocated usb_gtd
|
||||
AllocTransfer dd ?
|
||||
; Allocate and initialize one stage of a transfer.
|
||||
; ebx -> usb_pipe, other parameters are passed through the stack:
|
||||
; buffer,size = data to transfer
|
||||
; flags = same as in usb_open_pipe:
|
||||
; bit 0 = allow short transfer, other bits reserved
|
||||
; td = pointer to the current end-of-queue descriptor
|
||||
; direction =
|
||||
; 0000b for normal transfers,
|
||||
; 1000b for control SETUP transfer,
|
||||
; 1101b for control OUT transfer,
|
||||
; 1110b for control IN transfer
|
||||
; returns eax = pointer to the new end-of-queue descriptor
|
||||
; (not included in the queue itself) or 0 on error
|
||||
InsertTransfer dd ?
|
||||
; Activate previously initialized transfer (maybe with multiple stages).
|
||||
; esi -> usb_controller, ebx -> usb_pipe,
|
||||
; [esp+4] -> first usb_gtd for the transfer,
|
||||
; ecx -> last descriptor for the transfer
|
||||
NewDevice dd ?
|
||||
; Initiate configuration of a new device (create pseudo-pipe describing that
|
||||
; device and call usb_new_device).
|
||||
; esi -> usb_controller, eax = speed (one of USB_SPEED_* constants).
|
||||
ends
|
||||
|
||||
; =============================================================================
|
||||
; =================================== Code ====================================
|
||||
; =============================================================================
|
||||
iglobal
|
||||
; USB HC support: some functions interesting only for *HCI-drivers.
|
||||
align 4
|
||||
usb_hc_func:
|
||||
dd usb_process_gtd
|
||||
dd usb_init_static_endpoint
|
||||
dd usb_wakeup_if_needed
|
||||
dd usb_subscribe_control
|
||||
dd usb_subscription_done
|
||||
dd usb_allocate_common
|
||||
dd usb_free_common
|
||||
dd usb_td_to_virt
|
||||
dd usb_init_transfer
|
||||
dd usb_undo_tds
|
||||
dd usb_test_pending_port
|
||||
dd usb_get_tt
|
||||
dd usb_get_tt_think_time
|
||||
dd usb_new_device
|
||||
dd usb_disconnect_stage2
|
||||
dd usb_process_wait_lists
|
||||
dd usb_unlink_td
|
||||
dd usb_is_final_packet
|
||||
dd usb_find_ehci_companion
|
||||
endg
|
||||
|
||||
; Initializes one controller, called by usb_init for every controller.
|
||||
; edi -> usb_hardware_func, eax -> PCIDEV structure for the device.
|
||||
; eax -> PCIDEV structure for the device.
|
||||
proc usb_init_controller
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
@ -240,6 +35,10 @@ proc usb_init_controller
|
||||
; make [ebp-4] = (bus shl 8) + devfn, used by controller-specific Init funcs.
|
||||
push dword [eax+PCIDEV.devfn]
|
||||
push eax
|
||||
mov edi, [eax+PCIDEV.owner]
|
||||
test edi, edi
|
||||
jz .nothing
|
||||
mov edi, [edi+USBSRV.usb_func]
|
||||
; 2. Allocate *hci_controller + usb_controller.
|
||||
mov ebx, [edi+usb_hardware_func.DataSize]
|
||||
add ebx, sizeof.usb_controller
|
||||
@ -264,6 +63,8 @@ proc usb_init_controller
|
||||
mov [edi+usb_controller.ResettingPort-sizeof.usb_controller], al ; no resetting port
|
||||
dec eax ; don't allocate zero address
|
||||
mov [edi+usb_controller.ExistingAddresses-sizeof.usb_controller], eax
|
||||
mov eax, [ebp-4]
|
||||
mov [edi+usb_controller.PCICoordinates-sizeof.usb_controller], eax
|
||||
lea ecx, [edi+usb_controller.PeriodicLock-sizeof.usb_controller]
|
||||
call mutex_init
|
||||
add ecx, usb_controller.ControlLock - usb_controller.PeriodicLock
|
||||
@ -474,3 +275,48 @@ proc usb_process_one_wait_list
|
||||
.nothing:
|
||||
ret
|
||||
endp
|
||||
|
||||
; Called from USB1 controller-specific initialization.
|
||||
; Finds EHCI companion controller for given USB1 controller.
|
||||
; in: bl = PCI device:function for USB1 controller, bh = PCI bus
|
||||
; out: eax -> usb_controller for EHCI companion
|
||||
proc usb_find_ehci_companion
|
||||
; 1. Loop over all registered controllers.
|
||||
mov eax, usb_controllers_list
|
||||
.next:
|
||||
mov eax, [eax+usb_controller.Next]
|
||||
cmp eax, usb_controllers_list
|
||||
jz .notfound
|
||||
; 2. For every controller, check the type, ignore everything that is not EHCI.
|
||||
mov edx, [eax+usb_controller.HardwareFunc]
|
||||
cmp [edx+usb_hardware_func.ID], 'EHCI'
|
||||
jnz .next
|
||||
; 3. For EHCI controller, compare PCI coordinates with input data:
|
||||
; bus and device must be the same, function can be different.
|
||||
mov edx, [eax+usb_controller.PCICoordinates]
|
||||
xor edx, ebx
|
||||
cmp dx, 8
|
||||
jae .next
|
||||
ret
|
||||
.notfound:
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
|
||||
; Find Transaction Translator hub and port for the given device.
|
||||
; in: edx = parent hub for the device, ecx = port for the device
|
||||
; out: edx = TT hub for the device, ecx = TT port for the device.
|
||||
proc usb_get_tt
|
||||
; If the parent hub is high-speed, it is TT for the device.
|
||||
; Otherwise, the parent hub itself is behind TT, and the device
|
||||
; has the same TT hub+port as the parent hub.
|
||||
mov eax, [edx+usb_hub.ConfigPipe]
|
||||
mov eax, [eax+usb_pipe.DeviceData]
|
||||
cmp [eax+usb_device_data.Speed], USB_SPEED_HS
|
||||
jz @f
|
||||
movzx ecx, [eax+usb_device_data.TTPort]
|
||||
mov edx, [eax+usb_device_data.TTHub]
|
||||
@@:
|
||||
mov edx, [edx+usb_hub.ConfigPipe]
|
||||
ret
|
||||
endp
|
||||
|
@ -219,30 +219,48 @@ virtual at esp
|
||||
.config dd ? ; pointer to usb_config_descr
|
||||
.interface dd ? ; pointer to usb_interface_descr
|
||||
end virtual
|
||||
; 1. Check that the maximal nesting is not exceeded:
|
||||
; 5 non-root hubs is the maximum according to the spec.
|
||||
mov ebx, [.pipe]
|
||||
push 5
|
||||
mov eax, ebx
|
||||
.count_parents:
|
||||
mov eax, [eax+usb_pipe.DeviceData]
|
||||
mov eax, [eax+usb_device_data.Hub]
|
||||
test eax, eax
|
||||
jz .depth_ok
|
||||
mov eax, [eax+usb_hub.ConfigPipe]
|
||||
dec dword [esp]
|
||||
jnz .count_parents
|
||||
pop eax
|
||||
dbgstr 'Hub chain is too long'
|
||||
jmp .return0
|
||||
.depth_ok:
|
||||
pop eax
|
||||
; Hubs use one IN interrupt endpoint for polling the device
|
||||
; 1. Locate the descriptor of the interrupt endpoint.
|
||||
; 2. Locate the descriptor of the interrupt endpoint.
|
||||
; Loop over all descriptors owned by this interface.
|
||||
.lookep:
|
||||
; 1a. Skip the current descriptor.
|
||||
; 2a. Skip the current descriptor.
|
||||
movzx eax, [edx+usb_descr.bLength]
|
||||
add edx, eax
|
||||
sub ecx, eax
|
||||
jb .errorep
|
||||
; 1b. Length of data left must be at least sizeof.usb_endpoint_descr.
|
||||
; 2b. Length of data left must be at least sizeof.usb_endpoint_descr.
|
||||
cmp ecx, sizeof.usb_endpoint_descr
|
||||
jb .errorep
|
||||
; 1c. If we have found another interface descriptor but not found our endpoint,
|
||||
; 2c. If we have found another interface descriptor but not found our endpoint,
|
||||
; this is an error: all subsequent descriptors belong to that interface
|
||||
; (or further interfaces).
|
||||
cmp [edx+usb_endpoint_descr.bDescriptorType], USB_INTERFACE_DESCR
|
||||
jz .errorep
|
||||
; 1d. Ignore all interface-related descriptors except endpoint descriptor.
|
||||
; 2d. Ignore all interface-related descriptors except endpoint descriptor.
|
||||
cmp [edx+usb_endpoint_descr.bDescriptorType], USB_ENDPOINT_DESCR
|
||||
jnz .lookep
|
||||
; 1e. Length of endpoint descriptor must be at least sizeof.usb_endpoint_descr.
|
||||
; 2e. Length of endpoint descriptor must be at least sizeof.usb_endpoint_descr.
|
||||
cmp [edx+usb_endpoint_descr.bLength], sizeof.usb_endpoint_descr
|
||||
jb .errorep
|
||||
; 1f. Ignore all endpoints except for INTERRUPT IN.
|
||||
; 2f. Ignore all endpoints except for INTERRUPT IN.
|
||||
cmp [edx+usb_endpoint_descr.bEndpointAddress], 0
|
||||
jge .lookep
|
||||
mov al, [edx+usb_endpoint_descr.bmAttributes]
|
||||
@ -251,23 +269,22 @@ end virtual
|
||||
jnz .lookep
|
||||
; We have located the descriptor for INTERRUPT IN endpoint,
|
||||
; the pointer is in edx.
|
||||
; 2. Allocate memory for the hub descriptor.
|
||||
; 3. Allocate memory for the hub descriptor.
|
||||
; Maximum length (assuming 255 downstream ports) is 40 bytes.
|
||||
; Allocate 4 extra bytes to keep wMaxPacketSize.
|
||||
; 2a. Save registers.
|
||||
; 3a. Save registers.
|
||||
push edx
|
||||
; 2b. Call the allocator.
|
||||
; 3b. Call the allocator.
|
||||
movi eax, 44
|
||||
call malloc
|
||||
; 2c. Restore registers.
|
||||
; 3c. Restore registers.
|
||||
pop ecx
|
||||
; 2d. If failed, say something to the debug board and return error.
|
||||
; 3d. If failed, say something to the debug board and return error.
|
||||
test eax, eax
|
||||
jz .nomemory
|
||||
; 2e. Store the pointer in esi. xchg eax,r32 is one byte shorter than mov.
|
||||
; 3e. Store the pointer in esi. xchg eax,r32 is one byte shorter than mov.
|
||||
xchg esi, eax
|
||||
; 3. Open a pipe for the status endpoint with descriptor found in step 1.
|
||||
mov ebx, [.pipe]
|
||||
; 4. Open a pipe for the status endpoint with descriptor found in step 1.
|
||||
movzx eax, [ecx+usb_endpoint_descr.bEndpointAddress]
|
||||
movzx edx, [ecx+usb_endpoint_descr.bInterval]
|
||||
movzx ecx, [ecx+usb_endpoint_descr.wMaxPacketSize]
|
||||
@ -276,11 +293,11 @@ end virtual
|
||||
push ecx
|
||||
stdcall usb_open_pipe, ebx, eax, ecx, INTERRUPT_PIPE, edx
|
||||
pop ecx
|
||||
; If failed, free the memory allocated in step 2,
|
||||
; If failed, free the memory allocated in step 3,
|
||||
; say something to the debug board and return error.
|
||||
test eax, eax
|
||||
jz .free
|
||||
; 4. Send control query for the hub descriptor,
|
||||
; 5. Send control query for the hub descriptor,
|
||||
; pass status pipe as a callback parameter,
|
||||
; allow short packets.
|
||||
and ecx, (1 shl 11) - 1
|
||||
@ -291,7 +308,7 @@ end virtual
|
||||
(USB_HUB_DESCRIPTOR shl 24)
|
||||
mov dword [esi+4], 40 shl 16
|
||||
stdcall usb_control_async, ebx, esi, esi, 40, usb_hub_got_config, eax, 1
|
||||
; 5. If failed, free the memory allocated in step 2,
|
||||
; 6. If failed, free the memory allocated in step 3,
|
||||
; say something to the debug board and return error.
|
||||
test eax, eax
|
||||
jz .free
|
||||
@ -1245,3 +1262,14 @@ end virtual
|
||||
.nothing:
|
||||
retn 4
|
||||
endp
|
||||
|
||||
; Helper function for USB2 scheduler.
|
||||
; in: eax -> usb_hub
|
||||
; out: ecx = TT think time for the hub in FS-bytes
|
||||
proc usb_get_tt_think_time
|
||||
movzx ecx, [eax+usb_hub.HubCharacteristics]
|
||||
shr ecx, 5
|
||||
and ecx, 3
|
||||
inc ecx
|
||||
ret
|
||||
endp
|
||||
|
@ -29,19 +29,20 @@
|
||||
; ProcessDeferred and sleeps until this moment is reached or the thread
|
||||
; is awakened by IRQ handler.
|
||||
|
||||
iglobal
|
||||
uhci_service_name:
|
||||
db 'UHCI',0
|
||||
ohci_service_name:
|
||||
db 'OHCI',0
|
||||
ehci_service_name:
|
||||
db 'EHCI',0
|
||||
endg
|
||||
|
||||
; Initializes the USB subsystem.
|
||||
proc usb_init
|
||||
; 1. Initialize all locks.
|
||||
mov ecx, usb_controllers_list_mutex
|
||||
call mutex_init
|
||||
mov ecx, usb1_ep_mutex
|
||||
call mutex_init
|
||||
mov ecx, usb_gtd_mutex
|
||||
call mutex_init
|
||||
mov ecx, ehci_ep_mutex
|
||||
call mutex_init
|
||||
mov ecx, ehci_gtd_mutex
|
||||
call mutex_init
|
||||
; 2. Kick off BIOS from all USB controllers, calling the corresponding function
|
||||
; *hci_kickoff_bios. Also count USB controllers for the next step.
|
||||
; Note: USB1 companion(s) must go before the corresponding EHCI controller,
|
||||
@ -59,18 +60,33 @@ proc usb_init
|
||||
jz .done_kickoff
|
||||
cmp word [esi+PCIDEV.class+1], 0x0C03
|
||||
jnz .kickoff
|
||||
mov eax, uhci_kickoff_bios
|
||||
mov ebx, uhci_service_name
|
||||
cmp byte [esi+PCIDEV.class], 0x00
|
||||
jz .do_kickoff
|
||||
mov eax, ohci_kickoff_bios
|
||||
mov ebx, ohci_service_name
|
||||
cmp byte [esi+PCIDEV.class], 0x10
|
||||
jz .do_kickoff
|
||||
mov eax, ehci_kickoff_bios
|
||||
mov ebx, ehci_service_name
|
||||
cmp byte [esi+PCIDEV.class], 0x20
|
||||
jnz .kickoff
|
||||
.do_kickoff:
|
||||
inc dword [esp]
|
||||
call eax
|
||||
push ebx esi
|
||||
stdcall get_service, ebx
|
||||
pop esi ebx
|
||||
test eax, eax
|
||||
jz .driver_fail
|
||||
mov edx, [eax+USBSRV.usb_func]
|
||||
cmp [edx+usb_hardware_func.Version], USBHC_VERSION
|
||||
jnz .driver_invalid
|
||||
mov [esi+PCIDEV.owner], eax
|
||||
call [edx+usb_hardware_func.BeforeInit]
|
||||
jmp .kickoff
|
||||
.driver_fail:
|
||||
DEBUGF 1,'K : failed to load driver %s\n',ebx
|
||||
jmp .kickoff
|
||||
.driver_invalid:
|
||||
DEBUGF 1,'K : driver %s has wrong version\n',ebx
|
||||
jmp .kickoff
|
||||
.done_kickoff:
|
||||
pop eax
|
||||
@ -97,7 +113,6 @@ proc usb_init
|
||||
jz .done_ehci
|
||||
cmp [eax+PCIDEV.class], 0x0C0320
|
||||
jnz .scan_ehci
|
||||
mov edi, ehci_hardware_func
|
||||
call usb_init_controller
|
||||
jmp .scan_ehci
|
||||
.done_ehci:
|
||||
@ -108,10 +123,8 @@ proc usb_init
|
||||
mov eax, [eax+PCIDEV.list.next]
|
||||
cmp eax, pcidev_list
|
||||
jz .done_usb1
|
||||
mov edi, uhci_hardware_func
|
||||
cmp [eax+PCIDEV.class], 0x0C0300
|
||||
jz @f
|
||||
mov edi, ohci_hardware_func
|
||||
cmp [eax+PCIDEV.class], 0x0C0310
|
||||
jnz .scan_usb1
|
||||
@@:
|
||||
@ -238,11 +251,8 @@ usb_controllers_list_mutex MUTEX
|
||||
endg
|
||||
|
||||
include "memory.inc"
|
||||
include "common.inc"
|
||||
include "hccommon.inc"
|
||||
include "pipe.inc"
|
||||
include "ohci.inc"
|
||||
include "uhci.inc"
|
||||
include "ehci.inc"
|
||||
include "protocol.inc"
|
||||
include "hub.inc"
|
||||
include "scheduler.inc"
|
||||
|
@ -12,77 +12,6 @@
|
||||
|
||||
; Data for one pool: dd pointer to the first page, MUTEX lock.
|
||||
|
||||
uglobal
|
||||
; Structures in UHCI and OHCI have equal sizes.
|
||||
; Thus, functions and data for allocating/freeing can be shared;
|
||||
; we keep them here rather than in controller-specific files.
|
||||
align 4
|
||||
; Data for UHCI and OHCI endpoints pool.
|
||||
usb1_ep_first_page dd ?
|
||||
usb1_ep_mutex MUTEX
|
||||
; Data for UHCI and OHCI general transfer descriptors pool.
|
||||
usb_gtd_first_page dd ?
|
||||
usb_gtd_mutex MUTEX
|
||||
endg
|
||||
|
||||
; sanity check: structures in UHCI and OHCI should be the same for allocation
|
||||
if (sizeof.ohci_pipe = sizeof.uhci_pipe)
|
||||
|
||||
; Allocates one endpoint structure for UHCI/OHCI.
|
||||
; Returns pointer to software part (usb_pipe) in eax.
|
||||
proc usb1_allocate_endpoint
|
||||
push ebx
|
||||
mov ebx, usb1_ep_mutex
|
||||
stdcall usb_allocate_common, (sizeof.ohci_pipe + sizeof.usb_pipe + 0Fh) and not 0Fh
|
||||
test eax, eax
|
||||
jz @f
|
||||
add eax, sizeof.ohci_pipe
|
||||
@@:
|
||||
pop ebx
|
||||
ret
|
||||
endp
|
||||
|
||||
; Free one endpoint structure for UHCI/OHCI.
|
||||
; Stdcall with one argument, pointer to software part (usb_pipe).
|
||||
proc usb1_free_endpoint
|
||||
sub dword [esp+4], sizeof.ohci_pipe
|
||||
jmp usb_free_common
|
||||
endp
|
||||
|
||||
else
|
||||
; sanity check continued
|
||||
.err allocate_endpoint/free_endpoint must be different for OHCI and UHCI
|
||||
end if
|
||||
|
||||
; sanity check: structures in UHCI and OHCI should be the same for allocation
|
||||
if (sizeof.ohci_gtd = sizeof.uhci_gtd)
|
||||
|
||||
; Allocates one general transfer descriptor structure for UHCI/OHCI.
|
||||
; Returns pointer to software part (usb_gtd) in eax.
|
||||
proc usb1_allocate_general_td
|
||||
push ebx
|
||||
mov ebx, usb_gtd_mutex
|
||||
stdcall usb_allocate_common, (sizeof.ohci_gtd + sizeof.usb_gtd + 0Fh) and not 0Fh
|
||||
test eax, eax
|
||||
jz @f
|
||||
add eax, sizeof.ohci_gtd
|
||||
@@:
|
||||
pop ebx
|
||||
ret
|
||||
endp
|
||||
|
||||
; Free one general transfer descriptor structure for UHCI/OHCI.
|
||||
; Stdcall with one argument, pointer to software part (usb_gtd).
|
||||
proc usb1_free_general_td
|
||||
sub dword [esp+4], sizeof.ohci_gtd
|
||||
jmp usb_free_common
|
||||
endp
|
||||
|
||||
else
|
||||
; sanity check continued
|
||||
.err allocate_general_td/free_general_td must be different for OHCI and UHCI
|
||||
end if
|
||||
|
||||
; Allocator for fixed-size blocks: allocate a block.
|
||||
; [ebx-4] = pointer to the first page, ebx = pointer to MUTEX structure.
|
||||
proc usb_allocate_common
|
||||
@ -187,12 +116,12 @@ end virtual
|
||||
ret 4
|
||||
endp
|
||||
|
||||
; Helper procedure for OHCI: translate physical address in ecx
|
||||
; Helper procedure: translate physical address in ecx
|
||||
; of some transfer descriptor to linear address.
|
||||
; in: eax = address of first page
|
||||
proc usb_td_to_virt
|
||||
; Traverse all pages used for transfer descriptors, looking for the one
|
||||
; with physical address as in ecx.
|
||||
mov eax, [usb_gtd_first_page]
|
||||
@@:
|
||||
test eax, eax
|
||||
jz .zero
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,195 +1,5 @@
|
||||
; Functions for USB pipe manipulation: opening/closing, sending data etc.
|
||||
;
|
||||
; =============================================================================
|
||||
; ================================= Constants =================================
|
||||
; =============================================================================
|
||||
; USB pipe types
|
||||
CONTROL_PIPE = 0
|
||||
ISOCHRONOUS_PIPE = 1
|
||||
BULK_PIPE = 2
|
||||
INTERRUPT_PIPE = 3
|
||||
|
||||
; Status codes for transfer callbacks.
|
||||
; Taken from OHCI as most verbose controller in this sense.
|
||||
USB_STATUS_OK = 0 ; no error
|
||||
USB_STATUS_CRC = 1 ; CRC error
|
||||
USB_STATUS_BITSTUFF = 2 ; bit stuffing violation
|
||||
USB_STATUS_TOGGLE = 3 ; data toggle mismatch
|
||||
USB_STATUS_STALL = 4 ; device returned STALL
|
||||
USB_STATUS_NORESPONSE = 5 ; device not responding
|
||||
USB_STATUS_PIDCHECK = 6 ; invalid PID check bits
|
||||
USB_STATUS_WRONGPID = 7 ; unexpected PID value
|
||||
USB_STATUS_OVERRUN = 8 ; too many data from endpoint
|
||||
USB_STATUS_UNDERRUN = 9 ; too few data from endpoint
|
||||
USB_STATUS_BUFOVERRUN = 12 ; overflow of internal controller buffer
|
||||
USB_STATUS_BUFUNDERRUN = 13 ; underflow of internal controller buffer
|
||||
USB_STATUS_CLOSED = 16 ; pipe closed
|
||||
; either explicitly with USBClosePipe
|
||||
; or implicitly due to device disconnect
|
||||
|
||||
; flags for usb_pipe.Flags
|
||||
USB_FLAG_CLOSED = 1 ; pipe is closed, no new transfers
|
||||
; pipe is closed, return error instead of submitting any new transfer
|
||||
USB_FLAG_CAN_FREE = 2
|
||||
; pipe is closed via explicit call to USBClosePipe, so it can be freed without
|
||||
; any driver notification; if this flag is not set, then the pipe is closed due
|
||||
; to device disconnect, so it must remain valid until return from disconnect
|
||||
; callback provided by the driver
|
||||
USB_FLAG_EXTRA_WAIT = 4
|
||||
; The pipe was in wait list, while another event occured;
|
||||
; when the first wait will be done, reinsert the pipe to wait list
|
||||
USB_FLAG_CLOSED_BIT = 0 ; USB_FLAG_CLOSED = 1 shl USB_FLAG_CLOSED_BIT
|
||||
|
||||
; =============================================================================
|
||||
; ================================ Structures =================================
|
||||
; =============================================================================
|
||||
|
||||
; Pipe descriptor.
|
||||
; * An USB pipe is described by two structures, for hardware and for software.
|
||||
; * This is the software part. The hardware part is defined in a driver
|
||||
; of the corresponding controller.
|
||||
; * The hardware part is located immediately before usb_pipe,
|
||||
; both are allocated at once by controller-specific code
|
||||
; (it knows the total length, which depends on the hardware part).
|
||||
struct usb_pipe
|
||||
Controller dd ?
|
||||
; Pointer to usb_controller structure corresponding to this pipe.
|
||||
; Must be the first dword after hardware part, see *hci_new_device.
|
||||
;
|
||||
; Every endpoint is included into one of processing lists:
|
||||
; * Bulk list contains all Bulk endpoints.
|
||||
; * Control list contains all Control endpoints.
|
||||
; * Several Periodic lists serve Interrupt endpoints with different interval.
|
||||
; - There are N=2^n "leaf" periodic lists for N ms interval, one is processed
|
||||
; in the frames 0,N,2N,..., another is processed in the frames
|
||||
; 1,1+N,1+2N,... and so on. The hardware starts processing of periodic
|
||||
; endpoints in every frame from the list identified by lower n bits of the
|
||||
; frame number; the addresses of these N lists are written to the
|
||||
; controller data area during the initialization.
|
||||
; - We assume that n=5, N=32 to simplify the code and compact the data.
|
||||
; OHCI works in this way. UHCI and EHCI actually have n=10, N=1024,
|
||||
; but this is an overkill for interrupt endpoints; the large value of N is
|
||||
; useful only for isochronous transfers in UHCI and EHCI. UHCI/EHCI code
|
||||
; initializes "leaf" lists k,k+32,k+64,...,k+(1024-32) to the same value,
|
||||
; giving essentially N=32.
|
||||
; This restriction means that the actual maximum interval of polling any
|
||||
; interrupt endpoint is 32ms, which seems to be a reasonable value.
|
||||
; - Similarly, there are 16 lists for 16-ms interval, 8 lists for 8-ms
|
||||
; interval and so on. Finally, there is one list for 1ms interval. Their
|
||||
; addresses are not directly known to the controller.
|
||||
; - The hardware serves endpoints following a physical link from the hardware
|
||||
; part.
|
||||
; - The hardware links are organized as follows. If the list item is not the
|
||||
; last, it's hardware link points to the next item. The hardware link of
|
||||
; the last item points to the first item of the "next" list.
|
||||
; - The "next" list for k-th and (k+M)-th periodic lists for interval 2M ms
|
||||
; is the k-th periodic list for interval M ms, M >= 1. In this scheme,
|
||||
; if two "previous" lists are served in the frames k,k+2M,k+4M,...
|
||||
; and k+M,k+3M,k+5M,... correspondingly, the "next" list is served in
|
||||
; the frames k,k+M,k+2M,k+3M,k+4M,k+5M,..., which is exactly what we want.
|
||||
; - The links between Periodic, Control, Bulk lists and the processing of
|
||||
; Isochronous endpoints are controller-specific.
|
||||
; * The head of every processing list is a static entry which does not
|
||||
; correspond to any real pipe. It is described by usb_static_ep
|
||||
; structure, not usb_pipe. For OHCI and UHCI, sizeof.usb_static_ep plus
|
||||
; sizeof hardware part is 20h, the total number of lists is
|
||||
; 32+16+8+4+2+1+1+1 = 65, so all these structures fit in one page,
|
||||
; leaving space for other data. This is another reason for 32ms limit.
|
||||
; * Static endpoint descriptors are kept in *hci_controller structure.
|
||||
; * All items in every processing list, including the static head, are
|
||||
; organized in a double-linked list using .NextVirt and .PrevVirt fields.
|
||||
; * [[item.NextVirt].PrevVirt] = [[item.PrevVirt].NextVirt] for all items.
|
||||
NextVirt dd ?
|
||||
; Next endpoint in the processing list.
|
||||
; See also PrevVirt field and the description before NextVirt field.
|
||||
PrevVirt dd ?
|
||||
; Previous endpoint in the processing list.
|
||||
; See also NextVirt field and the description before NextVirt field.
|
||||
;
|
||||
; Every pipe has the associated transfer queue, that is, the double-linked
|
||||
; list of Transfer Descriptors aka TD. For Control, Bulk and Interrupt
|
||||
; endpoints this list consists of usb_gtd structures
|
||||
; (GTD = General Transfer Descriptors), for Isochronous endpoints
|
||||
; this list consists of usb_itd structures, which are not developed yet.
|
||||
; The pipe needs to know only the last TD; the first TD can be
|
||||
; obtained as [[pipe.LastTD].NextVirt].
|
||||
LastTD dd ?
|
||||
; Last TD in the transfer queue.
|
||||
;
|
||||
; All opened pipes corresponding to the same physical device are organized in
|
||||
; the double-linked list using .NextSibling and .PrevSibling fields.
|
||||
; The head of this list is kept in usb_device_data structure (OpenedPipeList).
|
||||
; This list is used when the device is disconnected and all pipes for the
|
||||
; device should be closed.
|
||||
; Also, all pipes closed due to disconnect must remain valid at least until
|
||||
; driver-provided disconnect function returns; all should-be-freed-but-not-now
|
||||
; pipes for one device are organized in another double-linked list with
|
||||
; the head in usb_device_data.ClosedPipeList; this list uses the same link
|
||||
; fields, one pipe can never be in both lists.
|
||||
NextSibling dd ?
|
||||
; Next pipe for the physical device.
|
||||
PrevSibling dd ?
|
||||
; Previous pipe for the physical device.
|
||||
;
|
||||
; When hardware part of pipe is changed, some time is needed before further
|
||||
; actions so that hardware reacts on this change. During that time,
|
||||
; all changed pipes are organized in single-linked list with the head
|
||||
; usb_controller.WaitPipeList* and link field NextWait.
|
||||
; Currently there are two possible reasons to change:
|
||||
; change of address/packet size in initial configuration,
|
||||
; close of the pipe. They are distinguished by USB_FLAG_CLOSED.
|
||||
NextWait dd ?
|
||||
Lock MUTEX
|
||||
; Mutex that guards operations with transfer queue for this pipe.
|
||||
Type db ?
|
||||
; Type of pipe, one of {CONTROL,ISOCHRONOUS,BULK,INTERRUPT}_PIPE.
|
||||
Flags db ?
|
||||
; Combination of flags, USB_FLAG_*.
|
||||
rb 2 ; dword alignment
|
||||
DeviceData dd ?
|
||||
; Pointer to usb_device_data, common for all pipes for one device.
|
||||
ends
|
||||
|
||||
; This structure describes the static head of every list of pipes.
|
||||
struct usb_static_ep
|
||||
; software fields
|
||||
Bandwidth dd ?
|
||||
; valid only for interrupt/isochronous USB1 lists
|
||||
; The offsets of the following two fields must be the same in this structure
|
||||
; and in usb_pipe.
|
||||
NextVirt dd ?
|
||||
PrevVirt dd ?
|
||||
ends
|
||||
|
||||
; This structure represents one transfer descriptor
|
||||
; ('g' stands for "general" as opposed to isochronous usb_itd).
|
||||
; Note that one transfer can have several descriptors:
|
||||
; a control transfer has three stages.
|
||||
; Additionally, every controller has a limit on transfer length with
|
||||
; one descriptor (packet size for UHCI, 1K for OHCI, 4K for EHCI),
|
||||
; large transfers must be split into individual packets according to that limit.
|
||||
struct usb_gtd
|
||||
Callback dd ?
|
||||
; Zero for intermediate descriptors, pointer to callback function
|
||||
; for final descriptor. See the docs for description of the callback.
|
||||
UserData dd ?
|
||||
; Dword which is passed to Callback as is, not used by USB code itself.
|
||||
; Two following fields organize all descriptors for one pipe in
|
||||
; the linked list.
|
||||
NextVirt dd ?
|
||||
PrevVirt dd ?
|
||||
Pipe dd ?
|
||||
; Pointer to the parent usb_pipe.
|
||||
Buffer dd ?
|
||||
; Pointer to data for this descriptor.
|
||||
Length dd ?
|
||||
; Length of data for this descriptor.
|
||||
ends
|
||||
|
||||
; =============================================================================
|
||||
; =================================== Code ====================================
|
||||
; =============================================================================
|
||||
|
||||
USB_STDCALL_VERIFY = 1
|
||||
macro stdcall_verify [arg]
|
||||
{
|
||||
@ -216,7 +26,7 @@ endp
|
||||
proc usb_open_pipe stdcall uses ebx esi edi,\
|
||||
config_pipe:dword, endpoint:dword, maxpacket:dword, type:dword, interval:dword
|
||||
locals
|
||||
tt_vars rd (ehci_select_tt_interrupt_list.local_vars_size + 3) / 4
|
||||
tt_vars rd 24 ; should be enough for ehci_select_tt_interrupt_list
|
||||
targetsmask dd ? ; S-Mask for USB2
|
||||
bandwidth dd ?
|
||||
target dd ?
|
||||
@ -810,6 +620,27 @@ proc usb_unlink_td
|
||||
ret
|
||||
endp
|
||||
|
||||
; One part of transfer is completed, run the associated callback
|
||||
; or update total length in the next part of transfer.
|
||||
; in: ebx -> usb_gtd, ecx = status, edx = length
|
||||
proc usb_process_gtd
|
||||
; 1. Test whether it is the last descriptor in the transfer
|
||||
; <=> it has an associated callback.
|
||||
mov eax, [ebx+usb_gtd.Callback]
|
||||
test eax, eax
|
||||
jz .nocallback
|
||||
; 2. It has an associated callback; call it with corresponding parameters.
|
||||
stdcall_verify eax, [ebx+usb_gtd.Pipe], ecx, \
|
||||
[ebx+usb_gtd.Buffer], edx, [ebx+usb_gtd.UserData]
|
||||
ret
|
||||
.nocallback:
|
||||
; 3. It is an intermediate descriptor. Add its length to the length
|
||||
; in the following descriptor.
|
||||
mov eax, [ebx+usb_gtd.NextVirt]
|
||||
add [eax+usb_gtd.Length], edx
|
||||
ret
|
||||
endp
|
||||
|
||||
if USB_STDCALL_VERIFY
|
||||
proc verify_regs
|
||||
virtual at esp
|
||||
|
@ -29,11 +29,6 @@ USB_DEVICE_QUALIFIER_DESCR = 6
|
||||
USB_OTHER_SPEED_CONFIG_DESCR = 7
|
||||
USB_INTERFACE_POWER_DESCR = 8
|
||||
|
||||
; Possible speeds of USB devices
|
||||
USB_SPEED_FS = 0 ; full-speed
|
||||
USB_SPEED_LS = 1 ; low-speed
|
||||
USB_SPEED_HS = 2 ; high-speed
|
||||
|
||||
; Compile-time setting. If set, the code will dump all descriptors as they are
|
||||
; read to the debug board.
|
||||
USB_DUMP_DESCRIPTORS = 1
|
||||
@ -370,7 +365,7 @@ proc usb_set_address_callback stdcall, pipe:dword, status:dword, buffer:dword, l
|
||||
; so setting the address could take some time until the cache is evicted.
|
||||
; Thus, the call is asynchronous; meet us in usb_after_set_address when it will
|
||||
; be safe to continue.
|
||||
dbgstr 'address set in device'
|
||||
; dbgstr 'address set in device'
|
||||
call [eax+usb_hardware_func.SetDeviceAddress]
|
||||
; 2b. If the port is in non-root hub, clear 'reset in progress' flag.
|
||||
; In any case, proceed to 4.
|
||||
@ -409,7 +404,7 @@ endp
|
||||
; is cleared after request from usb_set_address_callback.
|
||||
; in: ebx -> usb_pipe
|
||||
proc usb_after_set_address
|
||||
dbgstr 'address set for controller'
|
||||
; dbgstr 'address set for controller'
|
||||
; Issue control transfer GET_DESCRIPTOR(DEVICE_DESCR) for first 8 bytes.
|
||||
; Remember, we still do not know the actual packet size;
|
||||
; 8-bytes-request is safe.
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -514,6 +514,8 @@ struct PCIDEV
|
||||
devfn db ?
|
||||
bus db ?
|
||||
irq_line db ?
|
||||
rb 1
|
||||
owner dd ? ; pointer to SRV or 0
|
||||
ends
|
||||
|
||||
; The following macro assume that we are on uniprocessor machine.
|
||||
|
@ -128,10 +128,35 @@ proc get_service stdcall, sz_name:dword
|
||||
mov edx, [edx+SRV.fd]
|
||||
jmp @B
|
||||
.not_load:
|
||||
mov eax, [sz_name]
|
||||
; Try to load .dll driver first. If not, fallback to .obj.
|
||||
push edi
|
||||
sub esp, 36
|
||||
mov edi, esp
|
||||
mov dword [edi], '/sys'
|
||||
mov dword [edi+4], '/dri'
|
||||
mov dword [edi+8], 'vers'
|
||||
mov byte [edi+12], '/'
|
||||
@@:
|
||||
mov dl, [eax]
|
||||
mov [edi+13], dl
|
||||
inc eax
|
||||
inc edi
|
||||
test dl, dl
|
||||
jnz @b
|
||||
mov dword [edi+12], '.sys'
|
||||
mov byte [edi+16], 0
|
||||
mov edi, esp
|
||||
stdcall load_pe_driver, edi, 0
|
||||
add esp, 36
|
||||
pop edi
|
||||
test eax, eax
|
||||
jnz .nothing
|
||||
pop ebp
|
||||
jmp load_driver
|
||||
.ok:
|
||||
mov eax, edx
|
||||
.nothing:
|
||||
ret
|
||||
endp
|
||||
|
||||
@ -322,7 +347,7 @@ endp
|
||||
; allocate kernel memory and loads the specified file
|
||||
;
|
||||
; param
|
||||
; file_name= full path to file
|
||||
; file_name= path to file
|
||||
;
|
||||
; retval
|
||||
; eax= file image in kernel memory
|
||||
|
@ -45,6 +45,7 @@ __exports:
|
||||
map_io_mem, 'MapIoMem', \ ; stdcall
|
||||
map_page, 'MapPage', \ ; stdcall
|
||||
get_pg_addr, 'GetPgAddr', \ ; eax
|
||||
get_phys_addr, 'GetPhysAddr', \ ; eax
|
||||
map_space, 'MapSpace', \
|
||||
release_pages, 'ReleasePages', \
|
||||
\
|
||||
@ -112,6 +113,7 @@ __exports:
|
||||
usb_normal_transfer_async, 'USBNormalTransferAsync', \
|
||||
usb_control_async, 'USBControlTransferAsync', \
|
||||
usb_get_param, 'USBGetParam', \
|
||||
usb_hc_func, 'USBHCFunc', \
|
||||
\
|
||||
NET_add_device, 'NetRegDev', \
|
||||
NET_remove_device, 'NetUnRegDev', \
|
||||
|
@ -284,8 +284,7 @@ proc alloc_kernel_space stdcall, size:dword
|
||||
cmp eax, [heap_free]
|
||||
ja .error
|
||||
|
||||
mov ecx, heap_mutex
|
||||
call mutex_lock
|
||||
spin_lock_irqsave heap_mutex
|
||||
|
||||
mov eax, [size]
|
||||
|
||||
@ -345,8 +344,7 @@ proc alloc_kernel_space stdcall, size:dword
|
||||
|
||||
call md.add_to_used
|
||||
|
||||
mov ecx, heap_mutex
|
||||
call mutex_unlock
|
||||
spin_unlock_irqrestore heap_mutex
|
||||
mov eax, [esi+block_base]
|
||||
pop edi
|
||||
pop esi
|
||||
@ -364,8 +362,7 @@ proc alloc_kernel_space stdcall, size:dword
|
||||
jmp .add_used
|
||||
|
||||
.error_unlock:
|
||||
mov ecx, heap_mutex
|
||||
call mutex_unlock
|
||||
spin_unlock_irqrestore heap_mutex
|
||||
.error:
|
||||
xor eax, eax
|
||||
pop edi
|
||||
@ -377,8 +374,7 @@ endp
|
||||
align 4
|
||||
proc free_kernel_space stdcall uses ebx ecx edx esi edi, base:dword
|
||||
|
||||
mov ecx, heap_mutex
|
||||
call mutex_lock
|
||||
spin_lock_irqsave heap_mutex
|
||||
|
||||
mov eax, [base]
|
||||
|
||||
@ -446,8 +442,7 @@ proc free_kernel_space stdcall uses ebx ecx edx esi edi, base:dword
|
||||
lea edx, [mem_block_list+eax*8]
|
||||
list_add edi, edx
|
||||
.m_eq:
|
||||
mov ecx, heap_mutex
|
||||
call mutex_unlock
|
||||
spin_unlock_irqrestore heap_mutex
|
||||
xor eax, eax
|
||||
not eax
|
||||
ret
|
||||
@ -459,8 +454,7 @@ proc free_kernel_space stdcall uses ebx ecx edx esi edi, base:dword
|
||||
jmp .add_block
|
||||
|
||||
.fail:
|
||||
mov ecx, heap_mutex
|
||||
call mutex_unlock
|
||||
spin_unlock_irqrestore heap_mutex
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
@ -544,17 +538,15 @@ proc kernel_free stdcall, base:dword
|
||||
|
||||
push ebx esi
|
||||
|
||||
mov ecx, heap_mutex
|
||||
call mutex_lock
|
||||
spin_lock_irqsave heap_mutex
|
||||
|
||||
mov eax, [base]
|
||||
call md.find_used
|
||||
|
||||
mov ecx, heap_mutex
|
||||
cmp [esi+block_flags], USED_BLOCK
|
||||
jne .fail
|
||||
|
||||
call mutex_unlock
|
||||
spin_unlock_irqrestore heap_mutex
|
||||
|
||||
mov eax, [esi+block_base]
|
||||
mov ecx, [esi+block_size]
|
||||
@ -564,7 +556,7 @@ proc kernel_free stdcall, base:dword
|
||||
pop esi ebx
|
||||
ret
|
||||
.fail:
|
||||
call mutex_unlock
|
||||
spin_unlock_irqrestore heap_mutex
|
||||
xor eax, eax
|
||||
pop esi ebx
|
||||
ret
|
||||
|
@ -1223,22 +1223,7 @@ f68:
|
||||
cmp edx, OS_BASE
|
||||
jae .fail
|
||||
|
||||
mov edi, edx
|
||||
stdcall load_PE, ecx
|
||||
mov esi, eax
|
||||
test eax, eax
|
||||
jz @F
|
||||
|
||||
push edi
|
||||
push DRV_ENTRY
|
||||
call eax
|
||||
add esp, 8
|
||||
test eax, eax
|
||||
jz @F
|
||||
|
||||
mov [eax+SRV.entry], esi
|
||||
|
||||
@@:
|
||||
stdcall load_pe_driver, ecx, edx
|
||||
mov [esp+32], eax
|
||||
ret
|
||||
.22:
|
||||
@ -1318,26 +1303,32 @@ f68call: ; keep this table closer to main code
|
||||
|
||||
|
||||
align 4
|
||||
proc load_pe_driver stdcall, file:dword
|
||||
proc load_pe_driver stdcall, file:dword, cmdline:dword
|
||||
push esi
|
||||
|
||||
stdcall load_PE, [file]
|
||||
test eax, eax
|
||||
jz .fail
|
||||
|
||||
mov esi, eax
|
||||
stdcall eax, DRV_ENTRY
|
||||
push [cmdline]
|
||||
push DRV_ENTRY
|
||||
call eax
|
||||
pop ecx
|
||||
pop ecx
|
||||
test eax, eax
|
||||
jz .fail
|
||||
|
||||
mov [eax+SRV.entry], esi
|
||||
pop esi
|
||||
ret
|
||||
|
||||
.fail:
|
||||
xor eax, eax
|
||||
pop esi
|
||||
ret
|
||||
endp
|
||||
|
||||
|
||||
align 4
|
||||
proc init_mtrr
|
||||
|
||||
@ -1385,9 +1376,9 @@ proc init_mtrr
|
||||
xor eax, eax
|
||||
xor edx, edx
|
||||
@@:
|
||||
wrmsr
|
||||
inc ecx
|
||||
cmp ecx, 0x210
|
||||
wrmsr
|
||||
cmp ecx, 0x20F
|
||||
jb @b
|
||||
; enable MTRRs
|
||||
pop eax
|
||||
|
@ -85,13 +85,12 @@ L3:
|
||||
mov ecx, eax
|
||||
add edi, DWORD PTR [edx+260]
|
||||
|
||||
add ecx, 3
|
||||
shr ecx, 2
|
||||
rep movsd
|
||||
|
||||
L4:
|
||||
mov ecx, DWORD PTR [edx+256]
|
||||
add ecx, 4095
|
||||
and ecx, -4096
|
||||
cmp ecx, eax
|
||||
jbe L6
|
||||
sub ecx, eax
|
||||
@ -111,15 +110,17 @@ L2:
|
||||
mov edi, DWORD PTR [esp+32]
|
||||
cmp DWORD PTR [edi+164], 0
|
||||
je L9
|
||||
pushd [edi+164]
|
||||
mov esi, ebp
|
||||
mov ecx, ebp
|
||||
sub esi, DWORD PTR [edi+52]
|
||||
add ecx, DWORD PTR [edi+160]
|
||||
mov eax, esi
|
||||
shr eax, 16
|
||||
mov DWORD PTR [esp+12], eax
|
||||
jmp L11
|
||||
mov DWORD PTR [esp+16], eax
|
||||
L12:
|
||||
mov eax, [ecx+4]
|
||||
sub [esp], eax
|
||||
lea ebx, [eax-8]
|
||||
xor edi, edi
|
||||
shr ebx, 1
|
||||
@ -136,7 +137,7 @@ L14:
|
||||
je L18
|
||||
dec ax
|
||||
jne L15
|
||||
mov eax, DWORD PTR [esp+12]
|
||||
mov eax, DWORD PTR [esp+16]
|
||||
add WORD PTR [edx+ebp], ax
|
||||
L17:
|
||||
add WORD PTR [edx+ebp], si
|
||||
@ -149,9 +150,9 @@ L13:
|
||||
jne L14
|
||||
add ecx, DWORD PTR [ecx+4]
|
||||
L11:
|
||||
mov eax, DWORD PTR [ecx+4]
|
||||
test eax, eax
|
||||
jne L12
|
||||
cmp dword [esp], 0
|
||||
jg L12
|
||||
pop eax
|
||||
L9:
|
||||
mov edx, DWORD PTR [esp+32]
|
||||
cmp DWORD PTR [edx+132], 0
|
||||
@ -178,6 +179,10 @@ L23:
|
||||
mov ecx, DWORD PTR [eax-4]
|
||||
mov DWORD PTR [esp+48], edi
|
||||
mov edx, DWORD PTR [eax-20]
|
||||
test edx, edx
|
||||
jnz @f
|
||||
mov edx, ecx
|
||||
@@:
|
||||
mov DWORD PTR [esp+52], 0
|
||||
add ecx, ebp
|
||||
add edx, ebp
|
||||
|
@ -386,7 +386,18 @@ sys_resize_app_memory:
|
||||
; cmp eax,1
|
||||
dec ebx
|
||||
jnz .no_application_mem_resize
|
||||
|
||||
mov eax, [pg_data.pages_free]
|
||||
shl eax, 12
|
||||
cmp eax, ecx
|
||||
jae @f
|
||||
|
||||
xor eax, eax
|
||||
inc eax
|
||||
jmp .store_result
|
||||
@@:
|
||||
stdcall new_mem_resize, ecx
|
||||
.store_result:
|
||||
mov [esp+32], eax
|
||||
.no_application_mem_resize:
|
||||
ret
|
||||
|
@ -517,6 +517,7 @@ end if
|
||||
add edi, page_tabs
|
||||
.remap:
|
||||
lodsd
|
||||
and eax, 0xFFFFF000
|
||||
or eax, ebx; force user level r/w access
|
||||
stosd
|
||||
add edx, 0x1000
|
||||
|
@ -3,15 +3,18 @@
|
||||
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;; 20/11/2013 yogev_ezra: Initial version ;;
|
||||
;; Thanks for help to: dunkaist, eAndrew, hidnplayr, Mario ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision: 4261 $
|
||||
; 20/11/2013 yogev_ezra: Initial version (Vortex86 SoC type detection)
|
||||
; 26/11/2013 yogev_ezra: Added CPU speed modifier and MMX support flag detection
|
||||
; Thanks for help to: dunkaist, eAndrew, hidnplayr, Mario
|
||||
|
||||
$Revision: 4310 $
|
||||
|
||||
VORTEX86DEBUG = 0 ; For testing in emulators and in non-Vortex86 CPU computers, set this to 1
|
||||
VORTEX86DEBUGVALUE = 0x35504d44 ; FAKE port output = used for testing
|
||||
NORTH_BRIDGE = 0x80000000 ; Base address of Vortex86 PCI North Bridge
|
||||
SOUTH_BRIDGE = 0x80003800 ; Base address of Vortex86 PCI South Bridge
|
||||
|
||||
; Detect Vortex86 CPU and generate CPU name in string format (PCI address at 93H~90H in Vortex86 North Bridge contains SoC type)
|
||||
; Available Vortex86 CPU codes taken from Coreboot project. New codes should be added to "Vortex86SoClist" below
|
||||
@ -29,11 +32,11 @@ Vortex86SoCname db 'Vortex86 ',0 ; This variable will hold the full name
|
||||
Vortex86SoClist: ; List of Vortex86 CPUs known today. Add new record to this list when new CPU becomes available
|
||||
db 0x31, 'SX ' ; id=1
|
||||
db 0x32, 'DX ' ; id=2
|
||||
db 0x33, 'MX ' ; id=3
|
||||
db 0x33, 'MX ' ; id=3 MMX is available starting from CPU code 'MX' (id=3)
|
||||
db 0x34, 'DX2' ; id=4
|
||||
db 0x35, 'MX+' ; id=5
|
||||
db 0x37, 'EX ' ; id=6
|
||||
Vortex86SoCnum = ($ - Vortex86SoClist) / 4 ; Calculate the total number of known Vortex86 CPUs (if id=Vortex86SoCnum+1 --> unknown SoC)
|
||||
db 0x37, 'EX ' ; id=7
|
||||
Vortex86SoCnum = ($ - Vortex86SoClist) / 4 ; Calculate the total number of known Vortex86 CPUs
|
||||
endg
|
||||
|
||||
; When in debug mode, perform SoC detection regardless of the actual CPU vendor (even for vendors other than DMP)
|
||||
@ -43,55 +46,113 @@ if ~ VORTEX86DEBUG
|
||||
jnz .Vortex86end ; If the CPU vendor is not 'Vortex86 SoC', skip the SoC detection
|
||||
end if
|
||||
|
||||
mov dx, 0xcf8 ; CF8h = Vortex86 PCI Configuration Address port
|
||||
mov eax, 0x80000090 ; 0x80000090 = Starting PCI address to read from (32-bit register - accessed as DWORD)
|
||||
out dx, eax ; Send request to PCI address port to retrieve data from this address
|
||||
mov dx, 0xcfc ; CFCh = Vortex86 PCI Configuration Data port
|
||||
in eax, dx ; Read data (SoC type) from PCI data port
|
||||
mov eax, NORTH_BRIDGE+0x90 ; 0x80000090 = PCI Configuration Address Register to read from (32-bit register - accessed as DWORD)
|
||||
call .Vortex86PCIreg ; Get the CPU code from Vortex86 SoC North Bridge PCI register (Register Offset: 93H~90H)
|
||||
|
||||
if VORTEX86DEBUG ; When in debug mode, pretend that we received port output equal to "VORTEX86DEBUGVALUE"
|
||||
mov eax, VORTEX86DEBUGVALUE
|
||||
end if
|
||||
|
||||
DEBUGF 1, "K : Vortex86 SoC register returned 0x"
|
||||
test eax, eax ; We need to break out in case the result is '\0' since otherwise we will fail at NULL string
|
||||
jz .nullPCIoutput
|
||||
mov [Vortex86CPUcode], eax
|
||||
DEBUGF 1, "%x (%s): ", eax, Vortex86CPUcode
|
||||
cmp ax, 4d44h ; Check whether it's Vortex86 family (all Vortex86 SoC have ID in form of "0xNN504d44")
|
||||
jnz .notVortex86
|
||||
shr eax, 16 ; Discard lower word in EAX which is always 4d44h in Vortex86 family
|
||||
cmp al, 50h ; The 3rd byte is always 50h in Vortex86 SoC (if this is the case, we need just the highest byte)
|
||||
jnz .notVortex86
|
||||
mov bl, ah ; Copy SoC type to BL since EAX (that includes AH) is used implicitly in "LODSD" command below
|
||||
DEBUGF 1, "K : Vortex86 SoC type register (93H~90H) returned 0x"
|
||||
test eax, eax ; Check whether the port output was '\0'
|
||||
jz .nullPCIoutput ; In case the result is '\0' (NULL), skip further testing and exit
|
||||
mov [Vortex86CPUcode], eax ; Save HEX CPU code to Vortex86CPUcode (so it can be used later)
|
||||
DEBUGF 1, "%x (%s): ", eax, Vortex86CPUcode ; Print the CPU code (as HEX and as string) to debug log
|
||||
|
||||
mov ebx, 0x444d5000 ; Apply Vortex86 CPU code mask (all Vortex86 SoC have ID in form of "0xNN504d44")
|
||||
bswap eax ; Assumed it is Vortex86 SoC, the highest byte identifies the exact CPU, so move it to the lowest byte
|
||||
mov bl, al ; Copy SoC type to BL since EAX (that includes AL) is used implicitly in "LODSD" command below
|
||||
cmp eax, ebx ; Now see whether the 3 higher bytes were "0x504d44" (which means it's Vortex86)
|
||||
jnz .notVortex86 ; If it's not Vortex86 - go say so and exit
|
||||
|
||||
sub al, 0x30 ; Current Vortex86 CPU codes are in the range of 31h-37h, so convert them to integer (1,2,...)
|
||||
mov [Vortex86CPUid], al ; Save the CPUid (1=Vortex86SX, 2=Vortex86DX, ..., 7=Vortex86EX, ...)
|
||||
|
||||
mov esi, Vortex86SoClist ; ESI points to the start of Vortex86SoClist (used implicitly in "LODSD" command below)
|
||||
xor ecx, ecx ; Zero ECX (it is used as counter)
|
||||
cld ; Clears the DF flag in the EFLAGS register (DF=0 --> String operations increment ESI)
|
||||
@@:
|
||||
inc ecx ; Increment our counter
|
||||
cmp ecx, Vortex86SoCnum ; Check if we iterated Vortex86SoCnum times already (i.e. went over the entire Vortex86SoClist)
|
||||
ja .unknownVortex86 ; If the entire list was tested and our CPU is not in that list, it is unknown Vortex86 SoC
|
||||
inc ecx ; Increment our counter
|
||||
lodsd ; Load DWORD at address DS:ESI into EAX (puts 1 line from Vortex86SoClist into EAX, then increments ESI)
|
||||
cmp bl, al ; Check if our CPU matches the current record in the list
|
||||
jne @b ; No match --> repeat with next record
|
||||
|
||||
shr eax, 8 ; Match found --> drop the SoC type code from Vortex86SoClist name and replace it with \0
|
||||
mov dword [Vortex86SoCname+8], eax ; Concatenate it with prefix to receive complete SoC name (\0 is string termination)
|
||||
mov [Vortex86CPUid], cl ; Save the CPUid (1=Vortex86SX, 2=Vortex86DX, ..., Vortex86SoCnum+1=Unknown Vortex86)
|
||||
|
||||
DEBUGF 1, "%s (id=%d)\n", Vortex86SoCname, [Vortex86CPUid]:1
|
||||
jmp .Vortex86end ; Say what we have found (CPU name and id) and exit
|
||||
|
||||
.nullPCIoutput: ; Emulators and non-Vortex86 CPU computers will usually return \0 in this register
|
||||
DEBUGF 1, "0 (NULL)\n"
|
||||
jmp .Vortex86end
|
||||
|
||||
.unknownVortex86:
|
||||
mov [Vortex86CPUid], cl ; Save the CPUid (Vortex86SoCnum+1=Unknown Vortex86)
|
||||
DEBUGF 1, "unknown Vortex86 CPU (id=%d, last known is %d)\n", [Vortex86CPUid]:1, Vortex86SoCnum
|
||||
jmp .Vortex86end
|
||||
DEBUGF 1, "%s (id=%d)\n", Vortex86SoCname, [Vortex86CPUid]:1 ; Say what we have found (CPU name and id)
|
||||
jmp .Vortex86
|
||||
|
||||
.notVortex86: ; In case this register is used by other CPUs for other purpose, it's interesting what it contains
|
||||
DEBUGF 1, "not a Vortex86 CPU\n"
|
||||
jmp .Vortex86end
|
||||
|
||||
.unknownVortex86: ; It is Vortex86 CPU, but it's not in the list above
|
||||
DEBUGF 1, "unknown Vortex86 CPU (id=%d)\n", [Vortex86CPUid]:1 ; Inform the user that the CPU is Vortex86 but name is unknown
|
||||
|
||||
.Vortex86:
|
||||
mov eax, NORTH_BRIDGE+0x60 ; 0x80000060 = PCI Configuration Address Register to read from (32-bit register - accessed as DWORD)
|
||||
call .Vortex86PCIreg ; Get current flags of Vortex86SoC North Bridge STRAP Register (Register Offset: 63h~60h)
|
||||
DEBUGF 1, "K : Vortex86 STRAP Register (63h~60h) returned 0x%x\n",eax
|
||||
|
||||
mov eax, SOUTH_BRIDGE+0xC0 ; 0x800038C0 = PCI Configuration Address Register to read from (32-bit register - accessed as DWORD)
|
||||
call .Vortex86PCIreg ; Flags of Vortex86 South Bridge Internal Peripheral Feature Control Register (Register Offset: C3h~C0h)
|
||||
DEBUGF 1, "K : Vortex86 Internal Peripheral Feature Control Register (C3h~C0h) returned 0x%x\n",eax
|
||||
|
||||
mov eax, SOUTH_BRIDGE+0xCC ; 0x800038CC = PCI Configuration Address Register to read from (8-bit register - accessed as BYTE)
|
||||
call .Vortex86PCIreg ; Flags of Vortex86 South Bridge Internal Peripheral Feature Control Register III (Register Offset: CCh)
|
||||
DEBUGF 1, "K : Vortex86 Internal Peripheral Feature Control Register III (CCh) returned 0x%x\n",al
|
||||
|
||||
mov eax, NORTH_BRIDGE+0xA0 ; 0x800000A0 = PCI Configuration Address Register to read from (32-bit register - accessed as DWORD)
|
||||
call .Vortex86PCIreg ; Get current flags of Vortex86SoC North Bridge Host Control Register (Register Offset: A3h~A0h)
|
||||
DEBUGF 1, "K : Vortex86 Host Control Register (A3h~A0h) returned 0x%x: CPU speed is ",eax
|
||||
mov bl, al ; The lower byte of Vortex86 Host Control Register contains CPU speed modifier and MMX support status
|
||||
mov bh, al ; Backup the current AL value, so later we can test whether the value has changed
|
||||
and bl, 00000111b ; CPU speed modifier is stored in bits 0-2. Value=0 means MAX speed, other values - speed reduction
|
||||
jz .Vortex86CPUspeedMAX ; 0s in bits 0-2: CPU is at MAX speed (no need to modify)
|
||||
inc ebx ; The actual value is 1 less than 'Divide by' setting (value '001' means 'Divide by 2', etc.)
|
||||
DEBUGF 1, "reduced (divide by %d).\nK : Vortex86 changing CPU speed to ", bl ; Print the current CPU speed modifier to the log
|
||||
and al, 11111000b ; At least one of the bits 0-2 contains 1: CPU is at reduced speed. Set bits 0-2 to 0s to change to MAX
|
||||
.Vortex86CPUspeedMAX:
|
||||
DEBUGF 1, "MAX\n" ; Now the CPU should be running at MAX speed (don't write the value to PCI port yet)
|
||||
|
||||
cmp [Vortex86CPUid], 3 ; MMX is available starting from CPU code 'MX' (id=3)
|
||||
jb .skipVortex86MMX ; No MMX support - skip MMX support status detection (for id=1,2)
|
||||
DEBUGF 1, "K : Vortex86 MMX support status: MMX is " ; Bits 5-6 in Host Control Register contain MMX status
|
||||
test al, 100000b ; On MMX-capable Vortex86 SoC, Bit5 = is MMX enabled? (1=Yes/0=No)
|
||||
jnz .Vortex86MMXenabled ; MMX is already enabled (Bit5=1)
|
||||
DEBUGF 1, "DISABLED - enabling it for this session\n" ; Print to the log that MMX is disabled
|
||||
or al, 100000b ; Enable MMX support (don't write the value to PCI port yet)
|
||||
jmp .AfterMMXenabled
|
||||
.Vortex86MMXenabled:
|
||||
DEBUGF 1, "ENABLED\n" ; Print to the log that MMX is enabled
|
||||
.AfterMMXenabled:
|
||||
DEBUGF 1, "K : Vortex86 MMX report to CPUID: " ; Print to the log what CPUID command knowns about MMX support
|
||||
test al, 1000000b ; On MMX-capable Vortex86 SoC, Bit6 = report MMX support to CPUID? (1=Yes/0=No)
|
||||
jnz .Vortex86MMXreported ; MMX is already reported to CPUID (Bit6=1)
|
||||
DEBUGF 1, "OFF - turning it ON for this session\n" ; Print to the log that MMX will now be reported to CPUID
|
||||
or al, 1000000b ; Turn on MMX reporting to CPUID (don't write the value to PCI port yet)
|
||||
jmp .skipVortex86MMX
|
||||
.Vortex86MMXreported:
|
||||
DEBUGF 1, "ON\n" ; Print to the log that MMX reporting to CPUID is enabled
|
||||
|
||||
.skipVortex86MMX:
|
||||
cmp bh, al ; Check whether AL has changed before (if it did, we need to write it back to PCI port)
|
||||
jz .Vortex86end ; No change - no need to write to the port
|
||||
out dx, al ; Write the changed data to PCI port
|
||||
DEBUGF 1, "K : Vortex86 Host Control Register (A3h~A0h) new value is 0x%x\n",eax
|
||||
jmp .Vortex86end
|
||||
|
||||
.Vortex86PCIreg: ; Procedure receives input register value in EAX, and returns the output value also in EAX
|
||||
mov dx, 0xcf8 ; CF8h = Vortex86 PCI Configuration Address port
|
||||
out dx, eax ; Send request to PCI address port to retrieve data from this address
|
||||
mov dl, 0xfc ; CFCh = Vortex86 PCI Configuration Data port
|
||||
in eax, dx ; Read data from PCI data port
|
||||
ret
|
||||
|
||||
.nullPCIoutput: ; Emulators and non-Vortex86 CPU computers will usually return \0 in this register
|
||||
DEBUGF 1, "0 (NULL)\n"
|
||||
|
||||
.Vortex86end:
|
@ -458,6 +458,23 @@ if DUMP_PACKETS
|
||||
DEBUGF 1,'\n'
|
||||
end if
|
||||
stdcall USBNormalTransferAsync, [esi+usb_device_data.OutPipe], edx, command_block_wrapper.sizeof, request_callback1, esi, 0
|
||||
test eax, eax
|
||||
jz .nothing
|
||||
; 5. If the next stage is data stage in the same direction, enqueue it here.
|
||||
cmp [esi+usb_device_data.Command.Flags], 0
|
||||
js .nothing
|
||||
cmp [esi+usb_device_data.Command.Length], 0
|
||||
jz .nothing
|
||||
mov edx, [esi+usb_device_data.RequestsQueue+request_queue_item.Next]
|
||||
if DUMP_PACKETS
|
||||
DEBUGF 1,'K : USBSTOR out:'
|
||||
mov eax, [edx+request_queue_item.Buffer]
|
||||
mov ecx, [esi+usb_device_data.Command.Length]
|
||||
call debug_dump
|
||||
DEBUGF 1,'\n'
|
||||
end if
|
||||
stdcall USBNormalTransferAsync, [esi+usb_device_data.OutPipe], [edx+request_queue_item.Buffer], [esi+usb_device_data.Command.Length], request_callback2, esi, 0
|
||||
.nothing:
|
||||
ret
|
||||
endp
|
||||
|
||||
@ -526,28 +543,21 @@ end virtual
|
||||
; 3. Increment the stage.
|
||||
mov edx, [ecx+usb_device_data.RequestsQueue+request_queue_item.Next]
|
||||
inc [edx+request_queue_item.Stage]
|
||||
; 4. If there is no data, skip this stage.
|
||||
; 4. Check whether we need to send the data.
|
||||
; 4a. If there is no data, skip this stage.
|
||||
cmp [ecx+usb_device_data.Command.Length], 0
|
||||
jz ..request_get_status
|
||||
; 5. Initiate USB transfer. If this fails, go to the error handler.
|
||||
mov eax, [ecx+usb_device_data.InPipe]
|
||||
; 4b. If data were enqueued in the first stage, do nothing, wait for request_callback2.
|
||||
cmp [ecx+usb_device_data.Command.Flags], 0
|
||||
js @f
|
||||
mov eax, [ecx+usb_device_data.OutPipe]
|
||||
if DUMP_PACKETS
|
||||
DEBUGF 1,'K : USBSTOR out:'
|
||||
push eax ecx
|
||||
mov eax, [edx+request_queue_item.Buffer]
|
||||
mov ecx, [ecx+usb_device_data.Command.Length]
|
||||
call debug_dump
|
||||
pop ecx eax
|
||||
DEBUGF 1,'\n'
|
||||
end if
|
||||
@@:
|
||||
stdcall USBNormalTransferAsync, eax, [edx+request_queue_item.Buffer], [ecx+usb_device_data.Command.Length], request_callback2, ecx, 0
|
||||
jns .nothing
|
||||
; 5. Initiate USB transfer. If this fails, go to the error handler.
|
||||
stdcall USBNormalTransferAsync, [ecx+usb_device_data.InPipe], [edx+request_queue_item.Buffer], [ecx+usb_device_data.Command.Length], request_callback2, ecx, 0
|
||||
test eax, eax
|
||||
jz .error
|
||||
; 6. Return.
|
||||
; 6. The status stage goes to the same direction, enqueue it now.
|
||||
mov ecx, [.calldata]
|
||||
jmp ..enqueue_status
|
||||
.nothing:
|
||||
ret 20
|
||||
.error:
|
||||
; Error.
|
||||
@ -596,15 +606,20 @@ end if
|
||||
test eax, eax
|
||||
jnz .error
|
||||
; No error.
|
||||
; If the previous stage was in same direction, do nothing; status request is already enqueued.
|
||||
cmp [ecx+usb_device_data.Command.Flags], 0
|
||||
js .nothing
|
||||
..request_get_status:
|
||||
; 3. Increment the stage.
|
||||
mov edx, [ecx+usb_device_data.RequestsQueue+request_queue_item.Next]
|
||||
inc [edx+request_queue_item.Stage]
|
||||
; 4. Initiate USB transfer. If this fails, go to the error handler.
|
||||
..enqueue_status:
|
||||
lea edx, [ecx+usb_device_data.Status]
|
||||
stdcall USBNormalTransferAsync, [ecx+usb_device_data.InPipe], edx, command_status_wrapper.sizeof, request_callback3, ecx, 0
|
||||
test eax, eax
|
||||
jz .error
|
||||
.nothing:
|
||||
ret 20
|
||||
.error:
|
||||
; Error.
|
||||
|
@ -1884,7 +1884,6 @@ align 4
|
||||
; get WinMap start
|
||||
push esi
|
||||
mov esi, [_display.width]
|
||||
; imul edi, ebx
|
||||
mov edi, [d_width_calc_area + ebx*4]
|
||||
|
||||
add edi, eax
|
||||
|
@ -41,6 +41,8 @@ proc mem_test
|
||||
mov [BOOT_VARS-OS_BASE + 0x9108], eax
|
||||
mov [BOOT_VARS-OS_BASE + 0x910C], edi
|
||||
mov [BOOT_VARS-OS_BASE + 0x9110], eax
|
||||
inc eax
|
||||
mov [BOOT_VARS-OS_BASE + 0x9114], eax
|
||||
.ret:
|
||||
ret
|
||||
endp
|
||||
|
@ -2540,10 +2540,10 @@ sysfn_mouse_acceleration: ; 18.19 = set/get mouse features
|
||||
; cmp ecx,4 ; set mouse pointer position
|
||||
dec ecx
|
||||
jnz .set_mouse_button
|
||||
cmp dx, word[_display.width]
|
||||
cmp dx, word[_display.height]
|
||||
jae .end
|
||||
rol edx, 16
|
||||
cmp dx, word[_display.height]
|
||||
cmp dx, word[_display.width]
|
||||
jae .end
|
||||
mov [MOUSE_X], edx
|
||||
call wakeup_osloop
|
||||
|
@ -237,6 +237,8 @@ include "blkdev/ide_cache.inc"
|
||||
|
||||
; HD drive controller
|
||||
include "blkdev/hd_drv.inc"
|
||||
; Access through BIOS
|
||||
include "blkdev/bd_drv.inc"
|
||||
|
||||
; CD drive controller
|
||||
|
||||
|
@ -19,6 +19,13 @@
|
||||
$Revision: 3515 $
|
||||
|
||||
IPv4_MAX_FRAGMENTS = 64
|
||||
IPv4_MAX_ROUTES = 64
|
||||
|
||||
IPv4_ROUTE_FLAG_UP = 1 shl 0
|
||||
IPv4_ROUTE_FLAG_GATEWAY = 1 shl 1
|
||||
IPv4_ROUTE_FLAG_HOST = 1 shl 2
|
||||
IPv4_ROUTE_FLAG_D = 1 shl 3 ; Route was created by a redirect
|
||||
IPv4_ROUTE_FLAG_M = 1 shl 4 ; Route was modified by a redirect
|
||||
|
||||
struct IPv4_header
|
||||
|
||||
@ -54,6 +61,16 @@ struct IPv4_FRAGMENT_entry ; This structure will replace the ethern
|
||||
; Ip header begins here (we will need the IP header to re-construct the complete packet)
|
||||
ends
|
||||
|
||||
struct IPv4_ROUTE
|
||||
|
||||
Destination dd ?
|
||||
Gateway dd ?
|
||||
Flags dd ?
|
||||
Use dd ?
|
||||
Interface dd ?
|
||||
|
||||
ends
|
||||
|
||||
|
||||
uglobal
|
||||
align 4
|
||||
@ -70,6 +87,8 @@ align 4
|
||||
|
||||
IPv4_FRAGMENT_LIST rb IPv4_MAX_FRAGMENTS * sizeof.IPv4_FRAGMENT_slot
|
||||
|
||||
IPv4_ROUTES rd IPv4_MAX_ROUTES * sizeof.IPv4_ROUTE
|
||||
|
||||
endg
|
||||
|
||||
|
||||
|
@ -230,7 +230,7 @@ ICMP_input:
|
||||
test eax, eax
|
||||
jnz @f
|
||||
call NET_ptr_to_num4
|
||||
inc [UDP_PACKETS_TX + edi]
|
||||
inc [ICMP_PACKETS_TX + edi]
|
||||
@@:
|
||||
ret
|
||||
|
||||
|
@ -35,7 +35,7 @@ LOOPBACK_DEVICE:
|
||||
.packets_rx dd 0
|
||||
|
||||
.link_state dd -1
|
||||
.hwacc dd 0
|
||||
.hwacc dd NET_HWACC_TCP_IPv4_IN + NET_HWACC_TCP_IPv4_OUT
|
||||
|
||||
.namestr db 'loopback', 0
|
||||
|
||||
|
@ -28,7 +28,7 @@ struct SOCKET
|
||||
PID dd ? ; process ID
|
||||
TID dd ? ; thread ID
|
||||
Domain dd ? ; INET/LOCAL/..
|
||||
Type dd ? ; RAW/STREAM/DGRAP
|
||||
Type dd ? ; RAW/STREAM/DGRAM
|
||||
Protocol dd ? ; ICMP/IPv4/ARP/TCP/UDP
|
||||
errorcode dd ?
|
||||
device dd ? ; driver pointer, socket pointer if it's an LOCAL socket
|
||||
@ -92,8 +92,8 @@ struct TCP_SOCKET IP_SOCKET
|
||||
SND_MAX dd ?
|
||||
|
||||
; congestion control
|
||||
SND_CWND dd ?
|
||||
SND_SSTHRESH dd ?
|
||||
SND_CWND dd ? ; congestion window
|
||||
SND_SSTHRESH dd ? ; slow start threshold
|
||||
|
||||
;----------------------
|
||||
; Transmit timing stuff
|
||||
@ -141,10 +141,6 @@ struct TCP_SOCKET IP_SOCKET
|
||||
|
||||
seg_next dd ? ; re-assembly queue
|
||||
|
||||
temp_bits db ?
|
||||
rb 3 ; align
|
||||
|
||||
|
||||
ends
|
||||
|
||||
struct UDP_SOCKET IP_SOCKET
|
||||
@ -715,12 +711,13 @@ SOCKET_close:
|
||||
ret
|
||||
|
||||
.tcp:
|
||||
cmp [eax + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED ; state must be LISTEN, SYN_SENT or CLOSED
|
||||
jb .free
|
||||
|
||||
call TCP_usrclosed
|
||||
call TCP_output ;;;; Fixme: is this nescessary??
|
||||
call SOCKET_free
|
||||
|
||||
test eax, eax
|
||||
jz @f
|
||||
call TCP_output ; If connection is not closed yet, send the FIN
|
||||
@@:
|
||||
|
||||
ret
|
||||
|
||||
@ -1562,10 +1559,10 @@ SOCKET_ring_write:
|
||||
pop ecx
|
||||
|
||||
; unlock mutex
|
||||
push eax ecx
|
||||
pusha
|
||||
lea ecx, [eax + RING_BUFFER.mutex]
|
||||
call mutex_unlock ; TODO: check what registers this function actually destroys
|
||||
pop ecx eax
|
||||
popa
|
||||
|
||||
ret
|
||||
|
||||
@ -2085,7 +2082,6 @@ SOCKET_num_to_ptr:
|
||||
mov eax, [eax + SOCKET.NextPtr]
|
||||
or eax, eax
|
||||
jz .error
|
||||
diff16 "tetten", 0, $
|
||||
cmp [eax + SOCKET.Number], ecx
|
||||
jne .next_socket
|
||||
|
||||
@ -2205,7 +2201,7 @@ SOCKET_check_owner:
|
||||
;
|
||||
; Kernel calls this function when a certain process ends
|
||||
; This function will check if the process had any open sockets
|
||||
; And update them accordingly
|
||||
; And update them accordingly (clean up)
|
||||
;
|
||||
; IN: edx = pid
|
||||
; OUT: /
|
||||
@ -2251,7 +2247,7 @@ SOCKET_process_end:
|
||||
cmp [eax + SOCKET.Protocol], IP_PROTO_TCP
|
||||
jne .free
|
||||
|
||||
call TCP_close
|
||||
call TCP_disconnect
|
||||
jmp .closed
|
||||
|
||||
.free:
|
||||
@ -2356,20 +2352,9 @@ SOCKET_is_disconnected:
|
||||
and [eax + SOCKET.state], not (SS_ISCONNECTING + SS_ISCONNECTED + SS_ISDISCONNECTING)
|
||||
or [eax + SOCKET.state], SS_CANTRCVMORE + SS_CANTSENDMORE
|
||||
|
||||
cmp [eax + SOCKET.Protocol], IP_PROTO_TCP
|
||||
je .tcp
|
||||
|
||||
cmp [eax + SOCKET.Protocol], IP_PROTO_UDP
|
||||
je .udp
|
||||
|
||||
jmp SOCKET_notify
|
||||
|
||||
.tcp:
|
||||
.udp:
|
||||
mov [eax + UDP_SOCKET.LocalPort], 0 ; UDP and TCP structs store localport at the same offset
|
||||
mov [eax + UDP_SOCKET.RemotePort], 0
|
||||
|
||||
jmp SOCKET_notify
|
||||
|
||||
|
||||
;-----------------------------------------------------------------
|
||||
|
@ -110,7 +110,7 @@ SS_MORETOCOME = 0x4000
|
||||
SS_BLOCKED = 0x8000
|
||||
|
||||
|
||||
SOCKET_MAXDATA = 4096*32 ; must be 4096*(power of 2) where 'power of 2' is at least 8
|
||||
SOCKET_MAXDATA = 4096*8 ; must be 4096*(power of 2) where 'power of 2' is at least 8
|
||||
MAX_backlog = 20 ; maximum backlog for stream sockets
|
||||
|
||||
; Error Codes
|
||||
@ -152,7 +152,8 @@ NET_LINK_PPP = 2 ; Point to Point Protocol (PPPoE, ...)
|
||||
NET_LINK_IEEE802.11 = 3 ; IEEE 802.11 (WiFi)
|
||||
|
||||
; Hardware acceleration bits
|
||||
HWACC_TCP_IPv4 = 1 shl 0
|
||||
NET_HWACC_TCP_IPv4_IN = 1 shl 0
|
||||
NET_HWACC_TCP_IPv4_OUT = 1 shl 1
|
||||
|
||||
struct NET_DEVICE
|
||||
|
||||
|
@ -143,6 +143,62 @@ align 4
|
||||
TCP_input_event dd ?
|
||||
endg
|
||||
|
||||
uglobal
|
||||
align 4
|
||||
|
||||
TCPS_accepts dd ? ; #SYNs received in LISTEN state
|
||||
TCPS_closed dd ? ; #connections closed (includes drops)
|
||||
TCPS_connattempt dd ? ; #connections initiated (calls to connect)
|
||||
TCPS_conndrops dd ? ; #embryonic connections dropped (before SYN received)
|
||||
TCPS_connects dd ? ; #connections established actively or passively
|
||||
TCPS_delack dd ? ; #delayed ACKs sent
|
||||
TCPS_drops dd ? ; #connections dropped (after SYN received)
|
||||
TCPS_keepdrops dd ? ; #connections dropped in keepalive (established or awaiting SYN)
|
||||
TCPS_keepprobe dd ? ; #keepalive probes sent
|
||||
TCPS_keeptimeo dd ? ; #times keepalive timer or connections-establishment timer expire
|
||||
TCPS_pawsdrop dd ? ; #segments dropped due to PAWS
|
||||
TCPS_pcbcachemiss dd ? ; #times PCB cache comparison fails
|
||||
TCPS_persisttimeo dd ? ; #times persist timer expires
|
||||
TCPS_predack dd ? ; #times header prediction correct for ACKs
|
||||
TCPS_preddat dd ? ; #times header prediction correct for data packets
|
||||
TCPS_rcvackbyte dd ? ; #bytes ACKed by received ACKs
|
||||
TCPS_rcvackpack dd ? ; #received ACK packets
|
||||
TCPS_rcvacktoomuch dd ? ; #received ACKs for unsent data
|
||||
TCPS_rcvafterclose dd ? ; #packets received after connection closed
|
||||
TCPS_rcvbadoff dd ? ; #packets received with invalid header length
|
||||
TCPS_rcvbadsum dd ? ; #packets received with checksum errors
|
||||
TCPS_rcvbyte dd ? ; #bytes received in sequence
|
||||
TCPS_rcvbyteafterwin dd ? ; #bytes received beyond advertised window
|
||||
TCPS_rcvdupack dd ? ; #duplicate ACKs received
|
||||
TCPS_rcvdupbyte dd ? ; #bytes receivedin completely duplicate packets
|
||||
TCPS_rcvduppack dd ? ; #packets received with completely duplicate bytes
|
||||
TCPS_rcvoobyte dd ? ; #out-of-order bytes received
|
||||
TCPS_rcvoopack dd ? ; #out-of-order packets received
|
||||
TCPS_rcvpack dd ? ; #packets received in sequence
|
||||
TCPS_rcvpackafterwin dd ? ; #packets with some data beyond advertised window
|
||||
TCPS_rcvpartdupbyte dd ? ; #duplicate bytes in part-duplicate packets
|
||||
TCPS_rcvpartduppack dd ? ; #packets with some duplicate data
|
||||
TCPS_rcvshort dd ? ; #packets received too short
|
||||
TCPS_rcvtotal dd ? ; #total packets received
|
||||
TCPS_rcvwinprobe dd ? ; #window probe packets received
|
||||
TCPS_rcvwinupd dd ? ; #received window update packets
|
||||
TCPS_rexmttimeo dd ? ; #retransmission timeouts
|
||||
TCPS_rttupdated dd ? ; #times RTT estimators updated
|
||||
TCPS_segstimed dd ? ; #segments for which TCP tried to measure RTT
|
||||
TCPS_sndacks dd ? ; #ACK-only packets sent (data length = 0)
|
||||
TCPS_sndbyte dd ? ; #data bytes sent
|
||||
TCPS_sndctrl dd ? ; #control (SYN, FIN, RST) packets sent (data length = 0)
|
||||
TCPS_sndpack dd ? ; #data packets sent (data length > 0)
|
||||
TCPS_sndprobe dd ? ; #window probes sent (1 byte of data forced by persist timer)
|
||||
TCPS_sndrexmitbyte dd ? ; #data bytes retransmitted
|
||||
TCPS_sndrexmitpack dd ? ; #data packets retransmitted
|
||||
TCPS_sndtotal dd ? ; total #packets sent
|
||||
TCPS_sndurg dd ? ; #packets sent with URG-only (data length=0)
|
||||
TCPS_sndwinup dd ? ; #window update-only packets sent (data length=0)
|
||||
TCPS_timeoutdrop dd ? ; #connections dropped in retransmission timeout
|
||||
|
||||
endg
|
||||
|
||||
|
||||
;-----------------------------------------------------------------
|
||||
;
|
||||
|
@ -78,7 +78,13 @@ TCP_input:
|
||||
|
||||
|
||||
align 4
|
||||
TCP_process_input:
|
||||
proc TCP_process_input
|
||||
|
||||
locals
|
||||
dataoffset dd ?
|
||||
timestamp dd ?
|
||||
temp_bits db ?
|
||||
endl
|
||||
|
||||
xor esi, esi
|
||||
mov ecx, MANUAL_DESTROY
|
||||
@ -94,6 +100,7 @@ TCP_process_input:
|
||||
get_from_queue TCP_queue, TCP_QUEUE_SIZE, sizeof.TCP_queue_entry, .wait
|
||||
|
||||
push [esi + TCP_queue_entry.timestamp]
|
||||
pop [timestamp]
|
||||
push [esi + TCP_queue_entry.buffer_ptr]
|
||||
|
||||
mov ebx, [esi + TCP_queue_entry.device_ptr]
|
||||
@ -109,8 +116,8 @@ TCP_process_input:
|
||||
je .checksum_ok
|
||||
|
||||
; re-calculate the checksum (if not already done by hw)
|
||||
; test [ebx + NET_DEVICE.hwacc], HWACC_TCP_IPv4_IN
|
||||
; jnz .checksum_ok
|
||||
test [ebx + NET_DEVICE.hwacc], NET_HWACC_TCP_IPv4_IN
|
||||
jnz .checksum_ok
|
||||
|
||||
push ecx esi
|
||||
pushw [esi + TCP_header.Checksum]
|
||||
@ -123,12 +130,13 @@ TCP_process_input:
|
||||
.checksum_ok:
|
||||
|
||||
; Verify the data offset
|
||||
and [edx + TCP_header.DataOffset], 0xf0 ; Calculate TCP segment header size (throwing away unused reserved bits in TCP header)
|
||||
shr [edx + TCP_header.DataOffset], 2
|
||||
cmp [edx + TCP_header.DataOffset], sizeof.TCP_header ; Now see if it's at least the size of a standard TCP header
|
||||
jb .drop_no_socket ; If not, drop the packet
|
||||
|
||||
movzx eax, [edx + TCP_header.DataOffset]
|
||||
and al, 0xf0 ; Calculate TCP segment header size (throwing away unused reserved bits in TCP header)
|
||||
shr al, 2
|
||||
cmp al, sizeof.TCP_header ; Now see if it's at least the size of a standard TCP header
|
||||
jb .drop_no_socket ; If not, drop the packet
|
||||
mov [dataoffset], eax
|
||||
|
||||
sub ecx, eax ; substract TCP header size from total segment size
|
||||
jb .drop_no_socket ; If total segment size is less then the advertised header size, drop packet
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: %u bytes of data\n", ecx
|
||||
@ -211,7 +219,7 @@ TCP_process_input:
|
||||
;---------------------------
|
||||
; disable all temporary bits
|
||||
|
||||
mov [ebx + TCP_SOCKET.temp_bits], 0
|
||||
mov [temp_bits], 0
|
||||
|
||||
;---------------------------------------
|
||||
; unscale the window into a 32 bit value
|
||||
@ -245,7 +253,7 @@ TCP_process_input:
|
||||
|
||||
mov ebx, eax
|
||||
|
||||
mov [ebx + TCP_SOCKET.temp_bits], TCP_BIT_DROPSOCKET ;;; FIXME: should we take over bits from previous socket?
|
||||
mov [temp_bits], TCP_BIT_DROPSOCKET
|
||||
|
||||
push dword [edi + 4] ; Ipv4 destination addres
|
||||
pop [ebx + IP_SOCKET.LocalIP]
|
||||
@ -267,18 +275,18 @@ TCP_process_input:
|
||||
;--------------------
|
||||
; Process TCP options
|
||||
|
||||
;;; FIXME: for LISTEN, options should be called after we determined route, we need it for MSS
|
||||
;;; cmp [ebx + TCP_SOCKET.t_state], TCPS_LISTEN ; no options when in listen state
|
||||
;;; jz .not_uni_xfer ; also no header prediction
|
||||
|
||||
push ecx
|
||||
|
||||
movzx ecx, [edx + TCP_header.DataOffset]
|
||||
mov ecx, [dataoffset]
|
||||
cmp ecx, sizeof.TCP_header ; Does header contain any options?
|
||||
je .no_options
|
||||
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Segment has options\n"
|
||||
|
||||
;;; FIXME: for LISTEN, options should be called after we determined route, we need it for MSS
|
||||
;;; cmp [ebx + TCP_SOCKET.t_state], TCPS_LISTEN ; no options when in listen state
|
||||
;;; jz .not_uni_xfer ; also no header prediction
|
||||
|
||||
add ecx, edx
|
||||
lea esi, [edx + sizeof.TCP_header]
|
||||
|
||||
@ -311,9 +319,10 @@ TCP_process_input:
|
||||
test [edx + TCP_header.Flags], TH_SYN
|
||||
jz @f
|
||||
|
||||
xor eax, eax
|
||||
lodsw
|
||||
rol ax, 8
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Maxseg=%u\n", ax
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Maxseg=%u\n", eax
|
||||
call TCP_mss
|
||||
@@:
|
||||
jmp .opt_loop
|
||||
@ -366,10 +375,11 @@ TCP_process_input:
|
||||
@@:
|
||||
|
||||
lodsd
|
||||
bswap eax
|
||||
mov [ebx + TCP_SOCKET.ts_val], eax
|
||||
lodsd ; timestamp echo reply
|
||||
mov [ebx + TCP_SOCKET.ts_ecr], eax
|
||||
or [ebx + TCP_SOCKET.temp_bits], TCP_BIT_TIMESTAMP
|
||||
or [temp_bits], TCP_BIT_TIMESTAMP
|
||||
|
||||
; Since we have a timestamp, lets do the paws test right away!
|
||||
|
||||
@ -380,11 +390,11 @@ TCP_process_input:
|
||||
test eax, eax
|
||||
jz .no_paws
|
||||
cmp eax, [ebx + TCP_SOCKET.ts_val]
|
||||
jge .no_paws
|
||||
jbe .no_paws
|
||||
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: PAWS: detected an old segment\n"
|
||||
|
||||
mov eax, [esp+4+4] ; tcp_now
|
||||
mov eax, [timestamp]
|
||||
sub eax, [ebx + TCP_SOCKET.ts_recent_age]
|
||||
|
||||
pop ecx
|
||||
@ -474,9 +484,9 @@ TCP_process_input:
|
||||
|
||||
; Update RTT estimators
|
||||
|
||||
test [ebx + TCP_SOCKET.temp_bits], TCP_BIT_TIMESTAMP
|
||||
test [temp_bits], TCP_BIT_TIMESTAMP
|
||||
jz .no_timestamp_rtt
|
||||
mov eax, [esp + 4] ; timestamp when this segment was received
|
||||
mov eax, [timestamp]
|
||||
sub eax, [ebx + TCP_SOCKET.ts_ecr]
|
||||
inc eax
|
||||
call TCP_xmit_timer
|
||||
@ -536,12 +546,11 @@ TCP_process_input:
|
||||
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Header prediction: we are receiving %u bytes\n", ecx
|
||||
|
||||
add [ebx + TCP_SOCKET.RCV_NXT], ecx ; Update sequence number with number of bytes we have copied
|
||||
|
||||
movzx esi, [edx + TCP_header.DataOffset]
|
||||
mov esi, [dataoffset]
|
||||
add esi, edx
|
||||
lea eax, [ebx + STREAM_SOCKET.rcv]
|
||||
call SOCKET_ring_write ; Add the data to the socket buffer
|
||||
add [ebx + TCP_SOCKET.RCV_NXT], ecx ; Update sequence number with number of bytes we have copied
|
||||
|
||||
mov eax, ebx
|
||||
call SOCKET_notify
|
||||
@ -558,12 +567,13 @@ TCP_process_input:
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Header prediction failed\n"
|
||||
|
||||
; Calculate receive window size
|
||||
|
||||
push edx
|
||||
mov eax, SOCKETBUFFSIZE
|
||||
mov eax, SOCKET_MAXDATA
|
||||
sub eax, [ebx + STREAM_SOCKET.rcv.size]
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "Space in receive buffer=%d\n", eax
|
||||
mov edx, [ebx + TCP_SOCKET.RCV_ADV]
|
||||
sub edx, [ebx + TCP_SOCKET.RCV_NXT]
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "Current advertised window=%d\n", edx
|
||||
cmp eax, edx
|
||||
jg @f
|
||||
mov eax, edx
|
||||
@ -583,8 +593,9 @@ TCP_process_input:
|
||||
;----------------------------
|
||||
; trim any data not in window
|
||||
|
||||
; check for duplicate data at beginning of segment (635)
|
||||
; 1. Check for duplicate data at beginning of segment
|
||||
|
||||
; Calculate number of bytes we need to drop
|
||||
mov eax, [ebx + TCP_SOCKET.RCV_NXT]
|
||||
sub eax, [edx + TCP_header.SequenceNumber]
|
||||
jle .no_duplicate
|
||||
@ -609,7 +620,7 @@ TCP_process_input:
|
||||
dec eax
|
||||
.no_dup_syn:
|
||||
|
||||
; Check for entire duplicate segment (646)
|
||||
; 2. Check for entire duplicate segment
|
||||
cmp eax, ecx ; eax holds number of bytes to drop, ecx is data size
|
||||
jb .duplicate
|
||||
jnz @f
|
||||
@ -623,16 +634,19 @@ TCP_process_input:
|
||||
|
||||
; send an ACK and resynchronize and drop any data.
|
||||
; But keep on processing for RST or ACK
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "616\n"
|
||||
or [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
|
||||
mov eax, ecx
|
||||
;TODO: update stats
|
||||
|
||||
;;; TODO: update stats
|
||||
|
||||
;-----------------------------------------------
|
||||
; Remove duplicate data and update urgent offset
|
||||
|
||||
.duplicate:
|
||||
;;; TODO: 677
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: trimming duplicate data\n"
|
||||
|
||||
; Trim data from left side of window
|
||||
add [dataoffset], eax
|
||||
add [edx + TCP_header.SequenceNumber], eax
|
||||
sub ecx, eax
|
||||
|
||||
@ -643,10 +657,10 @@ TCP_process_input:
|
||||
@@:
|
||||
|
||||
;--------------------------------------------------
|
||||
; Handle data that arrives after process terminates (687)
|
||||
; Handle data that arrives after process terminates
|
||||
|
||||
.no_duplicate:
|
||||
cmp [ebx + SOCKET.PID], 0
|
||||
cmp [ebx + SOCKET.PID], 0 ;;; TODO: use socket flags instead??
|
||||
jne .not_terminated
|
||||
cmp [ebx + TCP_SOCKET.t_state], TCPS_CLOSE_WAIT
|
||||
jbe .not_terminated
|
||||
@ -659,7 +673,7 @@ TCP_process_input:
|
||||
jmp .respond_seg_reset
|
||||
|
||||
;----------------------------------------
|
||||
; Remove data beyond right edge of window (700-736)
|
||||
; Remove data beyond right edge of window
|
||||
|
||||
.not_terminated:
|
||||
mov eax, [edx + TCP_header.SequenceNumber]
|
||||
@ -688,32 +702,29 @@ TCP_process_input:
|
||||
jmp .findpcb ; FIXME: skip code for unscaling window, ...
|
||||
.no_new_request:
|
||||
|
||||
; If window is closed can only take segments at window edge, and have to drop data and PUSH from
|
||||
; If window is closed, we can only take segments at window edge, and have to drop data and PUSH from
|
||||
; incoming segments. Continue processing, but remember to ACK. Otherwise drop segment and ACK
|
||||
|
||||
cmp [ebx + TCP_SOCKET.RCV_WND], 0
|
||||
jne .drop_after_ack
|
||||
mov eax, [edx + TCP_header.SequenceNumber]
|
||||
cmp eax, [ebx + TCP_SOCKET.RCV_NXT]
|
||||
mov esi, [edx + TCP_header.SequenceNumber]
|
||||
cmp esi, [ebx + TCP_SOCKET.RCV_NXT]
|
||||
jne .drop_after_ack
|
||||
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "690\n"
|
||||
or [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
|
||||
;;; TODO: update stats
|
||||
jmp .no_excess_data
|
||||
.dont_drop_all:
|
||||
;;; TODO: update stats
|
||||
;;; TODO: 733
|
||||
|
||||
sub ecx, eax
|
||||
and [ebx + TCP_SOCKET.t_flags], not (TH_PUSH or TH_FIN)
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "Trimming %u bytes from the right of the window\n"
|
||||
sub ecx, eax ; remove data from the right side of window (decrease data length)
|
||||
and [edx + TCP_header.Flags], not (TH_PUSH or TH_FIN)
|
||||
.no_excess_data:
|
||||
|
||||
;-----------------
|
||||
; Record timestamp (737-746)
|
||||
; Record timestamp
|
||||
|
||||
; If last ACK falls within this segments sequence numbers, record its timestamp
|
||||
test [ebx + TCP_SOCKET.temp_bits], TCP_BIT_TIMESTAMP
|
||||
test [temp_bits], TCP_BIT_TIMESTAMP
|
||||
jz .no_timestamp
|
||||
mov eax, [ebx + TCP_SOCKET.last_ack_sent]
|
||||
sub eax, [edx + TCP_header.SequenceNumber]
|
||||
@ -727,7 +738,7 @@ TCP_process_input:
|
||||
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "Recording timestamp\n"
|
||||
|
||||
mov eax, [esp + 4] ; tcp_now
|
||||
mov eax, [timestamp]
|
||||
mov [ebx + TCP_SOCKET.ts_recent_age], eax
|
||||
mov eax, [ebx + TCP_SOCKET.ts_val]
|
||||
mov [ebx + TCP_SOCKET.ts_recent], eax
|
||||
@ -882,7 +893,9 @@ TCP_process_input:
|
||||
|
||||
mov eax, [ebx + TCP_SOCKET.SND_WND]
|
||||
cmp eax, [ebx + TCP_SOCKET.SND_CWND]
|
||||
cmova eax, [ebx + TCP_SOCKET.SND_CWND]
|
||||
jbe @f
|
||||
mov eax, [ebx + TCP_SOCKET.SND_CWND]
|
||||
@@:
|
||||
shr eax, 1
|
||||
push edx
|
||||
xor edx, edx
|
||||
@ -993,13 +1006,13 @@ TCP_process_input:
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: acceptable ACK for %u bytes\n", edi
|
||||
|
||||
;------------------------------------------
|
||||
; RTT measurements and retransmission timer (912-926)
|
||||
; RTT measurements and retransmission timer
|
||||
|
||||
; If we have a timestamp, update smoothed RTT
|
||||
|
||||
test [ebx + TCP_SOCKET.temp_bits], TCP_BIT_TIMESTAMP
|
||||
test [temp_bits], TCP_BIT_TIMESTAMP
|
||||
jz .timestamp_not_present
|
||||
mov eax, [esp+4]
|
||||
mov eax, [timestamp]
|
||||
sub eax, [ebx + TCP_SOCKET.ts_ecr]
|
||||
inc eax
|
||||
call TCP_xmit_timer
|
||||
@ -1028,7 +1041,7 @@ TCP_process_input:
|
||||
cmp eax, [edx + TCP_header.AckNumber]
|
||||
jne .more_data
|
||||
and [ebx + TCP_SOCKET.timer_flags], not timer_flag_retransmission
|
||||
or [ebx + TCP_SOCKET.temp_bits], TCP_BIT_NEEDOUTPUT
|
||||
or [temp_bits], TCP_BIT_NEEDOUTPUT
|
||||
jmp .no_restart
|
||||
.more_data:
|
||||
test [ebx + TCP_SOCKET.timer_flags], timer_flag_persist
|
||||
@ -1067,7 +1080,9 @@ TCP_process_input:
|
||||
pop ecx
|
||||
|
||||
cmp esi, eax
|
||||
cmova esi, eax
|
||||
jbe @f
|
||||
mov esi, eax
|
||||
@@:
|
||||
mov [ebx + TCP_SOCKET.SND_CWND], esi
|
||||
|
||||
;------------------------------------------
|
||||
@ -1175,12 +1190,9 @@ TCP_process_input:
|
||||
call mutex_unlock
|
||||
pop ebx
|
||||
|
||||
push ebx
|
||||
mov eax, ebx
|
||||
call TCP_disconnect
|
||||
pop ebx
|
||||
|
||||
jmp .destroy_new_socket
|
||||
call TCP_close
|
||||
jmp .drop_no_socket
|
||||
|
||||
.ack_tw:
|
||||
mov [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL
|
||||
@ -1228,7 +1240,7 @@ align 4
|
||||
TCP_rcvseqinit ebx
|
||||
|
||||
mov [ebx + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED
|
||||
mov [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
|
||||
or [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
|
||||
mov [ebx + TCP_SOCKET.timer_keepalive], TCP_time_keep_interval ;;;; macro
|
||||
or [ebx + TCP_SOCKET.timer_flags], timer_flag_keepalive
|
||||
|
||||
@ -1238,7 +1250,7 @@ align 4
|
||||
lea eax, [ebx + STREAM_SOCKET.rcv]
|
||||
call SOCKET_ring_create
|
||||
|
||||
and [ebx + TCP_SOCKET.temp_bits], not TCP_BIT_DROPSOCKET
|
||||
and [temp_bits], not TCP_BIT_DROPSOCKET
|
||||
|
||||
pusha
|
||||
mov eax, ebx
|
||||
@ -1355,7 +1367,16 @@ align 4
|
||||
|
||||
inc [edx + TCP_header.SequenceNumber]
|
||||
|
||||
;;; TODO: Drop any received data that follows receive window (590)
|
||||
; Drop any received data that doesnt fit in the receive window.
|
||||
cmp ecx, [ebx + TCP_SOCKET.RCV_WND]
|
||||
jbe .dont_trim
|
||||
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: received data does not fit in window, trimming %u bytes\n", eax
|
||||
mov ecx, [ebx + TCP_SOCKET.RCV_WND]
|
||||
and [edx + TCP_header.Flags], not (TH_FIN)
|
||||
;;; TODO: update stats
|
||||
|
||||
.dont_trim:
|
||||
|
||||
mov eax, [edx + TCP_header.SequenceNumber]
|
||||
mov [ebx + TCP_SOCKET.RCV_UP], eax
|
||||
@ -1409,7 +1430,7 @@ align 4
|
||||
push [edx + TCP_header.AckNumber]
|
||||
pop [ebx + TCP_SOCKET.SND_WL2]
|
||||
|
||||
or [ebx + TCP_SOCKET.temp_bits], TCP_BIT_NEEDOUTPUT
|
||||
or [temp_bits], TCP_BIT_NEEDOUTPUT
|
||||
|
||||
.no_window_update:
|
||||
|
||||
@ -1475,7 +1496,7 @@ align 4
|
||||
or [ebx + TCP_SOCKET.t_flags], TF_DELACK
|
||||
|
||||
pusha
|
||||
movzx esi, [edx + TCP_header.DataOffset]
|
||||
mov esi, [dataoffset]
|
||||
add esi, edx
|
||||
lea eax, [ebx + STREAM_SOCKET.rcv]
|
||||
call SOCKET_ring_write ; Add the data to the socket buffer
|
||||
@ -1489,16 +1510,16 @@ align 4
|
||||
jmp .data_done
|
||||
|
||||
.out_of_order:
|
||||
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP data is out of order\n"
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP data is out of order!\nSequencenumber is %u, we expected %u.\n", \
|
||||
[edx + TCP_header.SequenceNumber], [ebx + TCP_SOCKET.RCV_NXT]
|
||||
|
||||
; Uh-oh, some data is out of order, lets call TCP reassemble for help
|
||||
|
||||
call TCP_reassemble
|
||||
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "1470\n"
|
||||
; Generate ACK immediately, to let the other end know that a segment was received out of order,
|
||||
; and to tell it what sequence number is expected. This aids the fast-retransmit algorithm.
|
||||
or [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
|
||||
|
||||
.data_done:
|
||||
|
||||
;---------------
|
||||
@ -1517,7 +1538,7 @@ align 4
|
||||
mov eax, ebx
|
||||
call SOCKET_cant_recv_more
|
||||
|
||||
mov [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
|
||||
or [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
|
||||
inc [ebx + TCP_SOCKET.RCV_NXT]
|
||||
|
||||
.not_first_fin:
|
||||
@ -1539,29 +1560,54 @@ align 4
|
||||
dd .fin_timed ; TCPS_TIMED_WAIT
|
||||
|
||||
.fin_syn_est:
|
||||
|
||||
mov [ebx + TCP_SOCKET.t_state], TCPS_CLOSE_WAIT
|
||||
jmp .final_processing
|
||||
|
||||
.fin_wait1:
|
||||
|
||||
mov [ebx + TCP_SOCKET.t_state], TCPS_CLOSING
|
||||
jmp .final_processing
|
||||
|
||||
.fin_wait2:
|
||||
|
||||
mov [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT
|
||||
mov eax, ebx
|
||||
call TCP_cancel_timers
|
||||
mov [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL
|
||||
or [ebx + TCP_SOCKET.timer_flags], timer_flag_wait
|
||||
call SOCKET_is_disconnected
|
||||
jmp .final_processing
|
||||
|
||||
.fin_timed:
|
||||
mov [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL
|
||||
or [ebx + TCP_SOCKET.timer_flags], timer_flag_wait
|
||||
jmp .final_processing
|
||||
|
||||
;-----------------
|
||||
; Final processing
|
||||
|
||||
.final_processing:
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Final processing\n"
|
||||
|
||||
push ebx
|
||||
lea ecx, [ebx + SOCKET.mutex]
|
||||
call mutex_unlock
|
||||
pop eax
|
||||
|
||||
test [temp_bits], TCP_BIT_NEEDOUTPUT
|
||||
jnz .need_output
|
||||
|
||||
test [eax + TCP_SOCKET.t_flags], TF_ACKNOW
|
||||
jz .dumpit
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: ACK now!\n"
|
||||
|
||||
.need_output:
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: need output\n"
|
||||
call TCP_output
|
||||
|
||||
.dumpit:
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: dumping\n"
|
||||
|
||||
call NET_packet_free
|
||||
jmp .loop
|
||||
|
||||
|
||||
;-----------------
|
||||
; Drop the segment
|
||||
|
||||
|
||||
.drop_after_ack:
|
||||
@ -1598,35 +1644,6 @@ align 4
|
||||
jnz .respond_syn
|
||||
jmp .dumpit
|
||||
|
||||
;-----------------
|
||||
; Final processing
|
||||
|
||||
.final_processing:
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Final processing\n"
|
||||
|
||||
push ebx
|
||||
lea ecx, [ebx + SOCKET.mutex]
|
||||
call mutex_unlock
|
||||
pop eax
|
||||
|
||||
test [eax + TCP_SOCKET.temp_bits], TCP_BIT_NEEDOUTPUT
|
||||
jnz .need_output
|
||||
|
||||
test [eax + TCP_SOCKET.t_flags], TF_ACKNOW
|
||||
jz .dumpit
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: ACK now!\n"
|
||||
|
||||
.need_output:
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: need output\n"
|
||||
call TCP_output
|
||||
|
||||
.dumpit:
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: dumping\n"
|
||||
|
||||
call NET_packet_free
|
||||
add esp, 4
|
||||
jmp .loop
|
||||
|
||||
;---------
|
||||
; Respond
|
||||
|
||||
@ -1687,7 +1704,7 @@ align 4
|
||||
popa
|
||||
|
||||
.destroy_new_socket:
|
||||
test [ebx + TCP_SOCKET.temp_bits], TCP_BIT_DROPSOCKET
|
||||
test [temp_bits], TCP_BIT_DROPSOCKET
|
||||
jz .drop_no_socket
|
||||
|
||||
mov eax, ebx
|
||||
@ -1697,5 +1714,6 @@ align 4
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Drop (no socket)\n"
|
||||
|
||||
call NET_packet_free
|
||||
add esp, 4
|
||||
jmp .loop
|
||||
|
||||
endp
|
||||
|
@ -21,14 +21,17 @@ $Revision: 3289 $
|
||||
; TCP_output
|
||||
;
|
||||
; IN: eax = socket pointer
|
||||
;
|
||||
; OUT: /
|
||||
; OUT: eax = 0 on success/errorcode
|
||||
;
|
||||
;-----------------------------------------------------------------
|
||||
align 4
|
||||
TCP_output:
|
||||
proc TCP_output
|
||||
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_output: socket=%x\n", eax
|
||||
locals
|
||||
temp_bits db ?
|
||||
endl
|
||||
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_output: socket=%x state=%u\n", eax, [eax + TCP_SOCKET.t_state]
|
||||
|
||||
push eax
|
||||
lea ecx, [eax + SOCKET.mutex]
|
||||
@ -57,7 +60,7 @@ TCP_output:
|
||||
|
||||
.not_idle:
|
||||
.again:
|
||||
mov [eax + TCP_SOCKET.temp_bits], 0
|
||||
mov [temp_bits], 0
|
||||
|
||||
mov ebx, [eax + TCP_SOCKET.SND_NXT] ; calculate offset (71)
|
||||
sub ebx, [eax + TCP_SOCKET.SND_UNA] ;
|
||||
@ -145,7 +148,7 @@ TCP_output:
|
||||
jbe @f
|
||||
|
||||
mov esi, [eax + TCP_SOCKET.t_maxseg]
|
||||
or [eax + TCP_SOCKET.temp_bits], TCP_BIT_SENDALOT
|
||||
or [temp_bits], TCP_BIT_SENDALOT
|
||||
@@:
|
||||
|
||||
;--------------------------------------------
|
||||
@ -173,31 +176,31 @@ TCP_output:
|
||||
jz .len_zero
|
||||
|
||||
cmp esi, [eax + TCP_SOCKET.t_maxseg]
|
||||
je TCP_send
|
||||
je .send
|
||||
|
||||
add ebx, esi ; offset + length
|
||||
cmp ebx, [eax + STREAM_SOCKET.snd.size]
|
||||
jb @f
|
||||
|
||||
test [eax + TCP_SOCKET.t_flags], TF_NODELAY
|
||||
jnz TCP_send
|
||||
jnz .send
|
||||
|
||||
mov ebx, [eax + TCP_SOCKET.SND_MAX]
|
||||
cmp ebx, [eax + TCP_SOCKET.SND_UNA]
|
||||
je TCP_send
|
||||
je .send
|
||||
@@:
|
||||
|
||||
test [eax + TCP_SOCKET.t_force], -1 ;;;
|
||||
jnz TCP_send
|
||||
jnz .send
|
||||
|
||||
mov ebx, [eax + TCP_SOCKET.max_sndwnd]
|
||||
shr ebx, 1
|
||||
cmp esi, ebx
|
||||
jae TCP_send
|
||||
jae .send
|
||||
|
||||
mov ebx, [eax + TCP_SOCKET.SND_NXT]
|
||||
cmp ebx, [eax + TCP_SOCKET.SND_MAX]
|
||||
jb TCP_send
|
||||
jb .send
|
||||
|
||||
.len_zero:
|
||||
|
||||
@ -229,9 +232,10 @@ TCP_output:
|
||||
mov edi, [eax + TCP_SOCKET.t_maxseg]
|
||||
shl edi, 1
|
||||
|
||||
; cmp ebx, edi
|
||||
; jae TCP_send
|
||||
cmp ebx, edi
|
||||
jae .send
|
||||
|
||||
shl ebx, 1
|
||||
; cmp ebx, [eax + TCP_SOCKET.] ;;; TODO: check with receive buffer high water mark
|
||||
; jae TCP_send
|
||||
|
||||
@ -240,17 +244,15 @@ TCP_output:
|
||||
;--------------------------
|
||||
; Should a segment be sent? (174)
|
||||
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_output: 174\n"
|
||||
|
||||
test [eax + TCP_SOCKET.t_flags], TF_ACKNOW ; we need to ACK
|
||||
jnz TCP_send
|
||||
jnz .send
|
||||
|
||||
test dl, TH_SYN + TH_RST ; we need to send a SYN or RST
|
||||
jnz TCP_send
|
||||
jnz .send
|
||||
|
||||
mov ebx, [eax + TCP_SOCKET.SND_UP] ; when urgent pointer is beyond start of send bufer
|
||||
cmp ebx, [eax + TCP_SOCKET.SND_UNA]
|
||||
ja TCP_send
|
||||
ja .send
|
||||
|
||||
test dl, TH_FIN
|
||||
jz .enter_persist ; no reason to send, enter persist state
|
||||
@ -258,11 +260,11 @@ TCP_output:
|
||||
; FIN was set, only send if not already sent, or on retransmit
|
||||
|
||||
test [eax + TCP_SOCKET.t_flags], TF_SENTFIN
|
||||
jz TCP_send
|
||||
jz .send
|
||||
|
||||
mov ebx, [eax + TCP_SOCKET.SND_NXT]
|
||||
cmp ebx, [eax + TCP_SOCKET.SND_UNA]
|
||||
je TCP_send
|
||||
je .send
|
||||
|
||||
;--------------------
|
||||
; Enter persist state (191)
|
||||
@ -298,13 +300,6 @@ TCP_output:
|
||||
ret
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
;-----------------------------------------------
|
||||
;
|
||||
; Send a segment (222)
|
||||
@ -314,8 +309,7 @@ TCP_output:
|
||||
; dl = flags
|
||||
;
|
||||
;-----------------------------------------------
|
||||
align 4
|
||||
TCP_send:
|
||||
.send:
|
||||
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_send: socket=%x length=%u flags=%x\n", eax, esi, dl
|
||||
|
||||
@ -406,16 +400,48 @@ TCP_send:
|
||||
jbe .no_overflow
|
||||
|
||||
mov esi, [eax + TCP_SOCKET.t_maxseg]
|
||||
or [eax + TCP_SOCKET.temp_bits], TCP_BIT_SENDALOT
|
||||
or [temp_bits], TCP_BIT_SENDALOT
|
||||
.no_overflow:
|
||||
|
||||
;----------------------------------------------------
|
||||
; Calculate the receive window.
|
||||
; Dont shrink window, but avoid silly window syndrome
|
||||
|
||||
mov ebx, SOCKET_MAXDATA
|
||||
sub ebx, [eax + STREAM_SOCKET.rcv.size]
|
||||
|
||||
cmp ebx, SOCKET_MAXDATA/4
|
||||
jae @f
|
||||
cmp ebx, [eax + TCP_SOCKET.t_maxseg]
|
||||
jae @f
|
||||
xor ebx, ebx
|
||||
@@:
|
||||
|
||||
cmp ebx, TCP_max_win
|
||||
jbe @f
|
||||
mov ebx, TCP_max_win
|
||||
@@:
|
||||
|
||||
mov ecx, [eax + TCP_SOCKET.RCV_ADV]
|
||||
sub ecx, [eax + TCP_SOCKET.RCV_NXT]
|
||||
cmp ebx, ecx
|
||||
ja @f
|
||||
mov ebx, ecx
|
||||
@@:
|
||||
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_send: window = %u\n", ebx
|
||||
|
||||
mov cl, [eax + TCP_SOCKET.RCV_SCALE]
|
||||
shr ebx, cl
|
||||
xchg bl, bh
|
||||
|
||||
;-----------------------------------------------------------------
|
||||
; Start by pushing all TCP header values in reverse order on stack
|
||||
; (essentially, creating the tcp header on the stack!)
|
||||
|
||||
pushw 0 ; .UrgentPointer dw ?
|
||||
pushw 0 ; .Checksum dw ?
|
||||
pushw 0x00a0 ; .Window dw ? ;;;;;;; FIXME (370)
|
||||
pushw bx ; .Window dw ?
|
||||
shl edi, 2 ; .DataOffset db ? only 4 left-most bits
|
||||
shl dx, 8
|
||||
or dx, di ; .Flags db ?
|
||||
@ -534,7 +560,13 @@ TCP_send:
|
||||
;--------------------
|
||||
; Create the checksum
|
||||
|
||||
xor dx, dx
|
||||
test [ebx + NET_DEVICE.hwacc], NET_HWACC_TCP_IPv4_OUT
|
||||
jnz .checksum_ok
|
||||
|
||||
TCP_checksum (eax + IP_SOCKET.LocalIP), (eax + IP_SOCKET.RemoteIP)
|
||||
|
||||
.checksum_ok:
|
||||
mov [esi + TCP_header.Checksum], dx
|
||||
|
||||
;----------------
|
||||
@ -566,7 +598,7 @@ TCP_send:
|
||||
push [eax + TCP_SOCKET.RCV_NXT]
|
||||
pop [eax + TCP_SOCKET.last_ack_sent]
|
||||
|
||||
; and flags
|
||||
; clear the ACK flags
|
||||
and [eax + TCP_SOCKET.t_flags], not (TF_ACKNOW + TF_DELACK)
|
||||
|
||||
;--------------
|
||||
@ -582,7 +614,7 @@ TCP_send:
|
||||
;-----------------------------
|
||||
; Check if we need more output
|
||||
|
||||
test [eax + TCP_SOCKET.temp_bits], TCP_BIT_SENDALOT
|
||||
test [temp_bits], TCP_BIT_SENDALOT
|
||||
jnz TCP_output.again
|
||||
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_send: success!\n"
|
||||
@ -622,7 +654,4 @@ TCP_send:
|
||||
ret
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
endp
|
@ -152,7 +152,9 @@ TCP_drop:
|
||||
|
||||
mov [eax + TCP_SOCKET.t_state], TCPS_CLOSED
|
||||
|
||||
push eax
|
||||
call TCP_output
|
||||
pop eax
|
||||
|
||||
;;; TODO: update stats
|
||||
|
||||
@ -169,8 +171,35 @@ TCP_drop:
|
||||
|
||||
|
||||
|
||||
;-------------------------
|
||||
;
|
||||
; TCP_disconnect
|
||||
;
|
||||
; IN: eax = socket ptr
|
||||
; OUT: eax = socket ptr / 0
|
||||
;
|
||||
;-------------------------
|
||||
align 4
|
||||
TCP_disconnect:
|
||||
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_disconnect: %x\n", eax
|
||||
|
||||
cmp [eax + TCP_SOCKET.t_state], TCPS_ESTABLISHED
|
||||
jb TCP_close ; Connection not yet synchronised, just get rid of the socket
|
||||
|
||||
; TODO: implement LINGER
|
||||
|
||||
call SOCKET_is_disconnecting
|
||||
call TCP_usrclosed
|
||||
|
||||
test eax, eax
|
||||
jz @f
|
||||
push eax
|
||||
call TCP_output
|
||||
pop eax
|
||||
@@:
|
||||
|
||||
ret
|
||||
|
||||
|
||||
;-------------------------
|
||||
@ -178,7 +207,7 @@ TCP_drop:
|
||||
; TCP_close
|
||||
;
|
||||
; IN: eax = socket ptr
|
||||
; OUT: eax = socket ptr
|
||||
; OUT: /
|
||||
;
|
||||
;-------------------------
|
||||
align 4
|
||||
@ -190,7 +219,9 @@ TCP_close:
|
||||
;;; TODO: update slow start threshold
|
||||
|
||||
call SOCKET_is_disconnected
|
||||
;; call SOCKET_free
|
||||
call SOCKET_free
|
||||
|
||||
xor eax, eax
|
||||
|
||||
ret
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;; Part of the TCP/IP network stack for KolibriOS ;;
|
||||
@ -57,7 +57,6 @@ TCP_usrclosed:
|
||||
|
||||
.wait1:
|
||||
mov [eax + TCP_SOCKET.t_state], TCPS_FIN_WAIT_1
|
||||
; TODO: set timer?
|
||||
pop ebx
|
||||
ret
|
||||
|
||||
@ -68,7 +67,6 @@ TCP_usrclosed:
|
||||
|
||||
.disc:
|
||||
call SOCKET_is_disconnected
|
||||
; TODO: set timer?
|
||||
.ret:
|
||||
pop ebx
|
||||
ret
|
||||
@ -203,34 +201,3 @@ TCP_connect:
|
||||
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
|
||||
|
||||
|
||||
;-------------------------
|
||||
;
|
||||
; TCP_disconnect
|
||||
;
|
||||
; IN: eax = socket ptr
|
||||
; OUT: eax = socket ptr
|
||||
;
|
||||
;-------------------------
|
||||
align 4
|
||||
TCP_disconnect:
|
||||
|
||||
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_disconnect: %x\n", eax
|
||||
|
||||
cmp [eax + TCP_SOCKET.t_state], TCPS_ESTABLISHED
|
||||
jb TCP_close
|
||||
|
||||
|
||||
; TODO: implement LINGER ?
|
||||
|
||||
call SOCKET_is_disconnecting
|
||||
call TCP_usrclosed
|
||||
|
||||
push eax
|
||||
call TCP_output
|
||||
pop eax
|
||||
|
||||
ret
|
@ -295,6 +295,8 @@ proc set_cursor stdcall, hcursor:dword
|
||||
; jne .fail
|
||||
mov ebx, [current_slot]
|
||||
xchg eax, [ebx+APPDATA.cursor]
|
||||
mov [redrawmouse_unconditional], 1
|
||||
call __sys_draw_pointer
|
||||
ret
|
||||
;--------------------------------------
|
||||
align 4
|
||||
|
@ -1952,7 +1952,6 @@ align 4
|
||||
mov esi, bgr_next_line
|
||||
mov edi, bgr_cur_line
|
||||
mov ecx, [_display.width]
|
||||
inc ecx
|
||||
rep movsd
|
||||
jmp bgr_resmooth1
|
||||
;--------------------------------------
|
||||
|
Loading…
Reference in New Issue
Block a user