kolibri-acpi:update

git-svn-id: svn://kolibrios.org@4423 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
Sergey Semyonov (Serge) 2014-01-01 21:16:27 +00:00
parent a461856fa1
commit 3ed9acd41a
40 changed files with 1549 additions and 7555 deletions

View 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}

View File

@ -10,7 +10,6 @@ $Revision$
; Low-level driver for HDD access ; Low-level driver for HDD access
; DMA support by Mario79 ; DMA support by Mario79
; Access through BIOS by diamond
; LBA48 support by Mario79 ; LBA48 support by Mario79
;----------------------------------------------------------------------------- ;-----------------------------------------------------------------------------
struct HD_DATA struct HD_DATA
@ -32,17 +31,6 @@ ide_callbacks:
dd 0 ; use default cache size dd 0 ; use default cache size
.end: .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 hd0_data HD_DATA ?, 0, 1
hd1_data HD_DATA ?, 0x10, 2 hd1_data HD_DATA ?, 0x10, 2
hd2_data HD_DATA ?, 0, 3 hd2_data HD_DATA ?, 0, 3
@ -112,6 +100,22 @@ endl
ja .nodma ja .nodma
cmp [dma_hdd], 1 cmp [dma_hdd], 1
jnz .nodma 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 call hd_read_dma
jmp @f jmp @f
.nodma: .nodma:
@ -204,6 +208,22 @@ endl
jae .nodma jae .nodma
cmp [dma_hdd], 1 cmp [dma_hdd], 1
jnz .nodma 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 call cache_write_dma
jmp .common jmp .common
.nodma: .nodma:
@ -251,137 +271,6 @@ proc ide_querymedia stdcall, hd_data, mediainfo
ret ret
endp 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 align 4
; input: eax = sector, edi -> buffer ; input: eax = sector, edi -> buffer
@ -803,23 +692,37 @@ IDE_irq_14_handler:
pushfd pushfd
cli cli
pushad pushad
; clear Bus Master IDE Command register
mov [IDE_common_irq_param], 0 mov [IDE_common_irq_param], 0
mov dx, [IDEContrRegsBaseAddr] mov dx, [IDEContrRegsBaseAddr]
mov al, 0 ; test whether it is our interrupt?
out dx, al add edx, 2
in al, dx
test al, 100b
jz @f
; clear Bus Master IDE Status register ; clear Bus Master IDE Status register
; clear Interrupt bit ; clear Interrupt bit
add edx, 2
mov al, 4 ; 100b
out dx, al 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 popad
popfd popfd
;-------------------------------------- ;--------------------------------------
align 4 align 4
.exit: .exit:
mov al, 1 mov al, 0
ret ret
;----------------------------------------------------------------------------- ;-----------------------------------------------------------------------------
align 4 align 4
@ -830,24 +733,38 @@ IDE_irq_15_handler:
pushfd pushfd
cli cli
pushad pushad
; clear Bus Master IDE Command register
mov [IDE_common_irq_param], 0 mov [IDE_common_irq_param], 0
mov dx, [IDEContrRegsBaseAddr] mov dx, [IDEContrRegsBaseAddr]
add dx, 8 add dx, 8
mov al, 0 ; test whether it is our interrupt?
out dx, al add edx, 2
in al, dx
test al, 100b
jz @f
; clear Bus Master IDE Status register ; clear Bus Master IDE Status register
; clear Interrupt bit ; clear Interrupt bit
add edx, 2
mov al, 4 ; 100b
out dx, al 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 popad
popfd popfd
;-------------------------------------- ;--------------------------------------
align 4 align 4
.exit: .exit:
mov al, 1 mov al, 0
ret ret
;----------------------------------------------------------------------------- ;-----------------------------------------------------------------------------
align 4 align 4
@ -858,32 +775,46 @@ IDE_common_irq_handler:
pushfd pushfd
cli cli
pushad pushad
; clear Bus Master IDE Command register
xor ebx, ebx xor ebx, ebx
mov dx, [IDEContrRegsBaseAddr] mov dx, [IDEContrRegsBaseAddr]
mov eax, IDE_common_irq_param mov eax, IDE_common_irq_param
cmp [eax], irq14_num cmp [eax], irq14_num
mov [eax], bl mov [eax], bl
xor eax, eax
je @f je @f
add dx, 8 add dx, 8
;-------------------------------------- ;--------------------------------------
align 4 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 Bus Master IDE Status register
; clear Interrupt bit ; clear Interrupt bit
add edx, 2
mov al, 4 ; 100b
out dx, al 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 popad
popfd popfd
;-------------------------------------- ;--------------------------------------
align 4 align 4
.exit: .exit:
mov al, 1 mov al, 0
ret ret
;----------------------------------------------------------------------------- ;-----------------------------------------------------------------------------
align 4 align 4
@ -1252,139 +1183,3 @@ IDE_BAR2_val dw ?
IDE_BAR3_val dw ? IDE_BAR3_val dw ?
endg 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}

View File

@ -432,14 +432,14 @@ sayerr:
mov [es:BOOT_IDE_PI_16], cx mov [es:BOOT_IDE_PI_16], cx
xor si, si ; device index = 0 xor si, si ; device index = 0
int 0x1A int 0x1A
jnc .found jnc .found_1
; c) class 1, subclass 1, programming interface 0x85 ; c) class 1, subclass 1, programming interface 0x85
mov ax, 0xB103 mov ax, 0xB103
mov ecx, 1*10000h + 1*100h + 0x85 mov ecx, 1*10000h + 1*100h + 0x85
mov [es:BOOT_IDE_PI_16], cx mov [es:BOOT_IDE_PI_16], cx
xor si, si ; device index = 0 xor si, si ; device index = 0
int 0x1A int 0x1A
jnc .found jnc .found_1
; d) class 1, subclass 1, programming interface 0x8A ; d) class 1, subclass 1, programming interface 0x8A
; This is a Parallel IDE Controller which uses IRQs 14 and 15. ; This is a Parallel IDE Controller which uses IRQs 14 and 15.
mov ax, 0xB103 mov ax, 0xB103
@ -447,7 +447,7 @@ sayerr:
mov [es:BOOT_IDE_PI_16], cx mov [es:BOOT_IDE_PI_16], cx
xor si, si ; device index = 0 xor si, si ; device index = 0
int 0x1A int 0x1A
jnc .found ; Parallel IDE Controller jnc .found_1 ; Parallel IDE Controller
; Controller not found! ; Controller not found!
xor ax, ax xor ax, ax
mov [es:BOOT_IDE_PI_16], ax mov [es:BOOT_IDE_PI_16], ax

View 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

View File

@ -1,238 +1,33 @@
; USB Host Controller support code: hardware-independent part, ; USB Host Controller support code: hardware-independent part,
; common for all controller types. ; common for all controller types.
; ============================================================================= iglobal
; ================================= Constants ================================= ; USB HC support: some functions interesting only for *HCI-drivers.
; ============================================================================= align 4
; USB device must have at least 100ms of stable power before initializing can usb_hc_func:
; proceed; one timer tick is 10ms, so enforce delay in 10 ticks dd usb_process_gtd
USB_CONNECT_DELAY = 10 dd usb_init_static_endpoint
; USB requires at least 10 ms for reset signalling. Normally, this is one timer dd usb_wakeup_if_needed
; tick. However, it is possible that we start reset signalling in the end of dd usb_subscribe_control
; interval between timer ticks and then we test time in the start of the next dd usb_subscription_done
; interval; in this case, the delta between [timer_ticks] is 1, but the real dd usb_allocate_common
; time passed is significantly less than 10 ms. To avoid this, we add an extra dd usb_free_common
; tick; this guarantees that at least 10 ms have passed. dd usb_td_to_virt
USB_RESET_TIME = 2 dd usb_init_transfer
; USB requires at least 10 ms of reset recovery, a delay between reset dd usb_undo_tds
; signalling and any commands to device. Add an extra tick for the same reasons dd usb_test_pending_port
; as with the previous constant. dd usb_get_tt
USB_RESET_RECOVERY_TIME = 2 dd usb_get_tt_think_time
dd usb_new_device
; ============================================================================= dd usb_disconnect_stage2
; ================================ Structures ================================= dd usb_process_wait_lists
; ============================================================================= dd usb_unlink_td
; Controller descriptor. dd usb_is_final_packet
; This structure represents the common (controller-independent) part dd usb_find_ehci_companion
; of a controller for the USB code. The corresponding controller-dependent endg
; 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 ====================================
; =============================================================================
; Initializes one controller, called by usb_init for every controller. ; 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 proc usb_init_controller
push ebp push ebp
mov ebp, esp mov ebp, esp
@ -240,6 +35,10 @@ proc usb_init_controller
; make [ebp-4] = (bus shl 8) + devfn, used by controller-specific Init funcs. ; make [ebp-4] = (bus shl 8) + devfn, used by controller-specific Init funcs.
push dword [eax+PCIDEV.devfn] push dword [eax+PCIDEV.devfn]
push eax push eax
mov edi, [eax+PCIDEV.owner]
test edi, edi
jz .nothing
mov edi, [edi+USBSRV.usb_func]
; 2. Allocate *hci_controller + usb_controller. ; 2. Allocate *hci_controller + usb_controller.
mov ebx, [edi+usb_hardware_func.DataSize] mov ebx, [edi+usb_hardware_func.DataSize]
add ebx, sizeof.usb_controller 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 mov [edi+usb_controller.ResettingPort-sizeof.usb_controller], al ; no resetting port
dec eax ; don't allocate zero address dec eax ; don't allocate zero address
mov [edi+usb_controller.ExistingAddresses-sizeof.usb_controller], eax 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] lea ecx, [edi+usb_controller.PeriodicLock-sizeof.usb_controller]
call mutex_init call mutex_init
add ecx, usb_controller.ControlLock - usb_controller.PeriodicLock add ecx, usb_controller.ControlLock - usb_controller.PeriodicLock
@ -474,3 +275,48 @@ proc usb_process_one_wait_list
.nothing: .nothing:
ret ret
endp 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

