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