forked from KolibriOS/kolibrios
kolibri-acpi:update
git-svn-id: svn://kolibrios.org@4423 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
parent
a461856fa1
commit
3ed9acd41a
293
kernel/branches/Kolibri-acpi/blkdev/bd_drv.inc
Normal file
293
kernel/branches/Kolibri-acpi/blkdev/bd_drv.inc
Normal file
@ -0,0 +1,293 @@
|
|||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;; ;;
|
||||||
|
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;;
|
||||||
|
;; Distributed under terms of the GNU General Public License ;;
|
||||||
|
;; ;;
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
$Revision: 4420 $
|
||||||
|
|
||||||
|
|
||||||
|
; Access through BIOS by diamond
|
||||||
|
iglobal
|
||||||
|
align 4
|
||||||
|
bd_callbacks:
|
||||||
|
dd bd_callbacks.end - bd_callbacks ; strucsize
|
||||||
|
dd 0 ; no close function
|
||||||
|
dd 0 ; no closemedia function
|
||||||
|
dd bd_querymedia
|
||||||
|
dd bd_read_interface
|
||||||
|
dd bd_write_interface
|
||||||
|
dd 0 ; no flush function
|
||||||
|
dd 0 ; use default cache size
|
||||||
|
.end:
|
||||||
|
endg
|
||||||
|
|
||||||
|
proc bd_read_interface stdcall uses edi, \
|
||||||
|
userdata, buffer, startsector:qword, numsectors
|
||||||
|
; userdata = old [hdpos] = 80h + index in NumBiosDisks
|
||||||
|
; buffer = pointer to buffer for data
|
||||||
|
; startsector = 64-bit start sector
|
||||||
|
; numsectors = pointer to number of sectors on input,
|
||||||
|
; must be filled with number of sectors really read
|
||||||
|
locals
|
||||||
|
sectors_todo dd ?
|
||||||
|
endl
|
||||||
|
; 1. Initialize number of sectors: get number of requested sectors
|
||||||
|
; and say that no sectors were read yet.
|
||||||
|
mov ecx, [numsectors]
|
||||||
|
mov eax, [ecx]
|
||||||
|
mov dword [ecx], 0
|
||||||
|
mov [sectors_todo], eax
|
||||||
|
; 2. Acquire the global lock.
|
||||||
|
mov ecx, ide_mutex
|
||||||
|
call mutex_lock
|
||||||
|
; 3. Convert parameters to the form suitable for worker procedures.
|
||||||
|
; Underlying procedures do not know about 64-bit sectors.
|
||||||
|
; Worker procedures use global variables and edi for [buffer].
|
||||||
|
cmp dword [startsector+4], 0
|
||||||
|
jnz .fail
|
||||||
|
and [hd_error], 0
|
||||||
|
mov eax, [userdata]
|
||||||
|
mov [hdpos], eax
|
||||||
|
mov eax, dword [startsector]
|
||||||
|
mov edi, [buffer]
|
||||||
|
; 4. Worker procedures take one sectors per time, so loop over all sectors to read.
|
||||||
|
.sectors_loop:
|
||||||
|
call bd_read
|
||||||
|
cmp [hd_error], 0
|
||||||
|
jnz .fail
|
||||||
|
mov ecx, [numsectors]
|
||||||
|
inc dword [ecx] ; one more sector is read
|
||||||
|
dec [sectors_todo]
|
||||||
|
jz .done
|
||||||
|
inc eax
|
||||||
|
jnz .sectors_loop
|
||||||
|
; 5. Loop is done, either due to error or because everything is done.
|
||||||
|
; Release the global lock and return the corresponding status.
|
||||||
|
.fail:
|
||||||
|
mov ecx, ide_mutex
|
||||||
|
call mutex_unlock
|
||||||
|
or eax, -1
|
||||||
|
ret
|
||||||
|
.done:
|
||||||
|
mov ecx, ide_mutex
|
||||||
|
call mutex_unlock
|
||||||
|
xor eax, eax
|
||||||
|
ret
|
||||||
|
endp
|
||||||
|
|
||||||
|
proc bd_write_interface stdcall uses esi edi, \
|
||||||
|
userdata, buffer, startsector:qword, numsectors
|
||||||
|
; userdata = old [hdpos] = 80h + index in NumBiosDisks
|
||||||
|
; buffer = pointer to buffer with data
|
||||||
|
; startsector = 64-bit start sector
|
||||||
|
; numsectors = pointer to number of sectors on input,
|
||||||
|
; must be filled with number of sectors really written
|
||||||
|
locals
|
||||||
|
sectors_todo dd ?
|
||||||
|
endl
|
||||||
|
; 1. Initialize number of sectors: get number of requested sectors
|
||||||
|
; and say that no sectors were read yet.
|
||||||
|
mov ecx, [numsectors]
|
||||||
|
mov eax, [ecx]
|
||||||
|
mov dword [ecx], 0
|
||||||
|
mov [sectors_todo], eax
|
||||||
|
; 2. Acquire the global lock.
|
||||||
|
mov ecx, ide_mutex
|
||||||
|
call mutex_lock
|
||||||
|
; 3. Convert parameters to the form suitable for worker procedures.
|
||||||
|
; Underlying procedures do not know about 64-bit sectors.
|
||||||
|
; Worker procedures use global variables and esi for [buffer].
|
||||||
|
cmp dword [startsector+4], 0
|
||||||
|
jnz .fail
|
||||||
|
and [hd_error], 0
|
||||||
|
mov eax, [userdata]
|
||||||
|
mov [hdpos], eax
|
||||||
|
mov esi, [buffer]
|
||||||
|
lea edi, [startsector]
|
||||||
|
mov [cache_chain_ptr], edi
|
||||||
|
; 4. Worker procedures take max 16 sectors per time,
|
||||||
|
; loop until all sectors will be processed.
|
||||||
|
.sectors_loop:
|
||||||
|
mov ecx, 16
|
||||||
|
cmp ecx, [sectors_todo]
|
||||||
|
jbe @f
|
||||||
|
mov ecx, [sectors_todo]
|
||||||
|
@@:
|
||||||
|
mov [cache_chain_size], cl
|
||||||
|
call bd_write_cache_chain
|
||||||
|
cmp [hd_error], 0
|
||||||
|
jnz .fail
|
||||||
|
movzx ecx, [cache_chain_size]
|
||||||
|
mov eax, [numsectors]
|
||||||
|
add [eax], ecx
|
||||||
|
sub [sectors_todo], ecx
|
||||||
|
jz .done
|
||||||
|
add [edi], ecx
|
||||||
|
jc .fail
|
||||||
|
shl ecx, 9
|
||||||
|
add esi, ecx
|
||||||
|
jmp .sectors_loop
|
||||||
|
; 5. Loop is done, either due to error or because everything is done.
|
||||||
|
; Release the global lock and return the corresponding status.
|
||||||
|
.fail:
|
||||||
|
mov ecx, ide_mutex
|
||||||
|
call mutex_unlock
|
||||||
|
or eax, -1
|
||||||
|
ret
|
||||||
|
.done:
|
||||||
|
mov ecx, ide_mutex
|
||||||
|
call mutex_unlock
|
||||||
|
xor eax, eax
|
||||||
|
ret
|
||||||
|
endp
|
||||||
|
|
||||||
|
; This is a stub.
|
||||||
|
proc bd_querymedia stdcall, hd_data, mediainfo
|
||||||
|
mov eax, [mediainfo]
|
||||||
|
mov [eax+DISKMEDIAINFO.Flags], 0
|
||||||
|
mov [eax+DISKMEDIAINFO.SectorSize], 512
|
||||||
|
or dword [eax+DISKMEDIAINFO.Capacity], 0xFFFFFFFF
|
||||||
|
or dword [eax+DISKMEDIAINFO.Capacity+4], 0xFFFFFFFF
|
||||||
|
xor eax, eax
|
||||||
|
ret
|
||||||
|
endp
|
||||||
|
|
||||||
|
;-----------------------------------------------------------------------------
|
||||||
|
; \begin{diamond}
|
||||||
|
uglobal
|
||||||
|
bios_hdpos dd 0 ; 0 is invalid value for [hdpos]
|
||||||
|
bios_cur_sector dd ?
|
||||||
|
bios_read_len dd ?
|
||||||
|
endg
|
||||||
|
;-----------------------------------------------------------------------------
|
||||||
|
align 4
|
||||||
|
bd_read:
|
||||||
|
push eax
|
||||||
|
push edx
|
||||||
|
mov edx, [bios_hdpos]
|
||||||
|
cmp edx, [hdpos]
|
||||||
|
jne .notread
|
||||||
|
mov edx, [bios_cur_sector]
|
||||||
|
cmp eax, edx
|
||||||
|
jb .notread
|
||||||
|
add edx, [bios_read_len]
|
||||||
|
dec edx
|
||||||
|
cmp eax, edx
|
||||||
|
ja .notread
|
||||||
|
sub eax, [bios_cur_sector]
|
||||||
|
shl eax, 9
|
||||||
|
add eax, (OS_BASE+0x9A000)
|
||||||
|
push ecx esi
|
||||||
|
mov esi, eax
|
||||||
|
mov ecx, 512/4
|
||||||
|
cld
|
||||||
|
rep movsd
|
||||||
|
pop esi ecx
|
||||||
|
pop edx
|
||||||
|
pop eax
|
||||||
|
ret
|
||||||
|
.notread:
|
||||||
|
push ecx
|
||||||
|
mov dl, 42h
|
||||||
|
mov ecx, 16
|
||||||
|
call int13_call
|
||||||
|
pop ecx
|
||||||
|
test eax, eax
|
||||||
|
jnz .v86err
|
||||||
|
test edx, edx
|
||||||
|
jz .readerr
|
||||||
|
mov [bios_read_len], edx
|
||||||
|
mov edx, [hdpos]
|
||||||
|
mov [bios_hdpos], edx
|
||||||
|
pop edx
|
||||||
|
pop eax
|
||||||
|
mov [bios_cur_sector], eax
|
||||||
|
jmp bd_read
|
||||||
|
.readerr:
|
||||||
|
.v86err:
|
||||||
|
mov [hd_error], 1
|
||||||
|
jmp hd_read_error
|
||||||
|
;-----------------------------------------------------------------------------
|
||||||
|
align 4
|
||||||
|
bd_write_cache_chain:
|
||||||
|
pusha
|
||||||
|
mov edi, OS_BASE + 0x9A000
|
||||||
|
movzx ecx, [cache_chain_size]
|
||||||
|
push ecx
|
||||||
|
shl ecx, 9-2
|
||||||
|
rep movsd
|
||||||
|
pop ecx
|
||||||
|
mov dl, 43h
|
||||||
|
mov eax, [cache_chain_ptr]
|
||||||
|
mov eax, [eax]
|
||||||
|
call int13_call
|
||||||
|
test eax, eax
|
||||||
|
jnz .v86err
|
||||||
|
cmp edx, ecx
|
||||||
|
jnz .writeerr
|
||||||
|
popa
|
||||||
|
ret
|
||||||
|
.v86err:
|
||||||
|
.writeerr:
|
||||||
|
popa
|
||||||
|
mov [hd_error], 1
|
||||||
|
jmp hd_write_error
|
||||||
|
;-----------------------------------------------------------------------------
|
||||||
|
uglobal
|
||||||
|
int13_regs_in rb sizeof.v86_regs
|
||||||
|
int13_regs_out rb sizeof.v86_regs
|
||||||
|
endg
|
||||||
|
;-----------------------------------------------------------------------------
|
||||||
|
align 4
|
||||||
|
int13_call:
|
||||||
|
; Because this code uses fixed addresses,
|
||||||
|
; it can not be run simultaniously by many threads.
|
||||||
|
; In current implementation it is protected by common mutex 'ide_status'
|
||||||
|
mov word [OS_BASE + 510h], 10h ; packet length
|
||||||
|
mov word [OS_BASE + 512h], cx ; number of sectors
|
||||||
|
mov dword [OS_BASE + 514h], 9A000000h ; buffer 9A00:0000
|
||||||
|
mov dword [OS_BASE + 518h], eax
|
||||||
|
and dword [OS_BASE + 51Ch], 0
|
||||||
|
push ebx ecx esi edi
|
||||||
|
mov ebx, int13_regs_in
|
||||||
|
mov edi, ebx
|
||||||
|
mov ecx, sizeof.v86_regs/4
|
||||||
|
xor eax, eax
|
||||||
|
rep stosd
|
||||||
|
mov byte [ebx+v86_regs.eax+1], dl
|
||||||
|
mov eax, [hdpos]
|
||||||
|
lea eax, [BiosDisksData+(eax-80h)*4]
|
||||||
|
mov dl, [eax]
|
||||||
|
mov byte [ebx+v86_regs.edx], dl
|
||||||
|
movzx edx, byte [eax+1]
|
||||||
|
; mov dl, 5
|
||||||
|
test edx, edx
|
||||||
|
jnz .hasirq
|
||||||
|
dec edx
|
||||||
|
jmp @f
|
||||||
|
.hasirq:
|
||||||
|
pushad
|
||||||
|
stdcall enable_irq, edx
|
||||||
|
popad
|
||||||
|
@@:
|
||||||
|
mov word [ebx+v86_regs.esi], 510h
|
||||||
|
mov word [ebx+v86_regs.ss], 9000h
|
||||||
|
mov word [ebx+v86_regs.esp], 0A000h
|
||||||
|
mov word [ebx+v86_regs.eip], 500h
|
||||||
|
mov [ebx+v86_regs.eflags], 20200h
|
||||||
|
mov esi, [sys_v86_machine]
|
||||||
|
mov ecx, 0x502
|
||||||
|
push fs
|
||||||
|
call v86_start
|
||||||
|
pop fs
|
||||||
|
and [bios_hdpos], 0
|
||||||
|
pop edi esi ecx ebx
|
||||||
|
movzx edx, byte [OS_BASE + 512h]
|
||||||
|
test byte [int13_regs_out+v86_regs.eflags], 1
|
||||||
|
jnz @f
|
||||||
|
mov edx, ecx
|
||||||
|
@@:
|
||||||
|
ret
|
||||||
|
; \end{diamond}
|
@ -10,7 +10,6 @@ $Revision$
|
|||||||
|
|
||||||
; Low-level driver for HDD access
|
; 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}
|
|
||||||
|
@ -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
|
||||||
|
446
kernel/branches/Kolibri-acpi/bus/usb/common.inc
Normal file
446
kernel/branches/Kolibri-acpi/bus/usb/common.inc
Normal file
@ -0,0 +1,446 @@
|
|||||||
|
; Constants and structures that are shared between different parts of
|
||||||
|
; USB subsystem and *HCI drivers.
|
||||||
|
|
||||||
|
; =============================================================================
|
||||||
|
; ================================= Constants =================================
|
||||||
|
; =============================================================================
|
||||||
|
; Version of all structures related to host controllers.
|
||||||
|
; Must be the same in kernel and *hci-drivers.
|
||||||
|
USBHC_VERSION = 1
|
||||||
|
|
||||||
|
; USB device must have at least 100ms of stable power before initializing can
|
||||||
|
; proceed; one timer tick is 10ms, so enforce delay in 10 ticks
|
||||||
|
USB_CONNECT_DELAY = 10
|
||||||
|
; USB requires at least 10 ms for reset signalling. Normally, this is one timer
|
||||||
|
; tick. However, it is possible that we start reset signalling in the end of
|
||||||
|
; interval between timer ticks and then we test time in the start of the next
|
||||||
|
; interval; in this case, the delta between [timer_ticks] is 1, but the real
|
||||||
|
; time passed is significantly less than 10 ms. To avoid this, we add an extra
|
||||||
|
; tick; this guarantees that at least 10 ms have passed.
|
||||||
|
USB_RESET_TIME = 2
|
||||||
|
; USB requires at least 10 ms of reset recovery, a delay between reset
|
||||||
|
; signalling and any commands to device. Add an extra tick for the same reasons
|
||||||
|
; as with the previous constant.
|
||||||
|
USB_RESET_RECOVERY_TIME = 2
|
||||||
|
|
||||||
|
; USB pipe types
|
||||||
|
CONTROL_PIPE = 0
|
||||||
|
ISOCHRONOUS_PIPE = 1
|
||||||
|
BULK_PIPE = 2
|
||||||
|
INTERRUPT_PIPE = 3
|
||||||
|
|
||||||
|
; Status codes for transfer callbacks.
|
||||||
|
; Taken from OHCI as most verbose controller in this sense.
|
||||||
|
USB_STATUS_OK = 0 ; no error
|
||||||
|
USB_STATUS_CRC = 1 ; CRC error
|
||||||
|
USB_STATUS_BITSTUFF = 2 ; bit stuffing violation
|
||||||
|
USB_STATUS_TOGGLE = 3 ; data toggle mismatch
|
||||||
|
USB_STATUS_STALL = 4 ; device returned STALL
|
||||||
|
USB_STATUS_NORESPONSE = 5 ; device not responding
|
||||||
|
USB_STATUS_PIDCHECK = 6 ; invalid PID check bits
|
||||||
|
USB_STATUS_WRONGPID = 7 ; unexpected PID value
|
||||||
|
USB_STATUS_OVERRUN = 8 ; too many data from endpoint
|
||||||
|
USB_STATUS_UNDERRUN = 9 ; too few data from endpoint
|
||||||
|
USB_STATUS_BUFOVERRUN = 12 ; overflow of internal controller buffer
|
||||||
|
USB_STATUS_BUFUNDERRUN = 13 ; underflow of internal controller buffer
|
||||||
|
USB_STATUS_CLOSED = 16 ; pipe closed
|
||||||
|
; either explicitly with USBClosePipe
|
||||||
|
; or implicitly due to device disconnect
|
||||||
|
|
||||||
|
; Possible speeds of USB devices
|
||||||
|
USB_SPEED_FS = 0 ; full-speed
|
||||||
|
USB_SPEED_LS = 1 ; low-speed
|
||||||
|
USB_SPEED_HS = 2 ; high-speed
|
||||||
|
|
||||||
|
; flags for usb_pipe.Flags
|
||||||
|
USB_FLAG_CLOSED = 1 ; pipe is closed, no new transfers
|
||||||
|
; pipe is closed, return error instead of submitting any new transfer
|
||||||
|
USB_FLAG_CAN_FREE = 2
|
||||||
|
; pipe is closed via explicit call to USBClosePipe, so it can be freed without
|
||||||
|
; any driver notification; if this flag is not set, then the pipe is closed due
|
||||||
|
; to device disconnect, so it must remain valid until return from disconnect
|
||||||
|
; callback provided by the driver
|
||||||
|
USB_FLAG_EXTRA_WAIT = 4
|
||||||
|
; The pipe was in wait list, while another event occured;
|
||||||
|
; when the first wait will be done, reinsert the pipe to wait list
|
||||||
|
USB_FLAG_CLOSED_BIT = 0 ; USB_FLAG_CLOSED = 1 shl USB_FLAG_CLOSED_BIT
|
||||||
|
|
||||||
|
; =============================================================================
|
||||||
|
; ================================ Structures =================================
|
||||||
|
; =============================================================================
|
||||||
|
|
||||||
|
; Description of controller-specific data and functions.
|
||||||
|
struct usb_hardware_func
|
||||||
|
Version dd ? ; must be USBHC_VERSION
|
||||||
|
ID dd ? ; '*HCI'
|
||||||
|
DataSize dd ? ; sizeof(*hci_controller)
|
||||||
|
BeforeInit dd ?
|
||||||
|
; Early initialization: take ownership from BIOS.
|
||||||
|
; in: [ebp-4] = (bus shl 8) + devfn
|
||||||
|
Init dd ?
|
||||||
|
; Initialize controller-specific part of controller data.
|
||||||
|
; in: eax -> *hci_controller to initialize, [ebp-4] = (bus shl 8) + devfn
|
||||||
|
; out: eax = 0 <=> failed, otherwise eax -> usb_controller
|
||||||
|
ProcessDeferred dd ?
|
||||||
|
; Called regularly from the main loop of USB thread
|
||||||
|
; (either due to timeout from a previous call, or due to explicit wakeup).
|
||||||
|
; in: esi -> usb_controller
|
||||||
|
; out: eax = maximum timeout for next call (-1 = infinity)
|
||||||
|
SetDeviceAddress dd ?
|
||||||
|
; in: esi -> usb_controller, ebx -> usb_pipe, cl = address
|
||||||
|
GetDeviceAddress dd ?
|
||||||
|
; in: esi -> usb_controller, ebx -> usb_pipe
|
||||||
|
; out: eax = address
|
||||||
|
PortDisable dd ?
|
||||||
|
; Disable the given port in the root hub.
|
||||||
|
; in: esi -> usb_controller, ecx = port (zero-based)
|
||||||
|
InitiateReset dd ?
|
||||||
|
; Start reset signalling on the given port.
|
||||||
|
; in: esi -> usb_controller, ecx = port (zero-based)
|
||||||
|
SetEndpointPacketSize dd ?
|
||||||
|
; in: esi -> usb_controller, ebx -> usb_pipe, ecx = packet size
|
||||||
|
AllocPipe dd ?
|
||||||
|
; out: eax = pointer to allocated usb_pipe
|
||||||
|
FreePipe dd ?
|
||||||
|
; void stdcall with one argument = pointer to previously allocated usb_pipe
|
||||||
|
InitPipe dd ?
|
||||||
|
; in: edi -> usb_pipe for target, ecx -> usb_pipe for config pipe,
|
||||||
|
; esi -> usb_controller, eax -> usb_gtd for the first TD,
|
||||||
|
; [ebp+12] = endpoint, [ebp+16] = maxpacket, [ebp+20] = type
|
||||||
|
UnlinkPipe dd ?
|
||||||
|
; esi -> usb_controller, ebx -> usb_pipe
|
||||||
|
AllocTD dd ?
|
||||||
|
; out: eax = pointer to allocated usb_gtd
|
||||||
|
FreeTD dd ?
|
||||||
|
; void stdcall with one argument = pointer to previously allocated usb_gtd
|
||||||
|
AllocTransfer dd ?
|
||||||
|
; Allocate and initialize one stage of a transfer.
|
||||||
|
; ebx -> usb_pipe, other parameters are passed through the stack:
|
||||||
|
; buffer,size = data to transfer
|
||||||
|
; flags = same as in usb_open_pipe:
|
||||||
|
; bit 0 = allow short transfer, other bits reserved
|
||||||
|
; td = pointer to the current end-of-queue descriptor
|
||||||
|
; direction =
|
||||||
|
; 0000b for normal transfers,
|
||||||
|
; 1000b for control SETUP transfer,
|
||||||
|
; 1101b for control OUT transfer,
|
||||||
|
; 1110b for control IN transfer
|
||||||
|
; returns eax = pointer to the new end-of-queue descriptor
|
||||||
|
; (not included in the queue itself) or 0 on error
|
||||||
|
InsertTransfer dd ?
|
||||||
|
; Activate previously initialized transfer (maybe with multiple stages).
|
||||||
|
; esi -> usb_controller, ebx -> usb_pipe,
|
||||||
|
; [esp+4] -> first usb_gtd for the transfer,
|
||||||
|
; ecx -> last descriptor for the transfer
|
||||||
|
NewDevice dd ?
|
||||||
|
; Initiate configuration of a new device (create pseudo-pipe describing that
|
||||||
|
; device and call usb_new_device).
|
||||||
|
; esi -> usb_controller, eax = speed (one of USB_SPEED_* constants).
|
||||||
|
ends
|
||||||
|
|
||||||
|
; pointers to kernel API functions that are called from *HCI-drivers
|
||||||
|
struct usbhc_func
|
||||||
|
usb_process_gtd dd ?
|
||||||
|
usb_init_static_endpoint dd ?
|
||||||
|
usb_wakeup_if_needed dd ?
|
||||||
|
usb_subscribe_control dd ?
|
||||||
|
usb_subscription_done dd ?
|
||||||
|
usb_allocate_common dd ?
|
||||||
|
usb_free_common dd ?
|
||||||
|
usb_td_to_virt dd ?
|
||||||
|
usb_init_transfer dd ?
|
||||||
|
usb_undo_tds dd ?
|
||||||
|
usb_test_pending_port dd ?
|
||||||
|
usb_get_tt dd ?
|
||||||
|
usb_get_tt_think_time dd ?
|
||||||
|
usb_new_device dd ?
|
||||||
|
usb_disconnect_stage2 dd ?
|
||||||
|
usb_process_wait_lists dd ?
|
||||||
|
usb_unlink_td dd ?
|
||||||
|
usb_is_final_packet dd ?
|
||||||
|
usb_find_ehci_companion dd ?
|
||||||
|
ends
|
||||||
|
|
||||||
|
; Controller descriptor.
|
||||||
|
; This structure represents the common (controller-independent) part
|
||||||
|
; of a controller for the USB code. The corresponding controller-dependent
|
||||||
|
; part *hci_controller is located immediately before usb_controller.
|
||||||
|
struct usb_controller
|
||||||
|
; Two following fields organize all controllers in the global linked list.
|
||||||
|
Next dd ?
|
||||||
|
Prev dd ?
|
||||||
|
HardwareFunc dd ?
|
||||||
|
; Pointer to usb_hardware_func structure with controller-specific functions.
|
||||||
|
NumPorts dd ?
|
||||||
|
; Number of ports in the root hub.
|
||||||
|
PCICoordinates dd ?
|
||||||
|
; Device:function and bus number from PCI.
|
||||||
|
;
|
||||||
|
; The hardware is allowed to cache some data from hardware structures.
|
||||||
|
; Regular operations are designed considering this,
|
||||||
|
; but sometimes it is required to wait for synchronization of hardware cache
|
||||||
|
; with modified structures in memory.
|
||||||
|
; The code keeps two queues of pipes waiting for synchronization,
|
||||||
|
; one for asynchronous (bulk/control) pipes, one for periodic pipes, hardware
|
||||||
|
; cache is invalidated under different conditions for those types.
|
||||||
|
; Both queues are organized in the same way, as single-linked lists.
|
||||||
|
; There are three special positions: the head of list (new pipes are added
|
||||||
|
; here), the first pipe to be synchronized at the current iteration,
|
||||||
|
; the tail of list (all pipes starting from here are synchronized).
|
||||||
|
WaitPipeListAsync dd ?
|
||||||
|
WaitPipeListPeriodic dd ?
|
||||||
|
; List heads.
|
||||||
|
WaitPipeRequestAsync dd ?
|
||||||
|
WaitPipeRequestPeriodic dd ?
|
||||||
|
; Pending request to hardware to refresh cache for items from WaitPipeList*.
|
||||||
|
; (Pointers to some items in WaitPipeList* or NULLs).
|
||||||
|
ReadyPipeHeadAsync dd ?
|
||||||
|
ReadyPipeHeadPeriodic dd ?
|
||||||
|
; Items of RemovingList* which were released by hardware and are ready
|
||||||
|
; for further processing.
|
||||||
|
; (Pointers to some items in WaitPipeList* or NULLs).
|
||||||
|
NewConnected dd ?
|
||||||
|
; bit mask of recently connected ports of the root hub,
|
||||||
|
; bit set = a device was recently connected to the corresponding port;
|
||||||
|
; after USB_CONNECT_DELAY ticks of stable status these ports are moved to
|
||||||
|
; PendingPorts
|
||||||
|
NewDisconnected dd ?
|
||||||
|
; bit mask of disconnected ports of the root hub,
|
||||||
|
; bit set = a device in the corresponding port was disconnected,
|
||||||
|
; disconnect processing is required.
|
||||||
|
PendingPorts dd ?
|
||||||
|
; bit mask of ports which are ready to be initialized
|
||||||
|
ControlLock MUTEX ?
|
||||||
|
; mutex which guards all operations with control queue
|
||||||
|
BulkLock MUTEX ?
|
||||||
|
; mutex which guards all operations with bulk queue
|
||||||
|
PeriodicLock MUTEX ?
|
||||||
|
; mutex which guards all operations with periodic queues
|
||||||
|
WaitSpinlock:
|
||||||
|
; spinlock guarding WaitPipeRequest/ReadyPipeHead (but not WaitPipeList)
|
||||||
|
StartWaitFrame dd ?
|
||||||
|
; USB frame number when WaitPipeRequest* was registered.
|
||||||
|
ResettingHub dd ?
|
||||||
|
; Pointer to usb_hub responsible for the currently resetting port, if any.
|
||||||
|
; NULL for the root hub.
|
||||||
|
ResettingPort db ?
|
||||||
|
; Port that is currently resetting, 0-based.
|
||||||
|
ResettingSpeed db ?
|
||||||
|
; Speed of currently resetting device.
|
||||||
|
ResettingStatus db ?
|
||||||
|
; Status of port reset. 0 = no port is resetting, -1 = reset failed,
|
||||||
|
; 1 = reset in progress, 2 = reset recovery in progress.
|
||||||
|
rb 1 ; alignment
|
||||||
|
ResetTime dd ?
|
||||||
|
; Time when reset signalling or reset recovery has been started.
|
||||||
|
SetAddressBuffer rb 8
|
||||||
|
; Buffer for USB control command SET_ADDRESS.
|
||||||
|
ExistingAddresses rd 128/32
|
||||||
|
; Bitmask for 128 bits; bit i is cleared <=> address i is free for allocating
|
||||||
|
; for new devices. Bit 0 is always set.
|
||||||
|
ConnectedTime rd 16
|
||||||
|
; Time, in timer ticks, when the port i has signalled the connect event.
|
||||||
|
; Valid only if bit i in NewConnected is set.
|
||||||
|
DevicesByPort rd 16
|
||||||
|
; Pointer to usb_pipe for zero endpoint (which serves as device handle)
|
||||||
|
; for each port.
|
||||||
|
ends
|
||||||
|
|
||||||
|
; Pipe descriptor.
|
||||||
|
; * An USB pipe is described by two structures, for hardware and for software.
|
||||||
|
; * This is the software part. The hardware part is defined in a driver
|
||||||
|
; of the corresponding controller.
|
||||||
|
; * The hardware part is located immediately before usb_pipe,
|
||||||
|
; both are allocated at once by controller-specific code
|
||||||
|
; (it knows the total length, which depends on the hardware part).
|
||||||
|
struct usb_pipe
|
||||||
|
Controller dd ?
|
||||||
|
; Pointer to usb_controller structure corresponding to this pipe.
|
||||||
|
; Must be the first dword after hardware part, see *hci_new_device.
|
||||||
|
;
|
||||||
|
; Every endpoint is included into one of processing lists:
|
||||||
|
; * Bulk list contains all Bulk endpoints.
|
||||||
|
; * Control list contains all Control endpoints.
|
||||||
|
; * Several Periodic lists serve Interrupt endpoints with different interval.
|
||||||
|
; - There are N=2^n "leaf" periodic lists for N ms interval, one is processed
|
||||||
|
; in the frames 0,N,2N,..., another is processed in the frames
|
||||||
|
; 1,1+N,1+2N,... and so on. The hardware starts processing of periodic
|
||||||
|
; endpoints in every frame from the list identified by lower n bits of the
|
||||||
|
; frame number; the addresses of these N lists are written to the
|
||||||
|
; controller data area during the initialization.
|
||||||
|
; - We assume that n=5, N=32 to simplify the code and compact the data.
|
||||||
|
; OHCI works in this way. UHCI and EHCI actually have n=10, N=1024,
|
||||||
|
; but this is an overkill for interrupt endpoints; the large value of N is
|
||||||
|
; useful only for isochronous transfers in UHCI and EHCI. UHCI/EHCI code
|
||||||
|
; initializes "leaf" lists k,k+32,k+64,...,k+(1024-32) to the same value,
|
||||||
|
; giving essentially N=32.
|
||||||
|
; This restriction means that the actual maximum interval of polling any
|
||||||
|
; interrupt endpoint is 32ms, which seems to be a reasonable value.
|
||||||
|
; - Similarly, there are 16 lists for 16-ms interval, 8 lists for 8-ms
|
||||||
|
; interval and so on. Finally, there is one list for 1ms interval. Their
|
||||||
|
; addresses are not directly known to the controller.
|
||||||
|
; - The hardware serves endpoints following a physical link from the hardware
|
||||||
|
; part.
|
||||||
|
; - The hardware links are organized as follows. If the list item is not the
|
||||||
|
; last, it's hardware link points to the next item. The hardware link of
|
||||||
|
; the last item points to the first item of the "next" list.
|
||||||
|
; - The "next" list for k-th and (k+M)-th periodic lists for interval 2M ms
|
||||||
|
; is the k-th periodic list for interval M ms, M >= 1. In this scheme,
|
||||||
|
; if two "previous" lists are served in the frames k,k+2M,k+4M,...
|
||||||
|
; and k+M,k+3M,k+5M,... correspondingly, the "next" list is served in
|
||||||
|
; the frames k,k+M,k+2M,k+3M,k+4M,k+5M,..., which is exactly what we want.
|
||||||
|
; - The links between Periodic, Control, Bulk lists and the processing of
|
||||||
|
; Isochronous endpoints are controller-specific.
|
||||||
|
; * The head of every processing list is a static entry which does not
|
||||||
|
; correspond to any real pipe. It is described by usb_static_ep
|
||||||
|
; structure, not usb_pipe. For OHCI and UHCI, sizeof.usb_static_ep plus
|
||||||
|
; sizeof hardware part is 20h, the total number of lists is
|
||||||
|
; 32+16+8+4+2+1+1+1 = 65, so all these structures fit in one page,
|
||||||
|
; leaving space for other data. This is another reason for 32ms limit.
|
||||||
|
; * Static endpoint descriptors are kept in *hci_controller structure.
|
||||||
|
; * All items in every processing list, including the static head, are
|
||||||
|
; organized in a double-linked list using .NextVirt and .PrevVirt fields.
|
||||||
|
; * [[item.NextVirt].PrevVirt] = [[item.PrevVirt].NextVirt] for all items.
|
||||||
|
NextVirt dd ?
|
||||||
|
; Next endpoint in the processing list.
|
||||||
|
; See also PrevVirt field and the description before NextVirt field.
|
||||||
|
PrevVirt dd ?
|
||||||
|
; Previous endpoint in the processing list.
|
||||||
|
; See also NextVirt field and the description before NextVirt field.
|
||||||
|
;
|
||||||
|
; Every pipe has the associated transfer queue, that is, the double-linked
|
||||||
|
; list of Transfer Descriptors aka TD. For Control, Bulk and Interrupt
|
||||||
|
; endpoints this list consists of usb_gtd structures
|
||||||
|
; (GTD = General Transfer Descriptors), for Isochronous endpoints
|
||||||
|
; this list consists of usb_itd structures, which are not developed yet.
|
||||||
|
; The pipe needs to know only the last TD; the first TD can be
|
||||||
|
; obtained as [[pipe.LastTD].NextVirt].
|
||||||
|
LastTD dd ?
|
||||||
|
; Last TD in the transfer queue.
|
||||||
|
;
|
||||||
|
; All opened pipes corresponding to the same physical device are organized in
|
||||||
|
; the double-linked list using .NextSibling and .PrevSibling fields.
|
||||||
|
; The head of this list is kept in usb_device_data structure (OpenedPipeList).
|
||||||
|
; This list is used when the device is disconnected and all pipes for the
|
||||||
|
; device should be closed.
|
||||||
|
; Also, all pipes closed due to disconnect must remain valid at least until
|
||||||
|
; driver-provided disconnect function returns; all should-be-freed-but-not-now
|
||||||
|
; pipes for one device are organized in another double-linked list with
|
||||||
|
; the head in usb_device_data.ClosedPipeList; this list uses the same link
|
||||||
|
; fields, one pipe can never be in both lists.
|
||||||
|
NextSibling dd ?
|
||||||
|
; Next pipe for the physical device.
|
||||||
|
PrevSibling dd ?
|
||||||
|
; Previous pipe for the physical device.
|
||||||
|
;
|
||||||
|
; When hardware part of pipe is changed, some time is needed before further
|
||||||
|
; actions so that hardware reacts on this change. During that time,
|
||||||
|
; all changed pipes are organized in single-linked list with the head
|
||||||
|
; usb_controller.WaitPipeList* and link field NextWait.
|
||||||
|
; Currently there are two possible reasons to change:
|
||||||
|
; change of address/packet size in initial configuration,
|
||||||
|
; close of the pipe. They are distinguished by USB_FLAG_CLOSED.
|
||||||
|
NextWait dd ?
|
||||||
|
Lock MUTEX
|
||||||
|
; Mutex that guards operations with transfer queue for this pipe.
|
||||||
|
Type db ?
|
||||||
|
; Type of pipe, one of {CONTROL,ISOCHRONOUS,BULK,INTERRUPT}_PIPE.
|
||||||
|
Flags db ?
|
||||||
|
; Combination of flags, USB_FLAG_*.
|
||||||
|
rb 2 ; dword alignment
|
||||||
|
DeviceData dd ?
|
||||||
|
; Pointer to usb_device_data, common for all pipes for one device.
|
||||||
|
ends
|
||||||
|
|
||||||
|
; This structure describes the static head of every list of pipes.
|
||||||
|
struct usb_static_ep
|
||||||
|
; software fields
|
||||||
|
Bandwidth dd ?
|
||||||
|
; valid only for interrupt/isochronous USB1 lists
|
||||||
|
; The offsets of the following two fields must be the same in this structure
|
||||||
|
; and in usb_pipe.
|
||||||
|
NextVirt dd ?
|
||||||
|
PrevVirt dd ?
|
||||||
|
ends
|
||||||
|
|
||||||
|
; This structure represents one transfer descriptor
|
||||||
|
; ('g' stands for "general" as opposed to isochronous usb_itd).
|
||||||
|
; Note that one transfer can have several descriptors:
|
||||||
|
; a control transfer has three stages.
|
||||||
|
; Additionally, every controller has a limit on transfer length with
|
||||||
|
; one descriptor (packet size for UHCI, 1K for OHCI, 4K for EHCI),
|
||||||
|
; large transfers must be split into individual packets according to that limit.
|
||||||
|
struct usb_gtd
|
||||||
|
Callback dd ?
|
||||||
|
; Zero for intermediate descriptors, pointer to callback function
|
||||||
|
; for final descriptor. See the docs for description of the callback.
|
||||||
|
UserData dd ?
|
||||||
|
; Dword which is passed to Callback as is, not used by USB code itself.
|
||||||
|
; Two following fields organize all descriptors for one pipe in
|
||||||
|
; the linked list.
|
||||||
|
NextVirt dd ?
|
||||||
|
PrevVirt dd ?
|
||||||
|
Pipe dd ?
|
||||||
|
; Pointer to the parent usb_pipe.
|
||||||
|
Buffer dd ?
|
||||||
|
; Pointer to data for this descriptor.
|
||||||
|
Length dd ?
|
||||||
|
; Length of data for this descriptor.
|
||||||
|
ends
|
||||||
|
|
||||||
|
; Interface-specific data. Several interfaces of one device can operate
|
||||||
|
; independently, each is controlled by some driver and is identified by
|
||||||
|
; some driver-specific data passed as is to the driver.
|
||||||
|
struct usb_interface_data
|
||||||
|
DriverData dd ?
|
||||||
|
; Passed as is to the driver.
|
||||||
|
DriverFunc dd ?
|
||||||
|
; Pointer to USBSRV structure for the driver.
|
||||||
|
ends
|
||||||
|
|
||||||
|
; Device-specific data.
|
||||||
|
struct usb_device_data
|
||||||
|
PipeListLock MUTEX
|
||||||
|
; Lock guarding OpenedPipeList. Must be the first item of the structure,
|
||||||
|
; the code passes pointer to usb_device_data as is to mutex_lock/unlock.
|
||||||
|
OpenedPipeList rd 2
|
||||||
|
; List of all opened pipes for the device.
|
||||||
|
; Used when the device is disconnected, so all pipes should be closed.
|
||||||
|
ClosedPipeList rd 2
|
||||||
|
; List of all closed, but still valid pipes for the device.
|
||||||
|
; A pipe closed with USBClosePipe is just deallocated,
|
||||||
|
; but a pipe closed due to disconnect must remain valid until driver-provided
|
||||||
|
; disconnect handler returns; this list links all such pipes to deallocate them
|
||||||
|
; after disconnect processing.
|
||||||
|
NumPipes dd ?
|
||||||
|
; Number of not-yet-closed pipes.
|
||||||
|
Hub dd ?
|
||||||
|
; NULL if connected to the root hub, pointer to usb_hub otherwise.
|
||||||
|
TTHub dd ?
|
||||||
|
; Pointer to usb_hub for (the) hub with Transaction Translator for the device,
|
||||||
|
; NULL if the device operates in the same speed as the controller.
|
||||||
|
Port db ?
|
||||||
|
; Port on the hub, zero-based.
|
||||||
|
TTPort db ?
|
||||||
|
; Port on the TTHub, zero-based.
|
||||||
|
DeviceDescrSize db ?
|
||||||
|
; Size of device descriptor.
|
||||||
|
Speed db ?
|
||||||
|
; Device speed, one of USB_SPEED_*.
|
||||||
|
NumInterfaces dd ?
|
||||||
|
; Number of interfaces.
|
||||||
|
ConfigDataSize dd ?
|
||||||
|
; Total size of data associated with the configuration descriptor
|
||||||
|
; (including the configuration descriptor itself).
|
||||||
|
Interfaces dd ?
|
||||||
|
; Offset from the beginning of this structure to Interfaces field.
|
||||||
|
; Variable-length fields:
|
||||||
|
; DeviceDescriptor:
|
||||||
|
; device descriptor starts here
|
||||||
|
; ConfigDescriptor = DeviceDescriptor + DeviceDescrSize
|
||||||
|
; configuration descriptor with all associated data
|
||||||
|
; Interfaces = ALIGN_UP(ConfigDescriptor + ConfigDataSize, 4)
|
||||||
|
; array of NumInterfaces elements of type usb_interface_data
|
||||||
|
ends
|
||||||
|
|
||||||
|
usb_device_data.DeviceDescriptor = sizeof.usb_device_data
|
File diff suppressed because it is too large
Load Diff
@ -1,238 +1,33 @@
|
|||||||
; USB Host Controller support code: hardware-independent part,
|
; 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
|
||||||
|
@ -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
|
||||||
|
@ -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"
|
|
||||||
|
@ -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
@ -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
|
||||||
|
@ -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
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -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', \
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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:
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
|
||||||
|
|
||||||
|
|
||||||
;-----------------------------------------------------------------
|
;-----------------------------------------------------------------
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
;-----------------------------------------------------------------
|
;-----------------------------------------------------------------
|
||||||
;
|
;
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
@ -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
|
||||||
|
@ -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
|
||||||
;--------------------------------------
|
;--------------------------------------
|
||||||
|
Loading…
Reference in New Issue
Block a user