View File

@ -219,30 +219,48 @@ virtual at esp
.config dd ? ; pointer to usb_config_descr .config dd ? ; pointer to usb_config_descr
.interface dd ? ; pointer to usb_interface_descr .interface dd ? ; pointer to usb_interface_descr
end virtual 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 ; 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. ; Loop over all descriptors owned by this interface.
.lookep: .lookep:
; 1a. Skip the current descriptor. ; 2a. Skip the current descriptor.
movzx eax, [edx+usb_descr.bLength] movzx eax, [edx+usb_descr.bLength]
add edx, eax add edx, eax
sub ecx, eax sub ecx, eax
jb .errorep 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 cmp ecx, sizeof.usb_endpoint_descr
jb .errorep 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 ; this is an error: all subsequent descriptors belong to that interface
; (or further interfaces). ; (or further interfaces).
cmp [edx+usb_endpoint_descr.bDescriptorType], USB_INTERFACE_DESCR cmp [edx+usb_endpoint_descr.bDescriptorType], USB_INTERFACE_DESCR
jz .errorep 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 cmp [edx+usb_endpoint_descr.bDescriptorType], USB_ENDPOINT_DESCR
jnz .lookep 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 cmp [edx+usb_endpoint_descr.bLength], sizeof.usb_endpoint_descr
jb .errorep 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 cmp [edx+usb_endpoint_descr.bEndpointAddress], 0
jge .lookep jge .lookep
mov al, [edx+usb_endpoint_descr.bmAttributes] mov al, [edx+usb_endpoint_descr.bmAttributes]
@ -251,23 +269,22 @@ end virtual
jnz .lookep jnz .lookep
; We have located the descriptor for INTERRUPT IN endpoint, ; We have located the descriptor for INTERRUPT IN endpoint,
; the pointer is in edx. ; 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. ; Maximum length (assuming 255 downstream ports) is 40 bytes.
; Allocate 4 extra bytes to keep wMaxPacketSize. ; Allocate 4 extra bytes to keep wMaxPacketSize.
; 2a. Save registers. ; 3a. Save registers.
push edx push edx
; 2b. Call the allocator. ; 3b. Call the allocator.
movi eax, 44 movi eax, 44
call malloc call malloc
; 2c. Restore registers. ; 3c. Restore registers.
pop ecx 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 test eax, eax
jz .nomemory 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 xchg esi, eax
; 3. Open a pipe for the status endpoint with descriptor found in step 1. ; 4. Open a pipe for the status endpoint with descriptor found in step 1.
mov ebx, [.pipe]
movzx eax, [ecx+usb_endpoint_descr.bEndpointAddress] movzx eax, [ecx+usb_endpoint_descr.bEndpointAddress]
movzx edx, [ecx+usb_endpoint_descr.bInterval] movzx edx, [ecx+usb_endpoint_descr.bInterval]
movzx ecx, [ecx+usb_endpoint_descr.wMaxPacketSize] movzx ecx, [ecx+usb_endpoint_descr.wMaxPacketSize]
@ -276,11 +293,11 @@ end virtual
push ecx push ecx
stdcall usb_open_pipe, ebx, eax, ecx, INTERRUPT_PIPE, edx stdcall usb_open_pipe, ebx, eax, ecx, INTERRUPT_PIPE, edx
pop ecx 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. ; say something to the debug board and return error.
test eax, eax test eax, eax
jz .free 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, ; pass status pipe as a callback parameter,
; allow short packets. ; allow short packets.
and ecx, (1 shl 11) - 1 and ecx, (1 shl 11) - 1
@ -291,7 +308,7 @@ end virtual
(USB_HUB_DESCRIPTOR shl 24) (USB_HUB_DESCRIPTOR shl 24)
mov dword [esi+4], 40 shl 16 mov dword [esi+4], 40 shl 16
stdcall usb_control_async, ebx, esi, esi, 40, usb_hub_got_config, eax, 1 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. ; say something to the debug board and return error.
test eax, eax test eax, eax
jz .free jz .free
@ -1245,3 +1262,14 @@ end virtual
.nothing: .nothing:
retn 4 retn 4
endp 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

View File

@ -29,19 +29,20 @@
; ProcessDeferred and sleeps until this moment is reached or the thread ; ProcessDeferred and sleeps until this moment is reached or the thread
; is awakened by IRQ handler. ; 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. ; Initializes the USB subsystem.
proc usb_init proc usb_init
; 1. Initialize all locks. ; 1. Initialize all locks.
mov ecx, usb_controllers_list_mutex mov ecx, usb_controllers_list_mutex
call mutex_init 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 ; 2. Kick off BIOS from all USB controllers, calling the corresponding function
; *hci_kickoff_bios. Also count USB controllers for the next step. ; *hci_kickoff_bios. Also count USB controllers for the next step.
; Note: USB1 companion(s) must go before the corresponding EHCI controller, ; Note: USB1 companion(s) must go before the corresponding EHCI controller,
@ -59,18 +60,33 @@ proc usb_init
jz .done_kickoff jz .done_kickoff
cmp word [esi+PCIDEV.class+1], 0x0C03 cmp word [esi+PCIDEV.class+1], 0x0C03
jnz .kickoff jnz .kickoff
mov eax, uhci_kickoff_bios mov ebx, uhci_service_name
cmp byte [esi+PCIDEV.class], 0x00 cmp byte [esi+PCIDEV.class], 0x00
jz .do_kickoff jz .do_kickoff
mov eax, ohci_kickoff_bios mov ebx, ohci_service_name
cmp byte [esi+PCIDEV.class], 0x10 cmp byte [esi+PCIDEV.class], 0x10
jz .do_kickoff jz .do_kickoff
mov eax, ehci_kickoff_bios mov ebx, ehci_service_name
cmp byte [esi+PCIDEV.class], 0x20 cmp byte [esi+PCIDEV.class], 0x20
jnz .kickoff jnz .kickoff
.do_kickoff: .do_kickoff:
inc dword [esp] 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 jmp .kickoff
.done_kickoff: .done_kickoff:
pop eax pop eax
@ -97,7 +113,6 @@ proc usb_init
jz .done_ehci jz .done_ehci
cmp [eax+PCIDEV.class], 0x0C0320 cmp [eax+PCIDEV.class], 0x0C0320
jnz .scan_ehci jnz .scan_ehci
mov edi, ehci_hardware_func
call usb_init_controller call usb_init_controller
jmp .scan_ehci jmp .scan_ehci
.done_ehci: .done_ehci:
@ -108,10 +123,8 @@ proc usb_init
mov eax, [eax+PCIDEV.list.next] mov eax, [eax+PCIDEV.list.next]
cmp eax, pcidev_list cmp eax, pcidev_list
jz .done_usb1 jz .done_usb1
mov edi, uhci_hardware_func
cmp [eax+PCIDEV.class], 0x0C0300 cmp [eax+PCIDEV.class], 0x0C0300
jz @f jz @f
mov edi, ohci_hardware_func
cmp [eax+PCIDEV.class], 0x0C0310 cmp [eax+PCIDEV.class], 0x0C0310
jnz .scan_usb1 jnz .scan_usb1
@@: @@:
@ -238,11 +251,8 @@ usb_controllers_list_mutex MUTEX
endg endg
include "memory.inc" include "memory.inc"
include "common.inc"
include "hccommon.inc" include "hccommon.inc"
include "pipe.inc" include "pipe.inc"
include "ohci.inc"
include "uhci.inc"
include "ehci.inc"
include "protocol.inc" include "protocol.inc"
include "hub.inc" include "hub.inc"
include "scheduler.inc"

View File

@ -12,77 +12,6 @@
; Data for one pool: dd pointer to the first page, MUTEX lock. ; 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. ; Allocator for fixed-size blocks: allocate a block.
; [ebx-4] = pointer to the first page, ebx = pointer to MUTEX structure. ; [ebx-4] = pointer to the first page, ebx = pointer to MUTEX structure.
proc usb_allocate_common proc usb_allocate_common
@ -187,12 +116,12 @@ end virtual
ret 4 ret 4
endp endp
; Helper procedure for OHCI: translate physical address in ecx ; Helper procedure: translate physical address in ecx
; of some transfer descriptor to linear address. ; of some transfer descriptor to linear address.
; in: eax = address of first page
proc usb_td_to_virt proc usb_td_to_virt
; Traverse all pages used for transfer descriptors, looking for the one ; Traverse all pages used for transfer descriptors, looking for the one
; with physical address as in ecx. ; with physical address as in ecx.
mov eax, [usb_gtd_first_page]
@@: @@:
test eax, eax test eax, eax
jz .zero jz .zero

File diff suppressed because it is too large Load Diff

View File

@ -1,195 +1,5 @@
; Functions for USB pipe manipulation: opening/closing, sending data etc. ; 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 USB_STDCALL_VERIFY = 1
macro stdcall_verify [arg] macro stdcall_verify [arg]
{ {
@ -216,7 +26,7 @@ endp
proc usb_open_pipe stdcall uses ebx esi edi,\ proc usb_open_pipe stdcall uses ebx esi edi,\
config_pipe:dword, endpoint:dword, maxpacket:dword, type:dword, interval:dword config_pipe:dword, endpoint:dword, maxpacket:dword, type:dword, interval:dword
locals 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 targetsmask dd ? ; S-Mask for USB2
bandwidth dd ? bandwidth dd ?
target dd ? target dd ?
@ -810,6 +620,27 @@ proc usb_unlink_td
ret ret
endp 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 if USB_STDCALL_VERIFY
proc verify_regs proc verify_regs
virtual at esp virtual at esp

View File

@ -29,11 +29,6 @@ USB_DEVICE_QUALIFIER_DESCR = 6
USB_OTHER_SPEED_CONFIG_DESCR = 7 USB_OTHER_SPEED_CONFIG_DESCR = 7
USB_INTERFACE_POWER_DESCR = 8 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 ; Compile-time setting. If set, the code will dump all descriptors as they are
; read to the debug board. ; read to the debug board.
USB_DUMP_DESCRIPTORS = 1 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. ; 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 ; Thus, the call is asynchronous; meet us in usb_after_set_address when it will
; be safe to continue. ; be safe to continue.
dbgstr 'address set in device' ; dbgstr 'address set in device'
call [eax+usb_hardware_func.SetDeviceAddress] call [eax+usb_hardware_func.SetDeviceAddress]
; 2b. If the port is in non-root hub, clear 'reset in progress' flag. ; 2b. If the port is in non-root hub, clear 'reset in progress' flag.
; In any case, proceed to 4. ; In any case, proceed to 4.
@ -409,7 +404,7 @@ endp
; is cleared after request from usb_set_address_callback. ; is cleared after request from usb_set_address_callback.
; in: ebx -> usb_pipe ; in: ebx -> usb_pipe
proc usb_after_set_address 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. ; Issue control transfer GET_DESCRIPTOR(DEVICE_DESCR) for first 8 bytes.
; Remember, we still do not know the actual packet size; ; Remember, we still do not know the actual packet size;
; 8-bytes-request is safe. ; 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

View File

@ -514,6 +514,8 @@ struct PCIDEV
devfn db ? devfn db ?
bus db ? bus db ?
irq_line db ? irq_line db ?
rb 1
owner dd ? ; pointer to SRV or 0
ends ends
; The following macro assume that we are on uniprocessor machine. ; The following macro assume that we are on uniprocessor machine.

View File

@ -128,10 +128,35 @@ proc get_service stdcall, sz_name:dword
mov edx, [edx+SRV.fd] mov edx, [edx+SRV.fd]
jmp @B jmp @B
.not_load: .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 pop ebp
jmp load_driver jmp load_driver
.ok: .ok:
mov eax, edx mov eax, edx
.nothing:
ret ret
endp endp
@ -322,7 +347,7 @@ endp
; allocate kernel memory and loads the specified file ; allocate kernel memory and loads the specified file
; ;
; param ; param
; file_name= full path to file ; file_name= path to file
; ;
; retval ; retval
; eax= file image in kernel memory ; eax= file image in kernel memory

View File

@ -45,6 +45,7 @@ __exports:
map_io_mem, 'MapIoMem', \ ; stdcall map_io_mem, 'MapIoMem', \ ; stdcall
map_page, 'MapPage', \ ; stdcall map_page, 'MapPage', \ ; stdcall
get_pg_addr, 'GetPgAddr', \ ; eax get_pg_addr, 'GetPgAddr', \ ; eax
get_phys_addr, 'GetPhysAddr', \ ; eax
map_space, 'MapSpace', \ map_space, 'MapSpace', \
release_pages, 'ReleasePages', \ release_pages, 'ReleasePages', \
\ \
@ -112,6 +113,7 @@ __exports:
usb_normal_transfer_async, 'USBNormalTransferAsync', \ usb_normal_transfer_async, 'USBNormalTransferAsync', \
usb_control_async, 'USBControlTransferAsync', \ usb_control_async, 'USBControlTransferAsync', \
usb_get_param, 'USBGetParam', \ usb_get_param, 'USBGetParam', \
usb_hc_func, 'USBHCFunc', \
\ \
NET_add_device, 'NetRegDev', \ NET_add_device, 'NetRegDev', \
NET_remove_device, 'NetUnRegDev', \ NET_remove_device, 'NetUnRegDev', \

View File

@ -284,8 +284,7 @@ proc alloc_kernel_space stdcall, size:dword
cmp eax, [heap_free] cmp eax, [heap_free]
ja .error ja .error
mov ecx, heap_mutex spin_lock_irqsave heap_mutex
call mutex_lock
mov eax, [size] mov eax, [size]
@ -345,8 +344,7 @@ proc alloc_kernel_space stdcall, size:dword
call md.add_to_used call md.add_to_used
mov ecx, heap_mutex spin_unlock_irqrestore heap_mutex
call mutex_unlock
mov eax, [esi+block_base] mov eax, [esi+block_base]
pop edi pop edi
pop esi pop esi
@ -364,8 +362,7 @@ proc alloc_kernel_space stdcall, size:dword
jmp .add_used jmp .add_used
.error_unlock: .error_unlock:
mov ecx, heap_mutex spin_unlock_irqrestore heap_mutex
call mutex_unlock
.error: .error:
xor eax, eax xor eax, eax
pop edi pop edi
@ -377,8 +374,7 @@ endp
align 4 align 4
proc free_kernel_space stdcall uses ebx ecx edx esi edi, base:dword proc free_kernel_space stdcall uses ebx ecx edx esi edi, base:dword
mov ecx, heap_mutex spin_lock_irqsave heap_mutex
call mutex_lock
mov eax, [base] 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] lea edx, [mem_block_list+eax*8]
list_add edi, edx list_add edi, edx
.m_eq: .m_eq:
mov ecx, heap_mutex spin_unlock_irqrestore heap_mutex
call mutex_unlock
xor eax, eax xor eax, eax
not eax not eax
ret ret
@ -459,8 +454,7 @@ proc free_kernel_space stdcall uses ebx ecx edx esi edi, base:dword
jmp .add_block jmp .add_block
.fail: .fail:
mov ecx, heap_mutex spin_unlock_irqrestore heap_mutex
call mutex_unlock
xor eax, eax xor eax, eax
ret ret
endp endp
@ -544,17 +538,15 @@ proc kernel_free stdcall, base:dword
push ebx esi push ebx esi
mov ecx, heap_mutex spin_lock_irqsave heap_mutex
call mutex_lock
mov eax, [base] mov eax, [base]
call md.find_used call md.find_used
mov ecx, heap_mutex
cmp [esi+block_flags], USED_BLOCK cmp [esi+block_flags], USED_BLOCK
jne .fail jne .fail
call mutex_unlock spin_unlock_irqrestore heap_mutex
mov eax, [esi+block_base] mov eax, [esi+block_base]
mov ecx, [esi+block_size] mov ecx, [esi+block_size]
@ -564,7 +556,7 @@ proc kernel_free stdcall, base:dword
pop esi ebx pop esi ebx
ret ret
.fail: .fail:
call mutex_unlock spin_unlock_irqrestore heap_mutex
xor eax, eax xor eax, eax
pop esi ebx pop esi ebx
ret ret

View File

@ -1223,22 +1223,7 @@ f68:
cmp edx, OS_BASE cmp edx, OS_BASE
jae .fail jae .fail
mov edi, edx stdcall load_pe_driver, ecx, 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
@@:
mov [esp+32], eax mov [esp+32], eax
ret ret
.22: .22:
@ -1318,26 +1303,32 @@ f68call: ; keep this table closer to main code
align 4 align 4
proc load_pe_driver stdcall, file:dword proc load_pe_driver stdcall, file:dword, cmdline:dword
push esi
stdcall load_PE, [file] stdcall load_PE, [file]
test eax, eax test eax, eax
jz .fail jz .fail
mov esi, eax mov esi, eax
stdcall eax, DRV_ENTRY push [cmdline]
push DRV_ENTRY
call eax
pop ecx
pop ecx
test eax, eax test eax, eax
jz .fail jz .fail
mov [eax+SRV.entry], esi mov [eax+SRV.entry], esi
pop esi
ret ret
.fail: .fail:
xor eax, eax xor eax, eax
pop esi
ret ret
endp endp
align 4 align 4
proc init_mtrr proc init_mtrr
@ -1385,9 +1376,9 @@ proc init_mtrr
xor eax, eax xor eax, eax
xor edx, edx xor edx, edx
@@: @@:
wrmsr
inc ecx inc ecx
cmp ecx, 0x210 wrmsr
cmp ecx, 0x20F
jb @b jb @b
; enable MTRRs ; enable MTRRs
pop eax pop eax

View File

@ -85,13 +85,12 @@ L3:
mov ecx, eax mov ecx, eax
add edi, DWORD PTR [edx+260] add edi, DWORD PTR [edx+260]
add ecx, 3
shr ecx, 2 shr ecx, 2
rep movsd rep movsd
L4: L4:
mov ecx, DWORD PTR [edx+256] mov ecx, DWORD PTR [edx+256]
add ecx, 4095
and ecx, -4096
cmp ecx, eax cmp ecx, eax
jbe L6 jbe L6
sub ecx, eax sub ecx, eax
@ -111,15 +110,17 @@ L2:
mov edi, DWORD PTR [esp+32] mov edi, DWORD PTR [esp+32]
cmp DWORD PTR [edi+164], 0 cmp DWORD PTR [edi+164], 0
je L9 je L9
pushd [edi+164]
mov esi, ebp mov esi, ebp
mov ecx, ebp mov ecx, ebp
sub esi, DWORD PTR [edi+52] sub esi, DWORD PTR [edi+52]
add ecx, DWORD PTR [edi+160] add ecx, DWORD PTR [edi+160]
mov eax, esi mov eax, esi
shr eax, 16 shr eax, 16
mov DWORD PTR [esp+12], eax mov DWORD PTR [esp+16], eax
jmp L11
L12: L12:
mov eax, [ecx+4]
sub [esp], eax
lea ebx, [eax-8] lea ebx, [eax-8]
xor edi, edi xor edi, edi
shr ebx, 1 shr ebx, 1
@ -136,7 +137,7 @@ L14:
je L18 je L18
dec ax dec ax
jne L15 jne L15
mov eax, DWORD PTR [esp+12] mov eax, DWORD PTR [esp+16]
add WORD PTR [edx+ebp], ax add WORD PTR [edx+ebp], ax
L17: L17:
add WORD PTR [edx+ebp], si add WORD PTR [edx+ebp], si
@ -149,9 +150,9 @@ L13:
jne L14 jne L14
add ecx, DWORD PTR [ecx+4] add ecx, DWORD PTR [ecx+4]
L11: L11:
mov eax, DWORD PTR [ecx+4] cmp dword [esp], 0
test eax, eax jg L12
jne L12 pop eax
L9: L9:
mov edx, DWORD PTR [esp+32] mov edx, DWORD PTR [esp+32]
cmp DWORD PTR [edx+132], 0 cmp DWORD PTR [edx+132], 0
@ -178,6 +179,10 @@ L23:
mov ecx, DWORD PTR [eax-4] mov ecx, DWORD PTR [eax-4]
mov DWORD PTR [esp+48], edi mov DWORD PTR [esp+48], edi
mov edx, DWORD PTR [eax-20] mov edx, DWORD PTR [eax-20]
test edx, edx
jnz @f
mov edx, ecx
@@:
mov DWORD PTR [esp+52], 0 mov DWORD PTR [esp+52], 0
add ecx, ebp add ecx, ebp
add edx, ebp add edx, ebp

View File

@ -386,7 +386,18 @@ sys_resize_app_memory:
; cmp eax,1 ; cmp eax,1
dec ebx dec ebx
jnz .no_application_mem_resize 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 stdcall new_mem_resize, ecx
.store_result:
mov [esp+32], eax mov [esp+32], eax
.no_application_mem_resize: .no_application_mem_resize:
ret ret

View File

@ -517,6 +517,7 @@ end if
add edi, page_tabs add edi, page_tabs
.remap: .remap:
lodsd lodsd
and eax, 0xFFFFF000
or eax, ebx; force user level r/w access or eax, ebx; force user level r/w access
stosd stosd
add edx, 0x1000 add edx, 0x1000
@ -1208,7 +1209,7 @@ proc set_app_params stdcall,slot:dword, params:dword,\
mov [ebx+REG_EAX], eax mov [ebx+REG_EAX], eax
mov eax, [esi+0x08] ;app_eip mov eax, [esi+0x08] ;app_eip
mov [ebx+REG_EIP], eax;app_entry mov [ebx+REG_EIP], eax ;app_entry
mov [ebx+REG_CS], dword app_code mov [ebx+REG_CS], dword app_code
mov ecx, USER_PRIORITY mov ecx, USER_PRIORITY

View File

@ -3,15 +3,18 @@
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; ;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;; ;; 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 VORTEX86DEBUG = 0 ; For testing in emulators and in non-Vortex86 CPU computers, set this to 1
VORTEX86DEBUGVALUE = 0x35504d44 ; FAKE port output = used for testing 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) ; 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 ; 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 Vortex86SoClist: ; List of Vortex86 CPUs known today. Add new record to this list when new CPU becomes available
db 0x31, 'SX ' ; id=1 db 0x31, 'SX ' ; id=1
db 0x32, 'DX ' ; id=2 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 0x34, 'DX2' ; id=4
db 0x35, 'MX+' ; id=5 db 0x35, 'MX+' ; id=5
db 0x37, 'EX ' ; id=6 db 0x37, 'EX ' ; id=7
Vortex86SoCnum = ($ - Vortex86SoClist) / 4 ; Calculate the total number of known Vortex86 CPUs (if id=Vortex86SoCnum+1 --> unknown SoC) Vortex86SoCnum = ($ - Vortex86SoClist) / 4 ; Calculate the total number of known Vortex86 CPUs
endg endg
; When in debug mode, perform SoC detection regardless of the actual CPU vendor (even for vendors other than DMP) ; When in debug mode, perform SoC detection regardless of the actual CPU vendor (even for vendors other than DMP)
@ -41,57 +44,115 @@ endg
if ~ VORTEX86DEBUG if ~ VORTEX86DEBUG
cmp [cpu_vendor], 'Vort' cmp [cpu_vendor], 'Vort'
jnz .Vortex86end ; If the CPU vendor is not 'Vortex86 SoC', skip the SoC detection jnz .Vortex86end ; If the CPU vendor is not 'Vortex86 SoC', skip the SoC detection
end if end if
mov dx, 0xcf8 ; CF8h = Vortex86 PCI Configuration Address port mov eax, NORTH_BRIDGE+0x90 ; 0x80000090 = PCI Configuration Address Register to read from (32-bit register - accessed as DWORD)
mov eax, 0x80000090 ; 0x80000090 = Starting PCI address 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)
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
if VORTEX86DEBUG ; When in debug mode, pretend that we received port output equal to "VORTEX86DEBUGVALUE" if VORTEX86DEBUG ; When in debug mode, pretend that we received port output equal to "VORTEX86DEBUGVALUE"
mov eax, VORTEX86DEBUGVALUE mov eax, VORTEX86DEBUGVALUE
end if end if
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, ...)
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
mov esi, Vortex86SoClist ; ESI points to the start of Vortex86SoClist (used implicitly in "LODSD" command below) 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) 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) 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) 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 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) 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 cmp bl, al ; Check if our CPU matches the current record in the list
jne @b ; No match --> repeat with next record 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 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 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, "%s (id=%d)\n", Vortex86SoCname, [Vortex86CPUid]:1 ; Say what we have found (CPU name and id)
DEBUGF 1, "0 (NULL)\n" jmp .Vortex86
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
.notVortex86: ; In case this register is used by other CPUs for other purpose, it's interesting what it contains .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" 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: .Vortex86end:

View File

@ -458,6 +458,23 @@ if DUMP_PACKETS
DEBUGF 1,'\n' DEBUGF 1,'\n'
end if end if
stdcall USBNormalTransferAsync, [esi+usb_device_data.OutPipe], edx, command_block_wrapper.sizeof, request_callback1, esi, 0 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 ret
endp endp
@ -526,28 +543,21 @@ end virtual
; 3. Increment the stage. ; 3. Increment the stage.
mov edx, [ecx+usb_device_data.RequestsQueue+request_queue_item.Next] mov edx, [ecx+usb_device_data.RequestsQueue+request_queue_item.Next]
inc [edx+request_queue_item.Stage] 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 cmp [ecx+usb_device_data.Command.Length], 0
jz ..request_get_status jz ..request_get_status
; 5. Initiate USB transfer. If this fails, go to the error handler. ; 4b. If data were enqueued in the first stage, do nothing, wait for request_callback2.
mov eax, [ecx+usb_device_data.InPipe]
cmp [ecx+usb_device_data.Command.Flags], 0 cmp [ecx+usb_device_data.Command.Flags], 0
js @f jns .nothing
mov eax, [ecx+usb_device_data.OutPipe] ; 5. Initiate USB transfer. If this fails, go to the error handler.
if DUMP_PACKETS stdcall USBNormalTransferAsync, [ecx+usb_device_data.InPipe], [edx+request_queue_item.Buffer], [ecx+usb_device_data.Command.Length], request_callback2, ecx, 0
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
test eax, eax test eax, eax
jz .error 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 ret 20
.error: .error:
; Error. ; Error.
@ -596,15 +606,20 @@ end if
test eax, eax test eax, eax
jnz .error jnz .error
; No 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: ..request_get_status:
; 3. Increment the stage. ; 3. Increment the stage.
mov edx, [ecx+usb_device_data.RequestsQueue+request_queue_item.Next] mov edx, [ecx+usb_device_data.RequestsQueue+request_queue_item.Next]
inc [edx+request_queue_item.Stage] inc [edx+request_queue_item.Stage]
; 4. Initiate USB transfer. If this fails, go to the error handler. ; 4. Initiate USB transfer. If this fails, go to the error handler.
..enqueue_status:
lea edx, [ecx+usb_device_data.Status] lea edx, [ecx+usb_device_data.Status]
stdcall USBNormalTransferAsync, [ecx+usb_device_data.InPipe], edx, command_status_wrapper.sizeof, request_callback3, ecx, 0 stdcall USBNormalTransferAsync, [ecx+usb_device_data.InPipe], edx, command_status_wrapper.sizeof, request_callback3, ecx, 0
test eax, eax test eax, eax
jz .error jz .error
.nothing:
ret 20 ret 20
.error: .error:
; Error. ; Error.

View File

@ -1884,7 +1884,6 @@ align 4
; get WinMap start ; get WinMap start
push esi push esi
mov esi, [_display.width] mov esi, [_display.width]
; imul edi, ebx
mov edi, [d_width_calc_area + ebx*4] mov edi, [d_width_calc_area + ebx*4]
add edi, eax add edi, eax

View File

@ -41,6 +41,8 @@ proc mem_test
mov [BOOT_VARS-OS_BASE + 0x9108], eax mov [BOOT_VARS-OS_BASE + 0x9108], eax
mov [BOOT_VARS-OS_BASE + 0x910C], edi mov [BOOT_VARS-OS_BASE + 0x910C], edi
mov [BOOT_VARS-OS_BASE + 0x9110], eax mov [BOOT_VARS-OS_BASE + 0x9110], eax
inc eax
mov [BOOT_VARS-OS_BASE + 0x9114], eax
.ret: .ret:
ret ret
endp endp

View File

@ -2540,10 +2540,10 @@ sysfn_mouse_acceleration: ; 18.19 = set/get mouse features
; cmp ecx,4 ; set mouse pointer position ; cmp ecx,4 ; set mouse pointer position
dec ecx dec ecx
jnz .set_mouse_button jnz .set_mouse_button
cmp dx, word[_display.width] cmp dx, word[_display.height]
jae .end jae .end
rol edx, 16 rol edx, 16
cmp dx, word[_display.height] cmp dx, word[_display.width]
jae .end jae .end
mov [MOUSE_X], edx mov [MOUSE_X], edx
call wakeup_osloop call wakeup_osloop

View File

@ -237,6 +237,8 @@ include "blkdev/ide_cache.inc"
; HD drive controller ; HD drive controller
include "blkdev/hd_drv.inc" include "blkdev/hd_drv.inc"
; Access through BIOS
include "blkdev/bd_drv.inc"
; CD drive controller ; CD drive controller

View File

@ -19,6 +19,13 @@
$Revision: 3515 $ $Revision: 3515 $
IPv4_MAX_FRAGMENTS = 64 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 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) ; Ip header begins here (we will need the IP header to re-construct the complete packet)
ends ends
struct IPv4_ROUTE
Destination dd ?
Gateway dd ?
Flags dd ?
Use dd ?
Interface dd ?
ends
uglobal uglobal
align 4 align 4
@ -70,6 +87,8 @@ align 4
IPv4_FRAGMENT_LIST rb IPv4_MAX_FRAGMENTS * sizeof.IPv4_FRAGMENT_slot IPv4_FRAGMENT_LIST rb IPv4_MAX_FRAGMENTS * sizeof.IPv4_FRAGMENT_slot
IPv4_ROUTES rd IPv4_MAX_ROUTES * sizeof.IPv4_ROUTE
endg endg

View File

@ -230,7 +230,7 @@ ICMP_input:
test eax, eax test eax, eax
jnz @f jnz @f
call NET_ptr_to_num4 call NET_ptr_to_num4
inc [UDP_PACKETS_TX + edi] inc [ICMP_PACKETS_TX + edi]
@@: @@:
ret ret

View File

@ -35,7 +35,7 @@ LOOPBACK_DEVICE:
.packets_rx dd 0 .packets_rx dd 0
.link_state dd -1 .link_state dd -1
.hwacc dd 0 .hwacc dd NET_HWACC_TCP_IPv4_IN + NET_HWACC_TCP_IPv4_OUT
.namestr db 'loopback', 0 .namestr db 'loopback', 0

View File

@ -28,7 +28,7 @@ struct SOCKET
PID dd ? ; process ID PID dd ? ; process ID
TID dd ? ; thread ID TID dd ? ; thread ID
Domain dd ? ; INET/LOCAL/.. Domain dd ? ; INET/LOCAL/..
Type dd ? ; RAW/STREAM/DGRAP Type dd ? ; RAW/STREAM/DGRAM
Protocol dd ? ; ICMP/IPv4/ARP/TCP/UDP Protocol dd ? ; ICMP/IPv4/ARP/TCP/UDP
errorcode dd ? errorcode dd ?
device dd ? ; driver pointer, socket pointer if it's an LOCAL socket device dd ? ; driver pointer, socket pointer if it's an LOCAL socket
@ -92,8 +92,8 @@ struct TCP_SOCKET IP_SOCKET
SND_MAX dd ? SND_MAX dd ?
; congestion control ; congestion control
SND_CWND dd ? SND_CWND dd ? ; congestion window
SND_SSTHRESH dd ? SND_SSTHRESH dd ? ; slow start threshold
;---------------------- ;----------------------
; Transmit timing stuff ; Transmit timing stuff
@ -141,10 +141,6 @@ struct TCP_SOCKET IP_SOCKET
seg_next dd ? ; re-assembly queue seg_next dd ? ; re-assembly queue
temp_bits db ?
rb 3 ; align
ends ends
struct UDP_SOCKET IP_SOCKET struct UDP_SOCKET IP_SOCKET
@ -715,12 +711,13 @@ SOCKET_close:
ret ret
.tcp: .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_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 ret
@ -1562,10 +1559,10 @@ SOCKET_ring_write:
pop ecx pop ecx
; unlock mutex ; unlock mutex
push eax ecx pusha
lea ecx, [eax + RING_BUFFER.mutex] lea ecx, [eax + RING_BUFFER.mutex]
call mutex_unlock ; TODO: check what registers this function actually destroys call mutex_unlock ; TODO: check what registers this function actually destroys
pop ecx eax popa
ret ret
@ -2085,7 +2082,6 @@ SOCKET_num_to_ptr:
mov eax, [eax + SOCKET.NextPtr] mov eax, [eax + SOCKET.NextPtr]
or eax, eax or eax, eax
jz .error jz .error
diff16 "tetten", 0, $
cmp [eax + SOCKET.Number], ecx cmp [eax + SOCKET.Number], ecx
jne .next_socket jne .next_socket
@ -2205,7 +2201,7 @@ SOCKET_check_owner:
; ;
; Kernel calls this function when a certain process ends ; Kernel calls this function when a certain process ends
; This function will check if the process had any open sockets ; This function will check if the process had any open sockets
; And update them accordingly ; And update them accordingly (clean up)
; ;
; IN: edx = pid ; IN: edx = pid
; OUT: / ; OUT: /
@ -2251,7 +2247,7 @@ SOCKET_process_end:
cmp [eax + SOCKET.Protocol], IP_PROTO_TCP cmp [eax + SOCKET.Protocol], IP_PROTO_TCP
jne .free jne .free
call TCP_close call TCP_disconnect
jmp .closed jmp .closed
.free: .free:
@ -2356,20 +2352,9 @@ SOCKET_is_disconnected:
and [eax + SOCKET.state], not (SS_ISCONNECTING + SS_ISCONNECTED + SS_ISDISCONNECTING) and [eax + SOCKET.state], not (SS_ISCONNECTING + SS_ISCONNECTED + SS_ISDISCONNECTING)
or [eax + SOCKET.state], SS_CANTRCVMORE + SS_CANTSENDMORE 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 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
;----------------------------------------------------------------- ;-----------------------------------------------------------------

View File

@ -110,7 +110,7 @@ SS_MORETOCOME = 0x4000
SS_BLOCKED = 0x8000 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 MAX_backlog = 20 ; maximum backlog for stream sockets
; Error Codes ; Error Codes
@ -152,7 +152,8 @@ NET_LINK_PPP = 2 ; Point to Point Protocol (PPPoE, ...)
NET_LINK_IEEE802.11 = 3 ; IEEE 802.11 (WiFi) NET_LINK_IEEE802.11 = 3 ; IEEE 802.11 (WiFi)
; Hardware acceleration bits ; 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 struct NET_DEVICE

View File

@ -143,6 +143,62 @@ align 4
TCP_input_event dd ? TCP_input_event dd ?
endg 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
;----------------------------------------------------------------- ;-----------------------------------------------------------------
; ;

View File

@ -78,7 +78,13 @@ TCP_input:
align 4 align 4
TCP_process_input: proc TCP_process_input
locals
dataoffset dd ?
timestamp dd ?
temp_bits db ?
endl
xor esi, esi xor esi, esi
mov ecx, MANUAL_DESTROY mov ecx, MANUAL_DESTROY
@ -94,6 +100,7 @@ TCP_process_input:
get_from_queue TCP_queue, TCP_QUEUE_SIZE, sizeof.TCP_queue_entry, .wait get_from_queue TCP_queue, TCP_QUEUE_SIZE, sizeof.TCP_queue_entry, .wait
push [esi + TCP_queue_entry.timestamp] push [esi + TCP_queue_entry.timestamp]
pop [timestamp]
push [esi + TCP_queue_entry.buffer_ptr] push [esi + TCP_queue_entry.buffer_ptr]
mov ebx, [esi + TCP_queue_entry.device_ptr] mov ebx, [esi + TCP_queue_entry.device_ptr]
@ -109,8 +116,8 @@ TCP_process_input:
je .checksum_ok je .checksum_ok
; re-calculate the checksum (if not already done by hw) ; re-calculate the checksum (if not already done by hw)
; test [ebx + NET_DEVICE.hwacc], HWACC_TCP_IPv4_IN test [ebx + NET_DEVICE.hwacc], NET_HWACC_TCP_IPv4_IN
; jnz .checksum_ok jnz .checksum_ok
push ecx esi push ecx esi
pushw [esi + TCP_header.Checksum] pushw [esi + TCP_header.Checksum]
@ -123,12 +130,13 @@ TCP_process_input:
.checksum_ok: .checksum_ok:
; Verify the data offset ; 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] 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 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 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 DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: %u bytes of data\n", ecx
@ -211,7 +219,7 @@ TCP_process_input:
;--------------------------- ;---------------------------
; disable all temporary bits ; disable all temporary bits
mov [ebx + TCP_SOCKET.temp_bits], 0 mov [temp_bits], 0
;--------------------------------------- ;---------------------------------------
; unscale the window into a 32 bit value ; unscale the window into a 32 bit value
@ -245,7 +253,7 @@ TCP_process_input:
mov ebx, eax 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 push dword [edi + 4] ; Ipv4 destination addres
pop [ebx + IP_SOCKET.LocalIP] pop [ebx + IP_SOCKET.LocalIP]
@ -267,18 +275,18 @@ TCP_process_input:
;-------------------- ;--------------------
; Process TCP options ; 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 push ecx
movzx ecx, [edx + TCP_header.DataOffset] mov ecx, [dataoffset]
cmp ecx, sizeof.TCP_header ; Does header contain any options? cmp ecx, sizeof.TCP_header ; Does header contain any options?
je .no_options je .no_options
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Segment has options\n" 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 add ecx, edx
lea esi, [edx + sizeof.TCP_header] lea esi, [edx + sizeof.TCP_header]
@ -311,9 +319,10 @@ TCP_process_input:
test [edx + TCP_header.Flags], TH_SYN test [edx + TCP_header.Flags], TH_SYN
jz @f jz @f
xor eax, eax
lodsw lodsw
rol ax, 8 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 call TCP_mss
@@: @@:
jmp .opt_loop jmp .opt_loop
@ -366,10 +375,11 @@ TCP_process_input:
@@: @@:
lodsd lodsd
bswap eax
mov [ebx + TCP_SOCKET.ts_val], eax mov [ebx + TCP_SOCKET.ts_val], eax
lodsd ; timestamp echo reply lodsd ; timestamp echo reply
mov [ebx + TCP_SOCKET.ts_ecr], eax 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! ; Since we have a timestamp, lets do the paws test right away!
@ -380,11 +390,11 @@ TCP_process_input:
test eax, eax test eax, eax
jz .no_paws jz .no_paws
cmp eax, [ebx + TCP_SOCKET.ts_val] 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" 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] sub eax, [ebx + TCP_SOCKET.ts_recent_age]
pop ecx pop ecx
@ -474,9 +484,9 @@ TCP_process_input:
; Update RTT estimators ; Update RTT estimators
test [ebx + TCP_SOCKET.temp_bits], TCP_BIT_TIMESTAMP test [temp_bits], TCP_BIT_TIMESTAMP
jz .no_timestamp_rtt jz .no_timestamp_rtt
mov eax, [esp + 4] ; timestamp when this segment was received mov eax, [timestamp]
sub eax, [ebx + TCP_SOCKET.ts_ecr] sub eax, [ebx + TCP_SOCKET.ts_ecr]
inc eax inc eax
call TCP_xmit_timer 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 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 mov esi, [dataoffset]
movzx esi, [edx + TCP_header.DataOffset]
add esi, edx add esi, edx
lea eax, [ebx + STREAM_SOCKET.rcv] lea eax, [ebx + STREAM_SOCKET.rcv]
call SOCKET_ring_write ; Add the data to the socket buffer 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 mov eax, ebx
call SOCKET_notify call SOCKET_notify
@ -558,12 +567,13 @@ TCP_process_input:
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Header prediction failed\n" DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Header prediction failed\n"
; Calculate receive window size ; Calculate receive window size
push edx push edx
mov eax, SOCKETBUFFSIZE mov eax, SOCKET_MAXDATA
sub eax, [ebx + STREAM_SOCKET.rcv.size] 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] mov edx, [ebx + TCP_SOCKET.RCV_ADV]
sub edx, [ebx + TCP_SOCKET.RCV_NXT] sub edx, [ebx + TCP_SOCKET.RCV_NXT]
DEBUGF DEBUG_NETWORK_VERBOSE, "Current advertised window=%d\n", edx
cmp eax, edx cmp eax, edx
jg @f jg @f
mov eax, edx mov eax, edx
@ -583,8 +593,9 @@ TCP_process_input:
;---------------------------- ;----------------------------
; trim any data not in window ; 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] mov eax, [ebx + TCP_SOCKET.RCV_NXT]
sub eax, [edx + TCP_header.SequenceNumber] sub eax, [edx + TCP_header.SequenceNumber]
jle .no_duplicate jle .no_duplicate
@ -609,7 +620,7 @@ TCP_process_input:
dec eax dec eax
.no_dup_syn: .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 cmp eax, ecx ; eax holds number of bytes to drop, ecx is data size
jb .duplicate jb .duplicate
jnz @f jnz @f
@ -623,16 +634,19 @@ TCP_process_input:
; send an ACK and resynchronize and drop any data. ; send an ACK and resynchronize and drop any data.
; But keep on processing for RST or ACK ; But keep on processing for RST or ACK
DEBUGF DEBUG_NETWORK_VERBOSE, "616\n"
or [ebx + TCP_SOCKET.t_flags], TF_ACKNOW or [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
mov eax, ecx mov eax, ecx
;TODO: update stats
;;; TODO: update stats
;----------------------------------------------- ;-----------------------------------------------
; Remove duplicate data and update urgent offset ; Remove duplicate data and update urgent offset
.duplicate: .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 add [edx + TCP_header.SequenceNumber], eax
sub ecx, 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: .no_duplicate:
cmp [ebx + SOCKET.PID], 0 cmp [ebx + SOCKET.PID], 0 ;;; TODO: use socket flags instead??
jne .not_terminated jne .not_terminated
cmp [ebx + TCP_SOCKET.t_state], TCPS_CLOSE_WAIT cmp [ebx + TCP_SOCKET.t_state], TCPS_CLOSE_WAIT
jbe .not_terminated jbe .not_terminated
@ -655,11 +669,11 @@ TCP_process_input:
mov eax, ebx mov eax, ebx
call TCP_close call TCP_close
;;;TODO: update stats ;;; TODO: update stats
jmp .respond_seg_reset jmp .respond_seg_reset
;---------------------------------------- ;----------------------------------------
; Remove data beyond right edge of window (700-736) ; Remove data beyond right edge of window
.not_terminated: .not_terminated:
mov eax, [edx + TCP_header.SequenceNumber] mov eax, [edx + TCP_header.SequenceNumber]
@ -688,32 +702,29 @@ TCP_process_input:
jmp .findpcb ; FIXME: skip code for unscaling window, ... jmp .findpcb ; FIXME: skip code for unscaling window, ...
.no_new_request: .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 ; incoming segments. Continue processing, but remember to ACK. Otherwise drop segment and ACK
cmp [ebx + TCP_SOCKET.RCV_WND], 0 cmp [ebx + TCP_SOCKET.RCV_WND], 0
jne .drop_after_ack jne .drop_after_ack
mov eax, [edx + TCP_header.SequenceNumber] mov esi, [edx + TCP_header.SequenceNumber]
cmp eax, [ebx + TCP_SOCKET.RCV_NXT] cmp esi, [ebx + TCP_SOCKET.RCV_NXT]
jne .drop_after_ack jne .drop_after_ack
DEBUGF DEBUG_NETWORK_VERBOSE, "690\n"
or [ebx + TCP_SOCKET.t_flags], TF_ACKNOW or [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
;;; TODO: update stats ;;; TODO: update stats
jmp .no_excess_data
.dont_drop_all: .dont_drop_all:
;;; TODO: update stats ;;; TODO: update stats
;;; TODO: 733 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)
sub ecx, eax and [edx + TCP_header.Flags], not (TH_PUSH or TH_FIN)
and [ebx + TCP_SOCKET.t_flags], not (TH_PUSH or TH_FIN)
.no_excess_data: .no_excess_data:
;----------------- ;-----------------
; Record timestamp (737-746) ; Record timestamp
; If last ACK falls within this segments sequence numbers, record its 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 jz .no_timestamp
mov eax, [ebx + TCP_SOCKET.last_ack_sent] mov eax, [ebx + TCP_SOCKET.last_ack_sent]
sub eax, [edx + TCP_header.SequenceNumber] sub eax, [edx + TCP_header.SequenceNumber]
@ -727,7 +738,7 @@ TCP_process_input:
DEBUGF DEBUG_NETWORK_VERBOSE, "Recording timestamp\n" 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 [ebx + TCP_SOCKET.ts_recent_age], eax
mov eax, [ebx + TCP_SOCKET.ts_val] mov eax, [ebx + TCP_SOCKET.ts_val]
mov [ebx + TCP_SOCKET.ts_recent], eax mov [ebx + TCP_SOCKET.ts_recent], eax
@ -882,7 +893,9 @@ TCP_process_input:
mov eax, [ebx + TCP_SOCKET.SND_WND] mov eax, [ebx + TCP_SOCKET.SND_WND]
cmp eax, [ebx + TCP_SOCKET.SND_CWND] 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 shr eax, 1
push edx push edx
xor edx, edx xor edx, edx
@ -993,13 +1006,13 @@ TCP_process_input:
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: acceptable ACK for %u bytes\n", edi 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 ; 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 jz .timestamp_not_present
mov eax, [esp+4] mov eax, [timestamp]
sub eax, [ebx + TCP_SOCKET.ts_ecr] sub eax, [ebx + TCP_SOCKET.ts_ecr]
inc eax inc eax
call TCP_xmit_timer call TCP_xmit_timer
@ -1028,7 +1041,7 @@ TCP_process_input:
cmp eax, [edx + TCP_header.AckNumber] cmp eax, [edx + TCP_header.AckNumber]
jne .more_data jne .more_data
and [ebx + TCP_SOCKET.timer_flags], not timer_flag_retransmission 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 jmp .no_restart
.more_data: .more_data:
test [ebx + TCP_SOCKET.timer_flags], timer_flag_persist test [ebx + TCP_SOCKET.timer_flags], timer_flag_persist
@ -1067,7 +1080,9 @@ TCP_process_input:
pop ecx pop ecx
cmp esi, eax cmp esi, eax
cmova esi, eax jbe @f
mov esi, eax
@@:
mov [ebx + TCP_SOCKET.SND_CWND], esi mov [ebx + TCP_SOCKET.SND_CWND], esi
;------------------------------------------ ;------------------------------------------
@ -1175,12 +1190,9 @@ TCP_process_input:
call mutex_unlock call mutex_unlock
pop ebx pop ebx
push ebx
mov eax, ebx mov eax, ebx
call TCP_disconnect call TCP_close
pop ebx jmp .drop_no_socket
jmp .destroy_new_socket
.ack_tw: .ack_tw:
mov [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL mov [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL
@ -1228,7 +1240,7 @@ align 4
TCP_rcvseqinit ebx TCP_rcvseqinit ebx
mov [ebx + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED 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 mov [ebx + TCP_SOCKET.timer_keepalive], TCP_time_keep_interval ;;;; macro
or [ebx + TCP_SOCKET.timer_flags], timer_flag_keepalive or [ebx + TCP_SOCKET.timer_flags], timer_flag_keepalive
@ -1238,7 +1250,7 @@ align 4
lea eax, [ebx + STREAM_SOCKET.rcv] lea eax, [ebx + STREAM_SOCKET.rcv]
call SOCKET_ring_create call SOCKET_ring_create
and [ebx + TCP_SOCKET.temp_bits], not TCP_BIT_DROPSOCKET and [temp_bits], not TCP_BIT_DROPSOCKET
pusha pusha
mov eax, ebx mov eax, ebx
@ -1355,7 +1367,16 @@ align 4
inc [edx + TCP_header.SequenceNumber] 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 eax, [edx + TCP_header.SequenceNumber]
mov [ebx + TCP_SOCKET.RCV_UP], eax mov [ebx + TCP_SOCKET.RCV_UP], eax
@ -1409,7 +1430,7 @@ align 4
push [edx + TCP_header.AckNumber] push [edx + TCP_header.AckNumber]
pop [ebx + TCP_SOCKET.SND_WL2] pop [ebx + TCP_SOCKET.SND_WL2]
or [ebx + TCP_SOCKET.temp_bits], TCP_BIT_NEEDOUTPUT or [temp_bits], TCP_BIT_NEEDOUTPUT
.no_window_update: .no_window_update:
@ -1475,7 +1496,7 @@ align 4
or [ebx + TCP_SOCKET.t_flags], TF_DELACK or [ebx + TCP_SOCKET.t_flags], TF_DELACK
pusha pusha
movzx esi, [edx + TCP_header.DataOffset] mov esi, [dataoffset]
add esi, edx add esi, edx
lea eax, [ebx + STREAM_SOCKET.rcv] lea eax, [ebx + STREAM_SOCKET.rcv]
call SOCKET_ring_write ; Add the data to the socket buffer call SOCKET_ring_write ; Add the data to the socket buffer
@ -1489,16 +1510,16 @@ align 4
jmp .data_done jmp .data_done
.out_of_order: .out_of_order:
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP data is out of order!\nSequencenumber is %u, we expected %u.\n", \
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP data is out of order\n" [edx + TCP_header.SequenceNumber], [ebx + TCP_SOCKET.RCV_NXT]
; Uh-oh, some data is out of order, lets call TCP reassemble for help ; Uh-oh, some data is out of order, lets call TCP reassemble for help
call TCP_reassemble 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 or [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
.data_done: .data_done:
;--------------- ;---------------
@ -1517,7 +1538,7 @@ align 4
mov eax, ebx mov eax, ebx
call SOCKET_cant_recv_more 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] inc [ebx + TCP_SOCKET.RCV_NXT]
.not_first_fin: .not_first_fin:
@ -1539,29 +1560,54 @@ align 4
dd .fin_timed ; TCPS_TIMED_WAIT dd .fin_timed ; TCPS_TIMED_WAIT
.fin_syn_est: .fin_syn_est:
mov [ebx + TCP_SOCKET.t_state], TCPS_CLOSE_WAIT mov [ebx + TCP_SOCKET.t_state], TCPS_CLOSE_WAIT
jmp .final_processing jmp .final_processing
.fin_wait1: .fin_wait1:
mov [ebx + TCP_SOCKET.t_state], TCPS_CLOSING mov [ebx + TCP_SOCKET.t_state], TCPS_CLOSING
jmp .final_processing jmp .final_processing
.fin_wait2: .fin_wait2:
mov [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT mov [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT
mov eax, ebx mov eax, ebx
call TCP_cancel_timers 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 call SOCKET_is_disconnected
jmp .final_processing
.fin_timed: .fin_timed:
mov [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL mov [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL
or [ebx + TCP_SOCKET.timer_flags], timer_flag_wait 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: .drop_after_ack:
@ -1598,35 +1644,6 @@ align 4
jnz .respond_syn jnz .respond_syn
jmp .dumpit 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 ; Respond
@ -1687,7 +1704,7 @@ align 4
popa popa
.destroy_new_socket: .destroy_new_socket:
test [ebx + TCP_SOCKET.temp_bits], TCP_BIT_DROPSOCKET test [temp_bits], TCP_BIT_DROPSOCKET
jz .drop_no_socket jz .drop_no_socket
mov eax, ebx mov eax, ebx
@ -1697,5 +1714,6 @@ align 4
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Drop (no socket)\n" DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Drop (no socket)\n"
call NET_packet_free call NET_packet_free
add esp, 4
jmp .loop jmp .loop
endp

View File

@ -21,14 +21,17 @@ $Revision: 3289 $
; TCP_output ; TCP_output
; ;
; IN: eax = socket pointer ; IN: eax = socket pointer
; ; OUT: eax = 0 on success/errorcode
; OUT: /
; ;
;----------------------------------------------------------------- ;-----------------------------------------------------------------
align 4 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 push eax
lea ecx, [eax + SOCKET.mutex] lea ecx, [eax + SOCKET.mutex]
@ -57,7 +60,7 @@ TCP_output:
.not_idle: .not_idle:
.again: .again:
mov [eax + TCP_SOCKET.temp_bits], 0 mov [temp_bits], 0
mov ebx, [eax + TCP_SOCKET.SND_NXT] ; calculate offset (71) mov ebx, [eax + TCP_SOCKET.SND_NXT] ; calculate offset (71)
sub ebx, [eax + TCP_SOCKET.SND_UNA] ; sub ebx, [eax + TCP_SOCKET.SND_UNA] ;
@ -145,7 +148,7 @@ TCP_output:
jbe @f jbe @f
mov esi, [eax + TCP_SOCKET.t_maxseg] 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 jz .len_zero
cmp esi, [eax + TCP_SOCKET.t_maxseg] cmp esi, [eax + TCP_SOCKET.t_maxseg]
je TCP_send je .send
add ebx, esi ; offset + length add ebx, esi ; offset + length
cmp ebx, [eax + STREAM_SOCKET.snd.size] cmp ebx, [eax + STREAM_SOCKET.snd.size]
jb @f jb @f
test [eax + TCP_SOCKET.t_flags], TF_NODELAY test [eax + TCP_SOCKET.t_flags], TF_NODELAY
jnz TCP_send jnz .send
mov ebx, [eax + TCP_SOCKET.SND_MAX] mov ebx, [eax + TCP_SOCKET.SND_MAX]
cmp ebx, [eax + TCP_SOCKET.SND_UNA] cmp ebx, [eax + TCP_SOCKET.SND_UNA]
je TCP_send je .send
@@: @@:
test [eax + TCP_SOCKET.t_force], -1 ;;; test [eax + TCP_SOCKET.t_force], -1 ;;;
jnz TCP_send jnz .send
mov ebx, [eax + TCP_SOCKET.max_sndwnd] mov ebx, [eax + TCP_SOCKET.max_sndwnd]
shr ebx, 1 shr ebx, 1
cmp esi, ebx cmp esi, ebx
jae TCP_send jae .send
mov ebx, [eax + TCP_SOCKET.SND_NXT] mov ebx, [eax + TCP_SOCKET.SND_NXT]
cmp ebx, [eax + TCP_SOCKET.SND_MAX] cmp ebx, [eax + TCP_SOCKET.SND_MAX]
jb TCP_send jb .send
.len_zero: .len_zero:
@ -229,9 +232,10 @@ TCP_output:
mov edi, [eax + TCP_SOCKET.t_maxseg] mov edi, [eax + TCP_SOCKET.t_maxseg]
shl edi, 1 shl edi, 1
; cmp ebx, edi cmp ebx, edi
; jae TCP_send jae .send
shl ebx, 1
; cmp ebx, [eax + TCP_SOCKET.] ;;; TODO: check with receive buffer high water mark ; cmp ebx, [eax + TCP_SOCKET.] ;;; TODO: check with receive buffer high water mark
; jae TCP_send ; jae TCP_send
@ -240,17 +244,15 @@ TCP_output:
;-------------------------- ;--------------------------
; Should a segment be sent? (174) ; 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 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 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 mov ebx, [eax + TCP_SOCKET.SND_UP] ; when urgent pointer is beyond start of send bufer
cmp ebx, [eax + TCP_SOCKET.SND_UNA] cmp ebx, [eax + TCP_SOCKET.SND_UNA]
ja TCP_send ja .send
test dl, TH_FIN test dl, TH_FIN
jz .enter_persist ; no reason to send, enter persist state 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 ; FIN was set, only send if not already sent, or on retransmit
test [eax + TCP_SOCKET.t_flags], TF_SENTFIN test [eax + TCP_SOCKET.t_flags], TF_SENTFIN
jz TCP_send jz .send
mov ebx, [eax + TCP_SOCKET.SND_NXT] mov ebx, [eax + TCP_SOCKET.SND_NXT]
cmp ebx, [eax + TCP_SOCKET.SND_UNA] cmp ebx, [eax + TCP_SOCKET.SND_UNA]
je TCP_send je .send
;-------------------- ;--------------------
; Enter persist state (191) ; Enter persist state (191)
@ -298,13 +300,6 @@ TCP_output:
ret ret
;----------------------------------------------- ;-----------------------------------------------
; ;
; Send a segment (222) ; Send a segment (222)
@ -314,8 +309,7 @@ TCP_output:
; dl = flags ; dl = flags
; ;
;----------------------------------------------- ;-----------------------------------------------
align 4 .send:
TCP_send:
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_send: socket=%x length=%u flags=%x\n", eax, esi, dl 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 jbe .no_overflow
mov esi, [eax + TCP_SOCKET.t_maxseg] mov esi, [eax + TCP_SOCKET.t_maxseg]
or [eax + TCP_SOCKET.temp_bits], TCP_BIT_SENDALOT or [temp_bits], TCP_BIT_SENDALOT
.no_overflow: .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 ; Start by pushing all TCP header values in reverse order on stack
; (essentially, creating the tcp header on the stack!) ; (essentially, creating the tcp header on the stack!)
pushw 0 ; .UrgentPointer dw ? pushw 0 ; .UrgentPointer dw ?
pushw 0 ; .Checksum 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 edi, 2 ; .DataOffset db ? only 4 left-most bits
shl dx, 8 shl dx, 8
or dx, di ; .Flags db ? or dx, di ; .Flags db ?
@ -534,7 +560,13 @@ TCP_send:
;-------------------- ;--------------------
; Create the checksum ; 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) TCP_checksum (eax + IP_SOCKET.LocalIP), (eax + IP_SOCKET.RemoteIP)
.checksum_ok:
mov [esi + TCP_header.Checksum], dx mov [esi + TCP_header.Checksum], dx
;---------------- ;----------------
@ -566,7 +598,7 @@ TCP_send:
push [eax + TCP_SOCKET.RCV_NXT] push [eax + TCP_SOCKET.RCV_NXT]
pop [eax + TCP_SOCKET.last_ack_sent] pop [eax + TCP_SOCKET.last_ack_sent]
; and flags ; clear the ACK flags
and [eax + TCP_SOCKET.t_flags], not (TF_ACKNOW + TF_DELACK) and [eax + TCP_SOCKET.t_flags], not (TF_ACKNOW + TF_DELACK)
;-------------- ;--------------
@ -582,7 +614,7 @@ TCP_send:
;----------------------------- ;-----------------------------
; Check if we need more output ; 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 jnz TCP_output.again
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_send: success!\n" DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_send: success!\n"
@ -622,7 +654,4 @@ TCP_send:
ret ret
endp

View File

@ -152,7 +152,9 @@ TCP_drop:
mov [eax + TCP_SOCKET.t_state], TCPS_CLOSED mov [eax + TCP_SOCKET.t_state], TCPS_CLOSED
push eax
call TCP_output call TCP_output
pop eax
;;; TODO: update stats ;;; 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 ; TCP_close
; ;
; IN: eax = socket ptr ; IN: eax = socket ptr
; OUT: eax = socket ptr ; OUT: /
; ;
;------------------------- ;-------------------------
align 4 align 4
@ -190,7 +219,9 @@ TCP_close:
;;; TODO: update slow start threshold ;;; TODO: update slow start threshold
call SOCKET_is_disconnected call SOCKET_is_disconnected
;; call SOCKET_free call SOCKET_free
xor eax, eax
ret ret

View File

@ -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 ;; ;; Distributed under terms of the GNU General Public License ;;
;; ;; ;; ;;
;; Part of the TCP/IP network stack for KolibriOS ;; ;; Part of the TCP/IP network stack for KolibriOS ;;
@ -57,7 +57,6 @@ TCP_usrclosed:
.wait1: .wait1:
mov [eax + TCP_SOCKET.t_state], TCPS_FIN_WAIT_1 mov [eax + TCP_SOCKET.t_state], TCPS_FIN_WAIT_1
; TODO: set timer?
pop ebx pop ebx
ret ret
@ -68,7 +67,6 @@ TCP_usrclosed:
.disc: .disc:
call SOCKET_is_disconnected call SOCKET_is_disconnected
; TODO: set timer?
.ret: .ret:
pop ebx pop ebx
ret ret
@ -202,35 +200,4 @@ TCP_connect:
stdcall cancel_timer_hs, [eax + TCP_SOCKET.timer_connect] stdcall cancel_timer_hs, [eax + TCP_SOCKET.timer_connect]
xor eax, eax 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 ret

View File

@ -295,6 +295,8 @@ proc set_cursor stdcall, hcursor:dword
; jne .fail ; jne .fail
mov ebx, [current_slot] mov ebx, [current_slot]
xchg eax, [ebx+APPDATA.cursor] xchg eax, [ebx+APPDATA.cursor]
mov [redrawmouse_unconditional], 1
call __sys_draw_pointer
ret ret
;-------------------------------------- ;--------------------------------------
align 4 align 4

View File

@ -1952,7 +1952,6 @@ align 4
mov esi, bgr_next_line mov esi, bgr_next_line
mov edi, bgr_cur_line mov edi, bgr_cur_line
mov ecx, [_display.width] mov ecx, [_display.width]
inc ecx
rep movsd rep movsd
jmp bgr_resmooth1 jmp bgr_resmooth1
;-------------------------------------- ;--------------------------------------