/kernel/branches/Kolibri-acpi/blkdev/cd_drv.inc |
---|
1132,21 → 1132,22 |
mov [ignore_CD_eject_wait], 0 |
ret |
;----------------------------------------------------------------------------- |
iglobal |
timer_ATAPI_check dd 0 |
ATAPI_IDE0_lock db 0 |
ATAPI_IDE1_lock db 0 |
ATAPI_IDE2_lock db 0 |
ATAPI_IDE3_lock db 0 |
ATAPI_IDE4_lock db 0 |
ATAPI_IDE5_lock db 0 |
ATAPI_IDE6_lock db 0 |
ATAPI_IDE7_lock db 0 |
ATAPI_IDE8_lock db 0 |
ATAPI_IDE9_lock db 0 |
ATAPI_IDE10_lock db 0 |
ATAPI_IDE11_lock db 0 |
ignore_CD_eject_wait db 0 |
uglobal |
align 4 |
timer_ATAPI_check dd ? |
ATAPI_IDE0_lock db ? |
ATAPI_IDE1_lock db ? |
ATAPI_IDE2_lock db ? |
ATAPI_IDE3_lock db ? |
ATAPI_IDE4_lock db ? |
ATAPI_IDE5_lock db ? |
ATAPI_IDE6_lock db ? |
ATAPI_IDE7_lock db ? |
ATAPI_IDE8_lock db ? |
ATAPI_IDE9_lock db ? |
ATAPI_IDE10_lock db ? |
ATAPI_IDE11_lock db ? |
ignore_CD_eject_wait db ? |
endg |
;----------------------------------------------------------------------------- |
;************************************************* |
/kernel/branches/Kolibri-acpi/blkdev/cdrom.inc |
---|
0,0 → 1,271 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Copyright (C) MenuetOS 2000-2004 Ville Mikael Turjanmaa ;; |
;; Distributed under terms of the GNU General Public License ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision$ |
sys_cd_audio: |
cmp word [cdbase], word 0 |
jnz @f |
mov eax, 1 |
ret |
@@: |
; eax=1 cdplay at ebx 0x00FFSSMM |
; eax=2 get tracklist size of ecx to [ebx] |
; eax=3 stop/pause playing |
cmp eax, 1 |
jnz nocdp |
call sys_cdplay |
ret |
nocdp: |
cmp eax, 2 |
jnz nocdtl |
mov edi, [TASK_BASE] |
add edi, TASKDATA.mem_start |
add ebx, [edi] |
call sys_cdtracklist |
ret |
nocdtl: |
cmp eax, 3 |
jnz nocdpause |
call sys_cdpause |
ret |
nocdpause: |
mov eax, 0xffffff01 |
ret |
sys_cd_atapi_command: |
pushad |
mov dx, word [cdbase] |
add dx, 6 |
mov ax, word [cdid] |
out dx, al |
mov esi, 10 |
call delay_ms |
mov dx, word [cdbase] |
add dx, 7 |
in al, dx |
and al, 0x80 |
cmp al, 0 |
jnz res |
jmp cdl6 |
res: |
mov dx, word [cdbase] |
add dx, 7 |
mov al, 0x8 |
out dx, al |
mov dx, word [cdbase] |
add dx, 0x206 |
mov al, 0xe |
out dx, al |
mov esi, 1 |
call delay_ms |
mov dx, word [cdbase] |
add dx, 0x206 |
mov al, 0x8 |
out dx, al |
mov esi, 30 |
call delay_ms |
xor cx, cx |
cdl5: |
inc cx |
cmp cx, 10 |
jz cdl6 |
mov dx, word [cdbase] |
add dx, 7 |
in al, dx |
and al, 0x88 |
cmp al, 0x00 |
jz cdl5 |
mov esi, 100 |
call delay_ms |
jmp cdl5 |
cdl6: |
mov dx, word [cdbase] |
add dx, 4 |
mov al, 0 |
out dx, al |
mov dx, word [cdbase] |
add dx, 5 |
mov al, 0 |
out dx, al |
mov dx, word [cdbase] |
add dx, 7 |
mov al, 0xec |
out dx, al |
mov esi, 5 |
call delay_ms |
mov dx, word [cdbase] |
add dx, 1 |
mov al, 0 |
out dx, al |
add dx, 1 |
mov al, 0 |
out dx, al |
add dx, 1 |
mov al, 0 |
out dx, al |
add dx, 1 |
mov al, 0 |
out dx, al |
add dx, 1 |
mov al, 128 |
out dx, al |
add dx, 2 |
mov al, 0xa0 |
out dx, al |
xor cx, cx |
mov dx, word [cdbase] |
add dx, 7 |
cdl1: |
inc cx |
cmp cx, 100 |
jz cdl2 |
in al, dx |
and ax, 0x88 |
cmp al, 0x8 |
jz cdl2 |
mov esi, 2 |
call delay_ms |
jmp cdl1 |
cdl2: |
popad |
ret |
sys_cdplay: |
mov ax, 5 |
push ax |
push ebx |
cdplay: |
call sys_cd_atapi_command |
cli |
mov dx, word [cdbase] |
mov ax, 0x0047 |
out dx, ax |
mov al, 1 |
mov ah, [esp+0]; min xx |
out dx, ax |
mov ax, [esp+1]; fr sec |
out dx, ax |
mov ax, 256+99 |
out dx, ax |
mov ax, 0x0001 |
out dx, ax |
mov ax, 0x0000 |
out dx, ax |
mov esi, 10 |
call delay_ms |
sti |
add dx, 7 |
in al, dx |
test al, 1 |
jz cdplayok |
mov ax, [esp+4] |
dec ax |
mov [esp+4], ax |
cmp ax, 0 |
jz cdplayfail |
jmp cdplay |
cdplayfail: |
cdplayok: |
pop ebx |
pop ax |
xor eax, eax |
ret |
sys_cdtracklist: |
push ebx |
tcdplay: |
call sys_cd_atapi_command |
mov dx, word [cdbase] |
mov ax, 0x43+2*256 |
out dx, ax |
mov ax, 0x0 |
out dx, ax |
mov ax, 0x0 |
out dx, ax |
mov ax, 0x0 |
out dx, ax |
mov ax, 200 |
out dx, ax |
mov ax, 0x0 |
out dx, ax |
in al, dx |
mov cx, 1000 |
mov dx, word [cdbase] |
add dx, 7 |
cld |
cdtrnwewait: |
mov esi, 10 |
call delay_ms |
in al, dx |
and al, 128 |
cmp al, 0 |
jz cdtrl1 |
loop cdtrnwewait |
cdtrl1: |
; read the result |
mov ecx, [esp+0] |
mov dx, word [cdbase] |
cdtrread: |
add dx, 7 |
in al, dx |
and al, 8 |
cmp al, 8 |
jnz cdtrdone |
sub dx, 7 |
in ax, dx |
mov [ecx], ax |
add ecx, 2 |
jmp cdtrread |
cdtrdone: |
pop ecx |
xor eax, eax |
ret |
sys_cdpause: |
call sys_cd_atapi_command |
mov dx, word [cdbase] |
mov ax, 0x004B |
out dx, ax |
mov ax, 0 |
out dx, ax |
mov ax, 0 |
out dx, ax |
mov ax, 0 |
out dx, ax |
mov ax, 0 |
out dx, ax |
mov ax, 0 |
out dx, ax |
mov esi, 10 |
call delay_ms |
add dx, 7 |
in al, dx |
xor eax, eax |
ret |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
/kernel/branches/Kolibri-acpi/core/memory.inc |
---|
1313,10 → 1313,9 |
mov [esp+32], eax |
ret |
iglobal |
align 4 |
f68call: ; keep this table closer to main code |
f68call: |
dd f68.11 ; init_heap |
dd f68.12 ; user_alloc |
dd f68.13 ; user_free |
1334,8 → 1333,8 |
dd f68.25 ; unmask exception |
dd f68.26 ; user_unmap |
dd f68.27 ; load_file_umode |
endg |
align 4 |
proc load_pe_driver stdcall, file:dword, cmdline:dword |
push esi |
/kernel/branches/Kolibri-acpi/core/dll.inc |
---|
34,93 → 34,7 |
jmp .wait |
endp |
align 4 |
proc pci_read32 stdcall, bus:dword, devfn:dword, reg:dword |
push ebx |
xor eax, eax |
xor ebx, ebx |
mov ah, byte [bus] |
mov al, 6 |
mov bh, byte [devfn] |
mov bl, byte [reg] |
call pci_read_reg |
pop ebx |
ret |
endp |
align 4 |
proc pci_read16 stdcall, bus:dword, devfn:dword, reg:dword |
push ebx |
xor eax, eax |
xor ebx, ebx |
mov ah, byte [bus] |
mov al, 5 |
mov bh, byte [devfn] |
mov bl, byte [reg] |
call pci_read_reg |
pop ebx |
ret |
endp |
align 4 |
proc pci_read8 stdcall, bus:dword, devfn:dword, reg:dword |
push ebx |
xor eax, eax |
xor ebx, ebx |
mov ah, byte [bus] |
mov al, 4 |
mov bh, byte [devfn] |
mov bl, byte [reg] |
call pci_read_reg |
pop ebx |
ret |
endp |
align 4 |
proc pci_write8 stdcall, bus:dword, devfn:dword, reg:dword, val:dword |
push ebx |
xor eax, eax |
xor ebx, ebx |
mov ah, byte [bus] |
mov al, 8 |
mov bh, byte [devfn] |
mov bl, byte [reg] |
mov ecx, [val] |
call pci_write_reg |
pop ebx |
ret |
endp |
align 4 |
proc pci_write16 stdcall, bus:dword, devfn:dword, reg:dword, val:dword |
push ebx |
xor eax, eax |
xor ebx, ebx |
mov ah, byte [bus] |
mov al, 9 |
mov bh, byte [devfn] |
mov bl, byte [reg] |
mov ecx, [val] |
call pci_write_reg |
pop ebx |
ret |
endp |
align 4 |
proc pci_write32 stdcall, bus:dword, devfn:dword, reg:dword, val:dword |
push ebx |
xor eax, eax |
xor ebx, ebx |
mov ah, byte [bus] |
mov al, 10 |
mov bh, byte [devfn] |
mov bl, byte [reg] |
mov ecx, [val] |
call pci_write_reg |
pop ebx |
ret |
endp |
handle equ IOCTL.handle |
io_code equ IOCTL.io_code |
input equ IOCTL.input |
1427,8 → 1341,10 |
call free ;release object memory |
ret |
; param |
; ecx= size |
; eñõ= size |
align 4 |
create_object: |
1475,3 → 1391,5 |
xor eax, eax |
ret |
/kernel/branches/Kolibri-acpi/core/sync.inc |
---|
5,6 → 5,9 |
;; ;; |
;; Synhronization for MenuetOS. ;; |
;; Author: Halyavin Andrey, halyavin@land.ru ;; |
;; ;; |
;; ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision$ |
386,6 → 389,7 |
ret |
purge MUTEX_WAITER |
purge RWSEM_WAITING_FOR_WRITE |
purge RWSEM_WAITING_FOR_READ |
/kernel/branches/Kolibri-acpi/fs/fat.inc |
---|
1,4 → 1,4 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
43,7 → 43,6 |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision: 5578 $ |
cache_max equ 1919 ; max. is 1919*512+0x610000=0x6ffe00 |
/kernel/branches/Kolibri-acpi/fs/ext2/blocks.inc |
---|
7,7 → 7,7 |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision: 5363 $ |
$Revision: 4891 $ |
;--------------------------------------------------------------------- |
/kernel/branches/Kolibri-acpi/fs/ext2/ext2.asm |
---|
7,7 → 7,7 |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision: 5363 $ |
$Revision: 5089 $ |
include 'ext2.inc' |
/kernel/branches/Kolibri-acpi/fs/ext2/ext2.inc |
---|
7,7 → 7,7 |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision: 5363 $ |
$Revision: 4891 $ |
; Future jobs for driver, in order of preference: |
/kernel/branches/Kolibri-acpi/fs/ext2/inode.inc |
---|
7,7 → 7,7 |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision: 5363 $ |
$Revision: 4891 $ |
;--------------------------------------------------------------------- |
/kernel/branches/Kolibri-acpi/fs/ext2/resource.inc |
---|
7,7 → 7,7 |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision: 5363 $ |
$Revision: 4891 $ |
;--------------------------------------------------------------------- |
/kernel/branches/Kolibri-acpi/fs/xfs.asm |
---|
5,7 → 5,7 |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision: 5363 $ |
$Revision: 5089 $ |
include 'xfs.inc' |
/kernel/branches/Kolibri-acpi/fs/xfs.inc |
---|
5,7 → 5,7 |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision: 5363 $ |
$Revision: 4850 $ |
; from stat.h |
/kernel/branches/Kolibri-acpi/gui/char.mt |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/kernel/branches/Kolibri-acpi/kernel.asm |
---|
1688,8 → 1688,8 |
mov edi, [esp+64+4] |
jmp dtext |
;----------------------------------------------------------------------------- |
iglobal |
midi_base dw 0 |
uglobal |
midi_base dw ? |
endg |
;----------------------------------------------------------------------------- |
align 4 |
/kernel/branches/Kolibri-acpi/network/IPv4.inc |
---|
16,7 → 16,7 |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision: 5584 $ |
$Revision: 5522 $ |
IPv4_MAX_FRAGMENTS = 64 |
IPv4_MAX_ROUTES = 64 |
/kernel/branches/Kolibri-acpi/network/tcp_output.inc |
---|
14,7 → 14,7 |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision: 5584 $ |
$Revision: 5522 $ |
;----------------------------------------------------------------- |
; |
/kernel/branches/Kolibri-acpi/network/tcp_subr.inc |
---|
14,7 → 14,7 |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision: 5584 $ |
$Revision: 5522 $ |
align 4 |
iglobal |
/kernel/branches/Kolibri-acpi/network/ARP.inc |
---|
16,7 → 16,7 |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision: 5522 $ |
$Revision: 3386 $ |
ARP_NO_ENTRY = 0 |
ARP_VALID_MAPPING = 1 |
/kernel/branches/Kolibri-acpi/network/ethernet.inc |
---|
14,7 → 14,7 |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision: 5522 $ |
$Revision: 3346 $ |
ETH_FRAME_MINIMUM = 60 |
ETH_QUEUE_SIZE = 255 |
/kernel/branches/Kolibri-acpi/bus/pci/pci32.inc |
---|
166,6 → 166,8 |
call pci_make_config_cmd |
mov ebx, eax |
mov dx, 0xcf8 |
in eax, dx |
push eax |
; set up addressing to config data |
mov eax, ebx |
and al, 0xfc; make address dword-aligned |
191,7 → 193,14 |
jmp pci_fin_read1 |
pci_read_dword1: |
in eax, dx |
jmp pci_fin_read1 |
pci_fin_read1: |
; restore configuration control |
xchg eax, [esp] |
mov dx, 0xcf8 |
out dx, eax |
pop eax |
pop esi ebx |
ret |
pci_read_reg_2: |
202,8 → 211,15 |
mov esi, eax ; save register size into ESI |
and esi, 3 |
mov dx, 0xcfa |
push eax |
;store current state of config space |
mov dx, 0xcf8 |
in al, dx |
mov ah, al |
mov dl, 0xfa |
in al, dx |
xchg eax, [esp] |
; out 0xcfa,bus |
mov al, ah |
out dx, al |
232,8 → 248,18 |
jmp pci_fin_read2 |
pci_read_dword2: |
in eax, dx |
; jmp pci_fin_read2 |
pci_fin_read2: |
; restore configuration space |
xchg eax, [esp] |
mov dx, 0xcfa |
out dx, al |
mov dl, 0xf8 |
mov al, ah |
out dx, al |
pop eax |
pop esi ebx |
ret |
269,7 → 295,10 |
call pci_make_config_cmd |
mov ebx, eax |
; get current state into ecx |
mov dx, 0xcf8 |
in eax, dx |
push eax |
; set up addressing to config data |
mov eax, ebx |
and al, 0xfc; make address dword-aligned |
296,8 → 325,14 |
jmp pci_fin_write1 |
pci_write_dword1: |
out dx, eax |
jmp pci_fin_write1 |
pci_fin_write1: |
; restore configuration control |
pop eax |
mov dl, 0xf8 |
out dx, eax |
xor eax, eax |
pop ebx esi |
311,7 → 346,14 |
mov esi, eax ; save register size into ESI |
and esi, 3 |
mov dx, 0xcfa |
push eax |
;store current state of config space |
mov dx, 0xcf8 |
in al, dx |
mov ah, al |
mov dl, 0xfa |
in al, dx |
xchg eax, [esp] |
; out 0xcfa,bus |
mov al, ah |
out dx, al |
342,7 → 384,15 |
jmp pci_fin_write2 |
pci_write_dword2: |
out dx, eax |
jmp pci_fin_write2 |
pci_fin_write2: |
; restore configuration space |
pop eax |
mov dx, 0xcfa |
out dx, al |
mov dl, 0xf8 |
mov al, ah |
out dx, al |
xor eax, eax |
pop ebx esi |
608,6 → 658,12 |
mov dword[esp + 32], eax |
ret |
PCI_VENDOR_ID equ 0x00 |
PCI_CLASS_REVISION equ 0x08 |
PCI_HEADER_TYPE equ 0x0E |
PCI_SUBSYSTEM_VENDOR_ID equ 0x2c |
PCI_IRQ_LINE equ 0x3C |
proc pci_enum |
push ebp |
mov ebp, esp |
620,7 → 676,7 |
mov ah, [.bus] |
mov al, 2 |
mov bh, [.devfn] |
mov bl, 0 |
mov bl, PCI_VENDOR_ID |
call pci_read_reg |
cmp eax, 0xFFFFFFFF |
jnz .has_device |
636,27 → 692,37 |
jz .nomemory |
mov edi, eax |
mov [edi+PCIDEV.vendor_device_id], ecx |
mov eax, pcidev_list |
mov ecx, [eax+PCIDEV.bk] |
mov [edi+PCIDEV.bk], ecx |
mov [edi+PCIDEV.fd], eax |
mov [ecx+PCIDEV.fd], edi |
mov [eax+PCIDEV.bk], edi |
mov edx, pcidev_list |
list_add_tail edi, edx |
mov eax, dword [.devfn] |
mov dword [edi+PCIDEV.devfn], eax |
mov dword [edi+PCIDEV.owner], 0 |
mov word [edi+PCIDEV.devfn], ax |
mov bh, al |
mov al, 2 |
mov bl, 8 |
mov bl, PCI_CLASS_REVISION |
call pci_read_reg |
shr eax, 8 |
shr eax, 8 ;FIXME use byte mask |
mov [edi+PCIDEV.class], eax |
; mov ah, [.bus] |
; mov bh, byte [.devfn] |
; mov al, 2 |
; mov bl, PCI_SUBSYSTEM_VENDOR_ID |
; call pci_read_reg |
; mov [edi+PCIDEV.svid_sdid], eax |
; mov ah, [.bus] |
; mov al, 0 |
; mov bh, [.devfn] |
; mov bl, PCI_IRQ_LINE |
; call pci_read_reg |
; mov [edi+PCIDEV.irq_line], al |
test byte [.devfn], 7 |
jnz .next_func |
mov ah, [.bus] |
mov al, 0 |
mov bh, [.devfn] |
mov bl, 0Eh |
mov bl, PCI_HEADER_TYPE |
call pci_read_reg |
test al, al |
js .next_func |
677,3 → 743,334 |
mov eax, pcidev_list |
ret |
endp |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;internal functions |
;ecx (bus << 8)|devfn |
;edx register |
align 4 |
pci_bus: |
.conf1_index: |
; dword CF8 = (0x80000000 | ((reg & 0xF00) << 16) | (bus << 16) | (devfn << 8) | (reg & 0xFC)) |
push edx |
mov eax, edx ; eax = reg |
shl eax, 16 ; eax = reg << 16 |
shl ecx, 8 ; ecx = (bus << 16)|(devfn<<8) |
mov al, dl ; eax = (reg << 16)|reg |
and eax, 0x0F0000FC ; eax = ((reg & 0xF00) << 16)|(reg & 0xFC) |
lea eax, [0x80000000+eax+ecx] |
mov dx, 0xCF8 |
out dx, eax |
pop edx |
xor eax, eax |
ret |
align 4 |
.conf2_index: |
; byte CF8 = 0xF0 | (fn << 1) |
; byte CFA = bus |
push edx |
mov eax, ecx ; (bus << 8)|devfn |
and al, 7 ; fn |
lea eax, [0xF0+eax+eax] |
mov dx, 0xCF8 |
out dx, al |
mov al, ch ; bus |
mov dx, 0xCFA |
out dx, al |
pop edx |
xor eax, eax |
ret |
align 4 |
.conf1_read8: |
call .conf1_index |
and dx, 3 |
add dx, 0xCFC |
in al, dx |
ret |
align 4 |
.conf1_read16: |
call .conf1_index |
and dx, 2 |
add dx, 0xCFC |
in ax, dx |
ret |
align 4 |
.conf1_read32: |
call .conf1_index |
mov dx, 0xCFC |
in eax, dx |
ret |
align 4 |
.conf1_write8: |
call .conf1_index |
mov eax, [esp+4] |
and dx, 3 |
add dx, 0xCFC |
out dx, al |
ret 4 |
align 4 |
.conf1_write16: |
call .conf1_index |
mov eax, [esp+4] |
and dx, 2 |
add dx, 0xCFC |
out dx, ax |
ret 4 |
align 4 |
.conf1_write32: |
call .conf1_index |
mov eax, [esp+4] |
mov dx, 0xCFC |
out dx, eax |
ret 4 |
align 4 |
.conf2_read8: |
; in (0xC000 | (dev << 8) | reg) |
call .conf2_index |
and ecx, 0xF1 ;ecx = dev << 3 |
shl ecx, 5 ;ecx = dev << 8 |
lea edx, [0xC000+edx+ecx] |
in al, dx |
ret |
align 4 |
.conf2_read16: |
call .conf2_index |
and ecx, 0xF1 |
shl ecx, 5 |
lea edx, [0xC000+edx+ecx] |
in ax, dx |
ret |
align 4 |
.conf2_read32: |
call .conf2_index |
and ecx, 0xF1 |
shl ecx, 5 |
lea edx, [0xC000+edx+ecx] |
in eax, dx |
ret |
PCI_R8 equ 0 |
PCI_R16 equ 4 |
PCI_R32 equ 8 |
PCI_W8 equ 12 |
PCI_W16 equ 16 |
PCI_W32 equ 20 |
align 4 |
pci_conf1_rw: |
;internal function |
;eax accessor |
;ecx (bus << 8)|devfn |
.val equ esp+4 |
; dword CF8 = (0x80000000 | ((reg & 0xF00) << 16) | (bus << 16) | (devfn << 8) | (reg & 0xFC)) |
pushfd |
cli |
push edx |
push eax |
mov eax, edx ; eax = reg |
shl eax, 16 ; eax = reg << 16 |
shl ecx, 8 ; ecx = (bus << 16)|(devfn<<8) |
mov al, dl ; eax = (reg << 16)|reg |
and eax, 0x0F0000FC ; eax = ((reg & 0xF00) << 16)|(reg & 0xFC) |
lea eax, [0x80000000+eax+ecx] |
mov dx, 0xCF8 |
out dx, eax |
pop eax |
pop edx |
jmp dword [.fntab+eax] |
.r32: |
mov dx, 0xCFC |
in eax, dx |
.rdone: |
popfd |
ret |
.r16: |
and dx, 2 |
add dx, 0xCFC |
in al, dx |
jmp .rdone |
.r8: |
and dx, 3 |
add dx, 0xCFC |
in al, dx |
jmp .rdone |
.w32: |
mov eax, [esp+8] |
mov dx, 0xCFC |
out dx, eax |
.wdone: |
popfd |
ret 4 |
.w16: |
mov eax, [esp+8] |
and dx, 2 |
add dx, 0xCFC |
out dx, ax |
jmp .wdone |
.w8: |
mov eax, [esp+8] |
and dx, 3 |
add dx, 0xCFC |
out dx, al |
jmp .wdone |
align 4 |
.fntab: |
dd .r8 |
dd .r16 |
dd .r32 |
dd .w8 |
dd .w16 |
dd .w32 |
align 4 |
pci_fn_rw dd pci_conf1_rw |
;proc pci_bus_read8 fastcall, busaddr:dword, reg:dword |
;proc pci_bus_read16 fastcall, busaddr:dword, reg:dword |
;proc pci_bus_read32 fastcall, busaddr:dword, reg:dword |
align 4 |
pci_bus_read8: |
xor eax, eax |
jmp dword [pci_fn_rw] |
align 4 |
pci_bus_read16: |
mov eax, PCI_R16 |
jmp dword [pci_fn_rw] |
align 4 |
pci_bus_read32: |
mov eax, PCI_R32 |
jmp dword [pci_fn_rw] |
;proc pci_bus_write8 fastcall, busaddr:dword, reg:dword, val: dword |
;proc pci_bus_write16 fastcall, busaddr:dword, reg:dword, val: dword |
;proc pci_bus_write32 fastcall, busaddr:dword, reg:dword, val: dword |
align 4 |
pci_bus_write8: |
mov eax, PCI_W8 |
jmp dword [pci_fn_rw] |
align 4 |
pci_bus_write16: |
mov eax, PCI_W16 |
jmp dword [pci_fn_rw] |
align 4 |
pci_bus_write32: |
mov eax, PCI_W32 |
jmp dword [pci_fn_rw] |
;deprecated proc pci_read8 stdcall, bus:dword, devfn:dword, reg:dword |
;deprecated proc pci_read16 stdcall, bus:dword, devfn:dword, reg:dword |
;deprecated proc pci_read32 stdcall, bus:dword, devfn:dword, reg:dword |
align 4 |
pci_read8: |
.bus equ esp+4 |
.devfn equ esp+8 |
.pci_reg equ esp+12 |
.val equ esp+16 |
movzx ecx, byte [.devfn] |
mov ch, [.bus] |
movzx edx, word [.pci_reg] |
call pci_bus_read8 |
ret 12 |
align 4 |
pci_read16: |
.bus equ esp+4 |
.devfn equ esp+8 |
.pci_reg equ esp+12 |
.val equ esp+16 |
movzx ecx, byte [.devfn] |
mov ch, [.bus] |
movzx edx, word [.pci_reg] |
call pci_bus_read16 |
ret 12 |
align 4 |
pci_read32: |
.bus equ esp+4 |
.devfn equ esp+8 |
.pci_reg equ esp+12 |
.val equ esp+16 |
movzx ecx, byte [.devfn] |
mov ch, [.bus] |
movzx edx, word [.pci_reg] |
call pci_bus_read32 |
ret 12 |
;deprecated proc pci_write8 stdcall, bus:dword, devfn:dword, reg:dword, val:dword |
;deprecated proc pci_write16 stdcall, bus:dword, devfn:dword, reg:dword, val:dword |
;deprecated proc pci_write32 stdcall, bus:dword, devfn:dword, reg:dword, val:dword |
align 4 |
pci_write8: |
.bus equ esp+4 |
.devfn equ esp+8 |
.pci_reg equ esp+12 |
.val equ esp+16 |
movzx ecx, byte [.devfn] |
mov ch, [.bus] |
movzx edx, word [.pci_reg] |
push dword [esp+16] |
call pci_bus_write8 |
ret 16 |
align 4 |
pci_write16: |
.bus equ esp+4 |
.devfn equ esp+8 |
.pci_reg equ esp+12 |
.val equ esp+16 |
movzx ecx, byte [.devfn] |
mov ch, [.bus] |
movzx edx, word [.pci_reg] |
push dword [esp+16] |
call pci_bus_write16 |
ret 16 |
align 4 |
pci_write32: |
.bus equ esp+4 |
.devfn equ esp+8 |
.pci_reg equ esp+12 |
.val equ esp+16 |
movzx ecx, byte [.devfn] |
mov ch, [.bus] |
movzx edx, word [.pci_reg] |
push dword [esp+16] |
call pci_bus_write32 |
ret 16 |
/kernel/branches/Kolibri-acpi/video/blitter.inc |
---|
5,7 → 5,7 |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision: 5363 $ |
$Revision: 5164 $ |
struct BLITTER_BLOCK |
37,7 → 37,7 |
;esi= clip RECT ptr |
;edi= RECT ptr |
;return code: |
;CF= 0 - draw, 1 - don't draw |
;eax= 0 - draw, 1 - don't draw |
push ebx |
53,15 → 53,18 |
jl .fail |
cmp eax, ecx ;left >= clip.left |
jge @F |
jae @F |
mov [edi+RECT.left], ecx |
mov eax, ecx |
@@: |
mov [edi+RECT.left], eax |
cmp ebx, edx ;right <= clip.right |
jle @f |
mov ebx, edx |
@@: |
mov [edi+RECT.right], ebx |
mov [edi+RECT.right], edx |
@@: |
mov eax, [edi+RECT.top] |
mov ebx, [edi+RECT.bottom] |
mov ecx, [esi+RECT.top] ;clip.top |
74,21 → 77,23 |
jl .fail |
cmp eax, ecx ;top >= clip.top |
jge @F |
jae @F |
mov [edi+RECT.top], ecx |
mov eax, ecx |
@@: |
mov [edi+RECT.top], eax |
cmp ebx, edx ;bottom <= clip.bottom |
jle @f |
mov [edi+RECT.bottom], edx |
mov ebx, edx |
@@: |
mov [edi+RECT.bottom], ebx |
pop ebx |
clc |
xor eax, eax |
ret |
.fail: |
pop ebx |
stc |
mov eax, 1 |
ret |
95,9 → 100,6 |
align 4 |
blit_clip: |
;return code: |
;CF= 0 - draw, 1 - don't draw |
.sx0 equ 8 |
.sy0 equ 12 |
.sx1 equ 16 |
128,7 → 130,9 |
lea esi, [ebx+BLITTER.sc] |
call block_clip |
jc .done |
test eax, eax |
mov esi, 1 |
jnz .done |
mov edi, [esp+.sx0] |
mov edx, [ebx+BLITTER.dst_x] |
153,7 → 157,9 |
lea edi, [esp+.dx0] |
lea esi, [ebx+BLITTER.dc] |
call block_clip |
jc .done |
test eax, eax |
mov esi, 1 |
jnz .done |
mov edx, [esp+.dx0] |
mov eax, [esp+.dx1] |
176,8 → 182,9 |
mov [ebx+BLITTER.src_y], ecx |
mov [ebx+BLITTER.dst_x], edx |
mov [ebx+BLITTER.dst_y], eax |
clc |
xor esi, esi |
.done: |
mov eax, esi |
add esp, 40 |
pop ebx |
pop esi |
198,17 → 205,16 |
align 4 |
blit_32: |
.x_y equ 72 |
.tmp_x_y equ 76 |
push ebp |
push edi |
push esi |
push ebx |
virtual at sizeof.BLITTER |
.position dd ? ; (x shl 16) + y |
; ??? |
.extra_var1 dd ? |
.local_vars_size = $ |
end virtual |
sub esp, .local_vars_size |
sub esp, 80 |
mov eax, [TASK_BASE] |
mov ebx, [eax-twdw + WDATA.box.width] |
248,13 → 254,14 |
mov eax, [ecx+32] |
mov [esp+BLITTER.bitmap], eax |
mov [esp+56], eax |
mov eax, [ecx+36] |
mov [esp+BLITTER.stride], eax |
mov [esp+60], eax |
mov ecx, esp |
call blit_clip |
jc .L57 |
test eax, eax |
jne .done |
mov eax, [TASK_BASE] |
264,21 → 271,13 |
add ebp, [eax-twdw + WDATA.box.top] |
mov ecx, ebx |
add ecx, [esp+BLITTER.w] |
shl ecx, 16 |
mov cx, bp |
add ecx, [esp+BLITTER.h] |
mov [esp+.x_y], ecx |
mov eax, ebx |
shl eax, 16 |
mov ax, bp |
mov [esp+.position], eax |
mov edi, ebp |
; imul edi, [_display.pitch] |
mov edi, [BPSLine_calc_area+edi*4] |
; imul ebp, [_display.width] |
mov ebp, [d_width_calc_area+ebp*4] |
add ebp, ebx |
290,103 → 289,34 |
lea esi, [eax+esi*4] |
add esi, [esp+BLITTER.bitmap] |
mov eax, ecx |
mov ecx, [esp+BLITTER.h] |
mov edx, [esp+BLITTER.w] |
test ecx, ecx ;FIXME check clipping |
jz .L57 |
jz .done |
test edx, edx |
jz .L57 |
jz .done |
cmp [_display.bits_per_pixel], 32 |
jne .core_24 |
lea edi, [edi+ebx*4] |
; xchg bx, bx |
mov ebx, [CURRENT_TASK] |
; check for hardware cursor |
cmp [_display.select_cursor], select_cursor |
je .core_32.software_cursor |
cmp [_display.select_cursor], 0 |
jne .core_32.hardware_cursor |
;-------------------------------------- |
.core_32.software_cursor: |
align 4 |
.outer32: |
mov ecx, [esp+80] |
shr ecx, 4 |
and ecx, 3 |
align 4 |
.inner32: |
cmp [ebp], bl |
jne .skip |
;-------------------------------------- |
mov eax, [esi] |
jmp dword [.tbl_32+ecx*4] |
mov ecx, [esp+.position] |
; check mouse area for putpixel |
call [_display.check_mouse] |
;-------------------------------------- |
; store to real LFB |
mov [LFB_BASE+edi], eax |
;-------------------------------------- |
align 4 |
.skip: |
add esi, 4 |
add edi, 4 |
inc ebp |
add [esp+.position], 1 shl 16 |
dec edx |
jnz .inner32 |
.tbl_32 dd blit_copy_32 |
dd blit_copy_32_bgr |
dd blit_trans_32 |
dd blit_trans_32_bgr |
add esi, [esp+BLITTER.stride] |
add edi, [_display.lfb_pitch] |
add ebp, [_display.width] |
mov edx, [esp+BLITTER.w] |
mov eax, edx |
inc [esp+.position] |
sub ebp, edx |
shl eax, 2 |
sub esi, eax |
sub edi, eax |
shl eax, 16-2 |
sub [esp+.position], eax |
dec [esp+BLITTER.h] |
jnz .outer32 |
jmp .done |
.core_32.hardware_cursor: |
align 4 |
.hw.outer32: |
xor ecx, ecx |
align 4 |
.hw.inner32: |
cmp [ebp+ecx], bl |
jne .hw.skip |
mov eax, [esi+ecx*4] |
mov [LFB_BASE+edi+ecx*4], eax |
align 4 |
.hw.skip: |
inc ecx |
dec edx |
jnz .hw.inner32 |
add esi, [esp+BLITTER.stride] |
add edi, [_display.lfb_pitch] |
add ebp, [_display.width] |
mov edx, [esp+BLITTER.w] |
dec [esp+BLITTER.h] |
jnz .hw.outer32 |
.done: |
; call [draw_pointer] |
; call __sys_draw_pointer |
.L57: |
add esp, .local_vars_size |
add esp, 80 |
pop ebx |
pop esi |
pop edi |
393,133 → 323,121 |
pop ebp |
ret |
.core_24: |
cmp [_display.bits_per_pixel], 24 |
jne .core_16 |
align 4 |
blit_copy_32_bgr: |
mov ebx, 1 |
lea ebx, [ebx+ebx*2] |
lea edi, [LFB_BASE+edi+ebx] |
mov ebx, [CURRENT_TASK] |
align 4 |
blit_copy_32: |
align 4 |
.outer24: |
mov [esp+.extra_var1], edi |
.outer32: |
mov eax, [esp+.x_y] |
mov [esp+.tmp_x_y], eax |
xor ecx, ecx |
align 4 |
.inner24: |
cmp [ebp+ecx], bl ; Does the process own this pixel? |
jne .skip_1 |
.inner32: |
cmp [ebp+ecx], bl |
jne .skip |
;-------------------------------------- |
push eax |
mov eax, [esi+ecx*4] |
lea edi, [edi+ecx*2] |
; check for hardware cursor |
cmp [_display.select_cursor], select_cursor |
je @f |
cmp [_display.select_cursor], 0 |
jne .no_mouseunder_1 |
jne .no_mouseunder |
;-------------------------------------- |
align 4 |
@@: |
push ecx |
mov ecx, [esp+4+.tmp_x_y] |
mov ecx, [esp+4] |
ror ecx, 16 |
sub ecx, edx |
rol ecx, 16 |
sub ecx, [esp+BLITTER.h + 8] |
; check mouse area for putpixel |
call [_display.check_mouse] |
pop ecx |
;-------------------------------------- |
align 4 |
.no_mouseunder_1: |
mov [edi+ecx], ax |
shr eax, 16 |
mov [edi+ecx+2], al |
pop eax |
.no_mouseunder: |
; store to real LFB |
mov [LFB_BASE+edi+ecx*4], eax |
;-------------------------------------- |
align 4 |
.skip_1: |
.skip: |
add [esp+.tmp_x_y], dword 0x10000 |
inc ecx |
dec edx |
jnz .inner24 |
jnz .inner32 |
add esi, [esp+BLITTER.stride] |
mov edi, [esp+.extra_var1] |
add edi, [_display.lfb_pitch] |
add ebp, [_display.width] |
inc dword [esp+.x_y] |
mov edx, [esp+BLITTER.w] |
dec [esp+BLITTER.h] |
jnz .outer24 |
jnz .outer32 |
jmp .done |
jmp blit_32.done |
.core_16: |
lea edi, [LFB_BASE+edi+ebx*2] |
mov ebx, [CURRENT_TASK] |
align 4 |
blit_trans_32_bgr: |
mov ebx, 1 |
.outer16: |
mov [esp+.extra_var1], edi |
align 4 |
blit_trans_32: |
.outer32: |
mov eax, [esp+.x_y] |
mov [esp+.tmp_x_y], eax |
xor ecx, ecx |
.inner16: |
cmp [ebp+ecx], bl ; Does the process own this pixel? |
jne .skip_2 |
align 4 |
.inner32: |
cmp [ebp+ecx], bl |
jne .skip |
;-------------------------------------- |
push eax |
mov eax, [esi+ecx*4] |
test eax, 0xFF000000 |
jz .skip |
; check for hardware cursor |
cmp [_display.select_cursor], select_cursor |
je @f |
cmp [_display.select_cursor], 0 |
jne .no_mouseunder_2 |
jne .no_mouseunder |
;-------------------------------------- |
align 4 |
@@: |
push ecx |
mov ecx, [esp+4] |
ror ecx, 16 |
sub ecx, edx |
rol ecx, 16 |
sub ecx, [esp+BLITTER.h + 8] |
mov ecx, [esp+4+.tmp_x_y] |
; check mouse area for putpixel |
call [_display.check_mouse] |
pop ecx |
;-------------------------------------- |
.no_mouseunder_2: |
; convert to 16 bpp and store to LFB |
and eax, 00000000111110001111110011111000b |
shr ah, 2 |
shr ax, 3 |
ror eax, 8 |
add al, ah |
rol eax, 8 |
mov [edi+ecx*2], ax |
pop eax |
align 4 |
.no_mouseunder: |
; store to real LFB |
mov [LFB_BASE+edi+ecx*4], eax |
;-------------------------------------- |
.skip_2: |
align 4 |
.skip: |
add [esp+.tmp_x_y], dword 0x10000 |
inc ecx |
dec edx |
jnz .inner16 |
jnz .inner32 |
add esi, [esp+BLITTER.stride] |
mov edi, [esp+.extra_var1] |
add edi, [_display.lfb_pitch] |
add ebp, [_display.width] |
inc dword [esp+.x_y] |
mov edx, [esp+BLITTER.w] |
dec [esp+BLITTER.h] |
jnz .outer16 |
jnz .outer32 |
jmp .done |
jmp blit_32.done |
/kernel/branches/Kolibri-acpi/boot/ETFONT.FNT |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
/kernel/branches/Kolibri-acpi/docs/usbapi_ru.txt |
---|
0,0 → 1,249 |
Когда ядро обнаруживает подключенное устройство USB, оно настраивает его |
согласно USB-протокола - SET_ADDRESS + SET_CONFIGURATION. Всегда |
устанавливается первая конфигурация. Ядро также читает дескриптор |
устройства, чтобы показать некоторую информацию, читает и анализирует |
дескриптор конфигурации. Для каждого интерфейса ядро будет искать класс этого |
интерфейса и попытается загрузить соответствующий драйвер COFF. В настоящее |
время соответствие кодов классов и имен драйверов жестко прописано в коде ядра |
и выглядит следующим образом: |
3 = usbhid.obj, |
7 = usbprint.obj, |
8 = usbstor.obj, |
9 = поддерживаются самим ядром, |
другие = usbother.obj. |
Драйвер должен быть стандартным драйвером в формате COFF, экспортирующим |
процедуру под названием "START" и переменную "version". Загрузчик вызывает |
процедуру "START" как STDCALL с одним параметром DRV_ENTRY = 1. При завершении |
работы системы, если инициализация драйвера была успешна, "START" процедуру |
также вызывает код остановки системы с одним параметром DRV_EXIT = -1. |
Драйвер должен зарегистрировать себя в качестве драйвера USB в процедуре |
"START". Это делается путем вызова экспортируемой ядром функции RegUSBDriver и |
возврата её результата в качестве результата "START" процедуры. |
void* __stdcall RegUSBDriver( |
const char* name, |
void* handler, |
const USBFUNC* usbfunc |
); |
Параметр 'name' должен совпадать с именем драйвера, например "usbhid" для |
usbhid.obj. |
Параметр 'handler' является необязательным. Если он не NULL, то он должен |
указывать на стандартный обработчик IOCTL интерфейса, как в обычном (не-USB) |
драйвере. |
Параметр "Usbfunc" представляет собой указатель на следующую структуру: |
struc USBFUNC |
{ |
.strucsize dd ? ; размер структуры, включая это поле |
.add_device dd ? ; указатель на AddDevice процедуру в драйвере |
; (необходимо) |
.device_disconnect dd ? ; указатель на DeviceDisconnected процедуру в драйвере |
; опционально, может быть NULL |
; В будущем могут быть добавлены другие функции |
} |
Драйвер ДОЛЖЕН реализовать функцию: |
void* __stdcall AddDevice( |
void* pipe0, |
void* configdescr, |
void* interfacedescr |
); |
Параметр "Pipe0" - хэндл контрольного канала для нулевой конечной точки |
устройства. Он может быть использован в качестве аргумента для |
USBControlTransferAsync (см. далее). |
Параметр 'configdescr' указывает на дескриптор конфигурации и все связанные с |
ним данные, представленные так, как их возвращает запрос GET_DESCRIPTOR. |
Полный размер данных содержится в поле Length самого дескриптора. |
(см. USB2.0 spec.) |
Параметр 'interfacedescr' указывает на дескриптор интерфейса инициализируемого |
в данный момент. Это указатель на данные находящиеся внутри структуры |
"configdescr". (Помним, что структура INTERFACE_DESCRIPTOR, находится внутри |
структуры CONFIGURATION_DESCRIPTOR. См. USB2.0 Spec.) Обратите внимание, что |
одно устройство может реализовывать много интерфейсов и AddDevice может быть |
вызвана несколько раз с одним "configdescr" но разными "interfacedescr". |
Возвращенное значение NULL показывает, что инициализация не была успешной. |
Любое другое значение означает инициализацию устройства. Ядро не делает попыток |
как-то интерпретировать это значение. Это может быть, например, указатель на |
внутренние данные драйвера в памяти, выделенной с помощью Kmalloc или индексом |
в какой-то своей таблице. (Помните, что Kmalloc() НЕ stdcall-функция! Она |
портит регистр ebx!) |
Драйвер МОЖЕТ реализовать функцию: |
void __stdcall DeviceDisconnected( |
void* devicedata |
); |
Если данная функция реализована, то ядро вызывает её, когда устройство |
отключено, посылая ей в качестве параметра "devicedata" то, что было возвращено |
ему функцией "AddDevice" при старте драйвера. |
Драйвер может использовать следующие функции экспортируемые ядром: |
void* __stdcall USBOpenPipe( |
void* pipe0, |
int endpoint, |
int maxpacketsize, |
int type, |
int interval |
); |
Параметр "Pipe0" - хэндл контрольного канала для нулевой конечной точки |
устройства. Используется для идентификации устройства. |
Параметр "endpoint" номер конечной точки USB. Младшие 4 бита, собственно, номер |
точки, а бит 7 имеет следующее значение: 0 - для OUT точки, 1 - для IN точки. |
Остальные биты должны быть равны нулю. |
Параметр "maxpacketsize" устанавливает максимальный размер пакета для канала. |
Параметр "type" устанавливает тип передачи для конечной точки, как это прописано |
в USB спецификации: |
0 = control, |
1 = isochronous (сейчас не поддерживается), |
2 = bulk, |
3 = interrupt. |
Параметр "interval" игнорируется для control и bulk передач. Для конечных точек |
по прерываниям устанавливает периодичность опроса в миллисекундах. |
Функция возвращает хэндл канала при успешном его открытии либо NULL при ошибке. |
Хэндл канала обращается в NULL когда: |
а) канал будет явно закрыт функцией USBClosePipe (см. ниже); |
б) была выполнена предоставленная драйвером функция "DeviceDisconnected". |
void __stdcall USBClosePipe( |
void* pipe |
); |
Освобождает все ресурсы, связанные с выбранным каналом. Единственный параметр - |
указатель на хэндл, который был возвращен функцией USBOpenPipe при открытии |
канала. Когда устройство отключается, все связанные с ним каналы закрываются |
ядром; нет необходимости в самостоятельном вызове этой функции. |
void* __stdcall USBNormalTransferAsync( |
void* pipe, |
void* buffer, |
int size, |
void* callback, |
void* calldata, |
int flags |
); |
void* __stdcall USBControlTransferAsync( |
void* pipe, |
void* setup, |
void* buffer, |
int size, |
void* callback, |
void* calldata, |
int flags |
); |
Первая функция ставит в очередь bulk или interrupt передачу для выбранного |
канала. Тип и направление передачи фиксированы для bulk и interrupt типов |
конечных точек, как это было выбрано функцией USBOpenPipe. |
Вторая функция ставит в очередь control передачу для выбранного канала. |
Направление этой передачи определяется битом 7 байта 0 пакета "setup" |
(0 - для OUT, 1 - для IN передачи). Эта функция возвращает управление немедленно. |
По окончании передачи вызывается функция "callback" заданная как аргумент |
USB______TransferAsync. |
Параметр "pipe" - хэндл, возвращенный функцией USBOpenPipe. |
Параметр 'setup' функции USBControlTransferAsync указывает на 8-байтный |
конфигурационный пакет (см. USB2.0 Spec). |
Параметр "buffer" - это указатель на буфер. Для IN передач он будет заполнен |
принятыми данными. Для OUT передач он должен быть заполнен данными, которые мы |
хотим передать. Указатель может быть NULL для пустых передач, либо для передач |
control, если дополнительных данных не требуется. |
Параметр "size" - это размер данных для передачи. Он может быть равен 0 для |
пустых передач, либо для передач control, если дополнительных данных не требуется. |
Параметр "callback" - это указатель на функцию, которая будет вызвана по |
окончании передачи. |
Параметр "calldata" будет передан функции "callback" вызываемой по окончании |
передачи. Например, он может быть NULL или указывать на данные устройства или |
указывать на данные используемые как дополнительные параметры, передаваемые от |
вызывающей USB_____TransferAsync функции в callback функцию. |
Другие данные, связанные с передачей, могут быть помещены до буфера (по смещению) |
или после него. Они могут быть использованы из callback-функции, при необходимости. |
Параметр "flags" - это битовое поле. Бит 0 игнорируется для OUT передач. Для IN |
передач он означает, может ли устройство передать меньше данных (бит=1), чем |
определено в "size" или нет (бит=0). Остальные биты не используются и должны |
быть равны 0. |
Возвращаемое функциями значение равно NULL в случае ошибки и не NULL если |
передача успешно поставлена в очередь. Если происходит ошибка при передаче, то |
callback функция будет об этом оповещена. |
void __stdcall CallbackFunction( |
void* pipe, |
int status, |
void* buffer, |
int length, |
void* calldata |
); |
Параметры 'pipe', 'buffer', 'calldata' значат то же, что и для |
USB_____TransferAsync. |
Параметр "length" это счетчик переданных байт. Для control передач он отражает |
дополнительные 8 байт этапа SETUP. Т.е. 0 означает ошибку на этапе SETUP, а |
"size"+8 успешную передачу. |
Параметр "status" не равен 0 в случае ошибки: |
USB_STATUS_OK = 0 ; без ошибок |
USB_STATUS_CRC = 1 ; ошибка контрольной суммы |
USB_STATUS_BITSTUFF = 2 ; ошибка инверсии битов (bitstuffing) |
USB_STATUS_TOGGLE = 3 ; data toggle mismatch |
; (Нарушение последовательности DAT0/DAT1) |
USB_STATUS_STALL = 4 ; устройство возвратило STALL статус (остановлено) |
USB_STATUS_NORESPONSE = 5 ; устройство не отвечает |
USB_STATUS_PIDCHECK = 6 ; ошибка в поле PacketID (PID) |
USB_STATUS_WRONGPID = 7 ; неожидаемое PacketID (PID) значение |
USB_STATUS_OVERRUN = 8 ; слишком много данных от конечной точки |
USB_STATUS_UNDERRUN = 9 ; слишком мало данных от конечной точки |
USB_STATUS_BUFOVERRUN = 12 ; переполнение внутреннего буфера контроллера |
; возможна только для изохронных передач |
USB_STATUS_BUFUNDERRUN = 13 ; опустошение внутреннего буфера контроллера |
; возможна только для изохронных передач |
USB_STATUS_CLOSED = 16 ; канал закрыт либо через ClosePipe, либо в |
; результате отключения устройства |
Если несколько передач были поставлены в очередь для одного канала, то callback |
функции для них будут вызываться в порядке постановки передач в очередь. |
Если канал был закрыт ввиду USBClosePipe или отключения устройства, то callback |
функции (если очередь передач не пуста) получат USB_STATUS_CLOSED. |
Вызов DeviceDisconnected() последует после отработки всех оставшихся в очереди |
callback функций. |
void* __stdcall USBGetParam(void* pipe0, int param); |
Возвращает указатель на некоторые параметры устройства запомненные ядром при |
инициализации первой конфигурации. Не передает ничего устройству по шине. |
pipe0 - хэндл контрольного канала для нулевой конечной точки устройства. |
param - выбор возвращаемого параметра: |
0 - возвратить указатель на дескриптор устройства; |
1 - возвратить указатель на дескриптор конфигурации; |
2 - возвратить режим шины устройства: |
USB_SPEED_FS = 0 ; full-speed |
USB_SPEED_LS = 1 ; low-speed |
USB_SPEED_HS = 2 ; high-speed |
/kernel/branches/Kolibri-acpi/kernelsp.inc |
---|
5,7 → 5,7 |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision: 5363 $ |
$Revision: 4850 $ |
; Éste archivo debe ser editado con codificación CP866 |
/kernel/branches/Kolibri-acpi/sec_loader/trunk/kolibri_ldm/bootet.inc |
---|
0,0 → 1,119 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2007. All rights reserved. ;; |
;; Copyright (C) MenuetOS 2000-2004 Ville Mikael Turjanmaa ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; kolibri_ldm.asm the module for Secondary Loader ;; |
;; ;; |
;; KolibriOS 16-bit loader module, ;; |
;; based on bootcode for KolibriOS ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;====================================================================== |
; |
; BOOT DATA |
; |
;====================================================================== |
d80x25_bottom: |
db 186,' KolibriOS based on MenuetOS and comes with ABSOLUTELY ' |
db 'NO WARRANTY ',186 |
db 186,' See file COPYING for details ' |
db ' ',186 |
line_full_bottom |
d80x25_bottom_num = 3 |
novesa db "Ekraan: EGA/CGA",13,10,0 |
vervesa db "Vesa versioon: Vesa x.x",13,10,0 |
vervesa_off=20 |
msg_apm db " APM x.x ", 0 |
gr_mode db 186," Vesa 2.0+ 16 M LFB: [1] 640x480, [2] 800x600, " |
db "[3] 1024x768, [4] 1280x1024",13,10 |
db 186," Vesa 1.2 16 M Bnk: [5] 640x480, [6] 800x600, " |
db "[7] 1024x768, [8] 1280x1024",13,10 |
db 186," EGA/CGA 256 värvi: [9] 320x200, " |
db "VGA 16 värvi: [0] 640x480",13,10 |
db 186," Vali reziim: ",0 |
bt24 db "Bitti pikseli kohta: 24",13,10,0 |
bt32 db "Bitti pikseli kohta: 32",13,10,0 |
vrrmprint db "Kinnita VRR? (ekraani sagedus suurem kui 60Hz" |
db " ainult:",13,10 |
db 186," 1024*768->800*600 ja 800*600->640*480) [1-jah,2-ei]:",0 |
;askmouse db " Hiir:" |
; db " [1] PS/2 (USB), [2] Com1, [3] Com2." |
; db " Vali port [1-3]: ",0 |
;no_com1 db 13,10,186, " No COM1 mouse",0 |
;no_com2 db 13,10,186, " No COM2 mouse",0 |
;ask_dma db "Use DMA for HDD access? [1-yes, 2-only for reading, 3-no]: ",0 |
ask_bd db "Add disks visible by BIOS emulated in V86-mode? [1-yes, 2-no]: ",0 |
;gr_direct db 186," Use direct LFB writing? " |
; db "[1-yes/2-no] ? ",0 |
;mem_model db 13,10,186," Motherboard memory [1-16 Mb / 2-32 Mb / " |
; db "3-64Mb / 4-128 Mb / 5-256 Mb] ? ",0 |
;bootlog db 13,10,186," After bootlog display [1-continue/2-pause] ? ",0 |
bdev db "Paigalda mäluketas [1-diskett; 2-C:\kolibri.img (FAT32);" |
db 13,10,186," " |
db "3-kasuta eellaaditud mäluketast kerneli restardist;" |
db 13,10,186," " |
db "4-loo tühi pilt]: ",0 |
probetext db 13,10,13,10,186," Kasuta standartset graafika reziimi? [1-jah, " |
db "2-leia biosist (Vesa 3.0)]: ",0 |
;memokz256 db 13,10,186," RAM 256 Mb",0 |
;memokz128 db 13,10,186," RAM 128 Mb",0 |
;memokz64 db 13,10,186," RAM 64 Mb",0 |
;memokz32 db 13,10,186," RAM 32 Mb",0 |
;memokz16 db 13,10,186," RAM 16 Mb",0 |
prnotfnd db "Fataalne - Videoreziimi ei leitud.",0 |
;modena db "Fataalne - VBE 0x112+ on vajalik.",0 |
not386 db "Fataalne - CPU 386+ on vajalik.",0 |
btns db "Fataalne - Ei suuda värvisügavust määratleda.",0 |
fatalsel db "Fataalne - Graafilist reziimi riistvara ei toeta.",0 |
badsect db 13,10,186," Fataalne - Vigane sektor. Asenda diskett.",0 |
memmovefailed db 13,10,186," Fataalne - Int 0x15 liigutamine ebaõnnestus.",0 |
okt db " ... OK" |
linef db 13,10,0 |
diskload db "Loen disketti: 00 %",8,8,8,8,0 |
pros db "00" |
backspace2 db 8,8,0 |
boot_dev db 0 ; 0=floppy, 1=hd |
start_msg db "Vajuta [abcd] seadete muutmiseks, vajuta [Enter] laadimise jätkamiseks",13,10,0 |
time_msg db " või oota " |
time_str db " 5 sekundit" |
db " automaatseks jätkamiseks",13,10,0 |
current_cfg_msg db "Praegused seaded:",13,10,0 |
curvideo_msg db " [a] Videoreziim: ",0 |
mode1 db "640x480",0 |
mode2 db "800x600",0 |
mode3 db "1024x768",0 |
mode4 db "1280x1024",0 |
modes_msg dw mode4,mode1,mode2,mode3 |
modevesa20 db " koos LFB",0 |
modevesa12 db ", VESA 1.2 Bnk",0 |
mode9 db "320x200, EGA/CGA 256 värvi",0 |
mode10 db "640x480, VGA 16 värvi",0 |
probeno_msg db " (standard reziim)",0 |
probeok_msg db " (kontrolli ebastandardseid reziime)",0 |
;dma_msg db " [b] Kasuta DMA'd HDD juurdepääsuks:",0 |
usebd_msg db " [b] Add disks visible by BIOS:",0 |
on_msg db " sees",13,10,0 |
off_msg db " väljas",13,10,0 |
;readonly_msg db " ainult lugemiseks",13,10,0 |
vrrm_msg db " [c] Kasuta VRR:",0 |
preboot_device_msg db " [d] Disketi kujutis: ",0 |
preboot_device_msgs dw 0,pdm1,pdm2,pdm3 |
pdm1 db "reaalne diskett",13,10,0 |
pdm2 db "C:\kolibri.img (FAT32)",13,10,0 |
pdm3 db "kasuta juba laaditud kujutist",13,10,0 |
pdm4 db "loo tühi pilt",13,10,0 |
loading_msg db "Laadin KolibriOS...",0 |
save_quest db "Jäta meelde praegused seaded? [y/n]: ",0 |
loader_block_error db "Alglaaduri andmed vigased, ei saa jätkata. Peatatud.",0 |
remark1 db "Default values were selected to match most of configurations, but not all.",0 |
remark2 db "If you have LCD-monitor, disable VRR in the item [c] - you do not need it.",0 |
remark3 db "If the system does not boot, try to disable the item [b].",0 |
remarks dw remark1, remark2, remark3 |
num_remarks = 3 |
/kernel/branches/Kolibri-acpi/sec_loader/trunk/kolibri_ldm/bootge.inc |
---|
0,0 → 1,118 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2007. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;====================================================================== |
; |
; BOOT DATA |
; |
;====================================================================== |
d80x25_bottom: |
; db 186,' KolibriOS based on MenuetOS and comes with ABSOLUTELY ' |
; db 'NO WARRANTY ',186 |
; db 186,' See file COPYING for details ' |
; db ' ',186 |
db 186,' KolibriOS basiert auf MenuetOS und wird ohne jegliche ' |
db ' Garantie vertrieben ',186 |
db 186,' Details stehen in der Datei COPYING ' |
db ' ',186 |
line_full_bottom |
d80x25_bottom_num = 3 |
novesa db "Anzeige: EGA/CGA ",13,10,0 |
vervesa db "Vesa-Version: Vesa ",13,10,0 |
vervesa_off=22 |
msg_apm db " APM x.x ", 0 |
gr_mode db 186," Vesa 2.0+ 16 M LFB: [1] 640x480, [2] 800x600, " |
db "[3] 1024x768, [4] 1280x1024",13,10 |
db 186," Vesa 1.2 16 M Bnk: [5] 640x480, [6] 800x600, " |
db "[7] 1024x768, [8] 1280x1024",13,10 |
db 186," EGA/CGA 256 Farben: [9] 320x200, " |
db "VGA 16 Farben: [0] 640x480",13,10 |
db 186," Waehle Modus: ",0 |
bt24 db "Bits Per Pixel: 24",13,10,0 |
bt32 db "Bits Per Pixel: 32",13,10,0 |
vrrmprint db "VRR verwenden? (Monitorfrequenz groesser als 60Hz" |
db " only for transfers:",13,10 |
db 186," 1024*768->800*600 und 800*600->640*480) [1-ja,2-nein]:",0 |
;askmouse db " Maus angeschlossen an:" |
; db " [1] PS/2 (USB), [2] Com1, [3] Com2." |
; db " Waehle Port [1-3]: ",0 |
;no_com1 db 13,10,186, " Keine COM1 Maus",0 |
;no_com2 db 13,10,186, " Keine COM2 Maus",0 |
;ask_dma db "Nutze DMA zum HDD Zugriff? [1-ja, 2-allein fur Lesen, 3-nein]: ",0 |
ask_bd db "Add disks visible by BIOS emulated in V86-mode? [1-yes, 2-no]: ",0 |
;gr_direct db 186," Benutze direct LFB? " |
; db "[1-ja/2-nein] ? ",0 |
;mem_model db 13,10,186," Hauptspeicher [1-16 Mb / 2-32 Mb / " |
; db "3-64Mb / 4-128 Mb / 5-256 Mb] ? ",0 |
;bootlog db 13,10,186," After bootlog display [1-continue/2-pause] ? ",0 |
bdev db "Lade die Ramdisk von [1-Diskette; 2-C:\kolibri.img (FAT32);" |
db 13,10,186," " |
db "3-benutze ein bereits geladenes Kernel image;" |
db 13,10,186," " |
db "4-create blank image]: ",0 |
probetext db 13,10,13,10,186," Nutze Standardgrafikmodi? [1-ja, " |
db "2-BIOS Test (Vesa 3.0)]: ",0 |
;memokz256 db 13,10,186," RAM 256 Mb",0 |
;memokz128 db 13,10,186," RAM 128 Mb",0 |
;memokz64 db 13,10,186," RAM 64 Mb",0 |
;memokz32 db 13,10,186," RAM 32 Mb",0 |
;memokz16 db 13,10,186," RAM 16 Mb",0 |
prnotfnd db "Fatal - Videomodus nicht gefunden.",0 |
;modena db "Fatal - VBE 0x112+ required.",0 |
not386 db "Fatal - CPU 386+ benoetigt.",0 |
btns db "Fatal - konnte Farbtiefe nicht erkennen.",0 |
fatalsel db "Fatal - Grafikmodus nicht unterstuetzt.",0 |
badsect db 13,10,186," Fatal - Sektorfehler, Andere Diskette neutzen.",0 |
memmovefailed db 13,10,186," Fatal - Int 0x15 Fehler.",0 |
okt db " ... OK" |
linef db 13,10,0 |
diskload db "Lade Diskette: 00 %",8,8,8,8,0 |
pros db "00" |
backspace2 db 8,8,0 |
boot_dev db 0 ; 0=floppy, 1=hd |
start_msg db "Druecke [abcd], um die Einstellungen zu aendern , druecke [Enter] zum starten",13,10,0 |
time_msg db " oder warte " |
time_str db " 5 Sekunden" |
db " bis zum automatischen Start",13,10,0 |
current_cfg_msg db "Aktuelle Einstellungen:",13,10,0 |
curvideo_msg db " [a] Videomodus: ",0 |
mode1 db "640x480",0 |
mode2 db "800x600",0 |
mode3 db "1024x768",0 |
mode4 db "1280x1024",0 |
modes_msg dw mode4,mode1,mode2,mode3 |
modevesa20 db " mit LFB",0 |
modevesa12 db ", VESA 1.2 Bnk",0 |
mode9 db "320x200, EGA/CGA 256 colors",0 |
mode10 db "640x480, VGA 16 colors",0 |
probeno_msg db " (Standard Modus)",0 |
probeok_msg db " (teste nicht-standard Modi)",0 |
;dma_msg db " [b] Nutze DMA zum HDD Aufschreiben:",0 |
usebd_msg db " [b] Add disks visible by BIOS:",0 |
on_msg db " an",13,10,0 |
off_msg db " aus",13,10,0 |
;readonly_msg db " fur Lesen",13,10,0 |
vrrm_msg db " [c] Nutze VRR:",0 |
preboot_device_msg db " [d] Diskettenimage: ",0 |
preboot_device_msgs dw 0,pdm1,pdm2,pdm3 |
pdm1 db "Echte Diskette",13,10,0 |
pdm2 db "C:\kolibri.img (FAT32)",13,10,0 |
pdm3 db "Nutze bereits geladenes Image",13,10,0 |
pdm4 db "create blank image",13,10,0 |
loading_msg db "Lade KolibriOS...",0 |
save_quest db "Aktuelle Einstellungen speichern? [y/n]: ",0 |
loader_block_error db "Bootloader Daten ungueltig, Kann nicht fortfahren. Angehalten.",0 |
remark1 db "Default values were selected to match most of configurations, but not all.",0 |
remark2 db "If you have LCD-monitor, disable VRR in the item [c] - you do not need it.",0 |
remark3 db "If the system does not boot, try to disable the item [b].",0 |
remarks dw remark1, remark2, remark3 |
num_remarks = 3 |
/kernel/branches/Kolibri-acpi/sec_loader/trunk/kolibri_ldm/bootvesa.inc |
---|
0,0 → 1,759 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2007. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
struc VBE_VGAInfo { |
.VESASignature dd ? ; char |
.VESAVersion dw ? ; short |
.OemStringPtr dd ? ; char * |
.Capabilities dd ? ; ulong |
.VideoModePtr dd ? ; ulong |
.TotalMemory dw ? ; short |
; VBE 2.0+ |
.OemSoftwareRev db ? ; short |
.OemVendorNamePtr dw ? ; char * |
.OemProductNamePtr dw ? ; char * |
.OemProductRevPtr dw ? ; char * |
.reserved rb 222 ; char |
.OemData rb 256 ; char |
} |
struc VBE_ModeInfo { |
.ModeAttributes dw ? ; short |
.WinAAttributes db ? ; char |
.WinBAttributes db ? ; char |
.WinGranularity dw ? ; short |
.WinSize dw ? ; short |
.WinASegment dw ? ; ushort |
.WinBSegment dw ? ; ushort |
.WinFuncPtr dd ? ; void * |
.BytesPerScanLine dw ? ; short |
.XRes dw ? ; short |
.YRes dw ? ; short |
.XCharSize db ? ; char |
.YCharSize db ? ; char |
.NumberOfPlanes db ? ; char |
.BitsPerPixel db ? ; char |
.NumberOfBanks db ? ; char |
.MemoryModel db ? ; char |
.BankSize db ? ; char |
.NumberOfImagePages db ? ; char |
.res1 db ? ; char |
.RedMaskSize db ? ; char |
.RedFieldPosition db ? ; char |
.GreenMaskSize db ? ; char |
.GreenFieldPosition db ? ; char |
.BlueMaskSize db ? ; char |
.BlueFieldPosition db ? ; char |
.RsvedMaskSize db ? ; char |
.RsvedFieldPosition db ? ; char |
.DirectColorModeInfo db ? ; char ; MISSED IN THIS TUTORIAL!! SEE ABOVE |
; VBE 2.0+ |
.PhysBasePtr dd ? ; ulong |
.OffScreenMemOffset dd ? ; ulong |
.OffScreenMemSize dw ? ; short |
; VBE 3.0+ |
.LinbytesPerScanLine dw ? ; short |
.BankNumberOfImagePages db ? ; char |
.LinNumberOfImagePages db ? ; char |
.LinRedMaskSize db ? ; char |
.LinRedFieldPosition db ? ; char |
.LingreenMaskSize db ? ; char |
.LinGreenFieldPosition db ? ; char |
.LinBlueMaskSize db ? ; char |
.LinBlueFieldPosition db ? ; char |
.LinRsvdMaskSize db ? ; char |
.LinRsvdFieldPosition db ? ; char |
.MaxPixelClock dd ? ; ulong |
.res2 rb 190 ; char |
} |
virtual at $A000 |
vi VBE_VGAInfo |
mi VBE_ModeInfo |
modes_table: |
end virtual |
cursor_pos dw 0 ;âðåìåííîå õðàíåíèå êóðñîðà. |
home_cursor dw 0 ;current shows rows a table |
end_cursor dw 0 ;end of position current shows rows a table |
scroll_start dw 0 ;start position of scroll bar |
scroll_end dw 0 ;end position of scroll bar |
long_v_table equ 9 ;long of visible video table |
size_of_step equ 10 |
scroll_area_size equ (long_v_table-2) |
int2str: |
dec bl |
jz @f |
xor edx, edx |
div ecx |
push edx |
call int2str |
pop eax |
@@: |
or al, 0x30 |
mov [ds:di], al |
inc di |
ret |
int2strnz: |
cmp eax, ecx |
jb @f |
xor edx, edx |
div ecx |
push edx |
call int2strnz |
pop eax |
@@: |
or al, 0x30 |
mov [es:di], al |
inc di |
ret |
;------------------------------------------------------- |
;Write message about incorrect v_mode and write message about jmp on swith v_mode |
v_mode_error: |
_setcursor 19,2 |
mov si, fatalsel |
call printplain |
_setcursor 20,2 |
mov si, pres_key |
call printplain |
xor eax, eax |
int 16h |
jmp cfgmanager.d |
;------------------------------------------------------- |
; |
;------------------------------------------------------- |
print_vesa_info: |
_setcursor 5,2 |
mov [es:vi.VESASignature], 'VBE2' |
mov ax, 0x4F00 |
mov di, vi ;0xa000 |
int 0x10 |
or ah, ah |
jz @f |
mov [es:vi.VESASignature], 'VESA' |
mov ax, $4F00 |
mov di, vi |
int 0x10 |
or ah, ah |
jnz .exit |
@@: |
cmp [es:vi.VESASignature], 'VESA' |
jne .exit |
cmp [es:vi.VESAVersion], 0x0100 |
jb .exit |
jmp .vesaok2 |
.exit: |
mov si, novesa |
call printplain |
ret |
.vesaok2: |
mov ax, [es:vi.VESAVersion] |
add ax, '00' |
mov [s_vesa.ver], ah |
mov [s_vesa.ver+2], al |
mov si, s_vesa |
call printplain |
_setcursor 4,2 |
mov si, word[es:vi.OemStringPtr] |
mov di, si |
push ds |
mov ds, word[es:vi.OemStringPtr+2] |
call printplain |
pop ds |
ret |
;----------------------------------------------------------------------------- |
calc_vmodes_table: |
pushad |
; push 0 |
; pop es |
lfs si, [es:vi.VideoModePtr] |
mov bx, modes_table |
;save no vesa mode of work 320x200, EGA/CGA 256 梥⮢ and 640x480, VGA 16 梥⮢ |
mov word [es:bx], 640 |
mov word [es:bx+2], 480 |
mov word [es:bx+6], 0x13 |
mov word [es:bx+10], 640 |
mov word [es:bx+12], 480 |
mov word [es:bx+16], 0x12 |
add bx, 20 |
.next_mode: |
mov cx, word [fs:si]; mode number |
cmp cx, -1 |
je .modes_ok.2 |
mov ax, 0x4F01 |
mov di, mi |
int 0x10 |
or ah, ah |
jnz .modes_ok.2;vesa_info.exit |
test [es:mi.ModeAttributes], 00000001b ;videomode support ? |
jz @f |
test [es:mi.ModeAttributes], 00010000b ;picture ? |
jz @f |
test [es:mi.ModeAttributes], 10000000b ;LFB ? |
jz @f |
cmp [es:mi.BitsPerPixel], 24 ;It show only videomodes to have support 24 and 32 bpp |
jb @f |
; cmp [es:mi.BitsPerPixel],16 |
; jne .l0 |
; cmp [es:mi.GreenMaskSize],5 |
; jne .l0 |
; mov [es:mi.BitsPerPixel],15 |
.l0: |
cmp [es:mi.XRes], 640 |
jb @f |
cmp [es:mi.YRes], 480 |
jb @f |
; cmp [es:mi.BitsPerPixel],8 |
; jb @f |
mov ax, [es:mi.XRes] |
mov [es:bx+0], ax ; +0[2] : resolution X |
mov ax, [es:mi.YRes] |
mov [es:bx+2], ax ; +2[2] : resolution Y |
mov ax, [es:mi.ModeAttributes] |
mov [es:bx+4], ax ; +4[2] : attributes |
cmp [s_vesa.ver], '2' |
jb .lp1 |
or cx, 0x4000 ; use LFB |
.lp1: |
mov [es:bx+6], cx ; +6 : mode number |
movzx ax, byte [es:mi.BitsPerPixel] |
mov word [es:bx+8], ax ; +8 : bits per pixel |
add bx, size_of_step ; size of record |
@@: |
add si, 2 |
jmp .next_mode |
.modes_ok.2: |
mov word[es:bx], -1 ;end video table |
mov word[end_cursor], bx ;save end cursor position |
;;;;;;;;;;;;;;;;;; |
;Sort array |
; mov si,modes_table |
;.new_mode: |
; mov ax,word [es:si] |
; cmp ax,-1 |
; je .exxit |
; add ax,word [es:si+2] |
; add ax,word [es:si+8] |
; mov bp,si |
;.again: |
; add bp,12 |
; mov bx,word [es:bp] |
; cmp bx,-1 |
; je .exit |
; add bx,word [es:bp+2] |
; add bx,word [es:bp+8] |
; |
; cmp ax,bx |
; ja .loops |
; jmp .again |
;.loops: |
; push dword [es:si] |
; push dword [es:si+4] |
; push dword [es:si+8] |
; push dword [es:bp] |
; push dword [es:bp+4] |
; push dword [es:bp+8] |
; |
; pop dword [es:si+8] |
; pop dword [es:si+4] |
; pop dword [es:si] |
; pop dword [es:bp+8] |
; pop dword [es:bp+4] |
; pop dword [es:bp] |
; jmp .new_mode |
; |
;.exit: add si,12 |
; jmp .new_mode |
;.exxit: |
popad |
ret |
;----------------------------------------------------------------------------- |
draw_current_vmode: |
push 0 |
pop es |
mov si, word [cursor_pos] |
cmp word [es:si+6], 0x12 |
je .no_vesa_0x12 |
cmp word [es:si+6], 0x13 |
je .no_vesa_0x13 |
mov di, loader_block_error |
movzx eax, word[es:si+0] |
mov ecx, 10 |
call int2strnz |
mov byte[es:di], 'x' |
inc di |
movzx eax, word[es:si+2] |
call int2strnz |
mov byte[es:di], 'x' |
inc di |
movzx eax, word[es:si+8] |
call int2strnz |
mov dword[es:di], 0x00000d0a |
mov si, loader_block_error |
push ds |
push es |
pop ds |
call printplain |
pop ds |
ret |
.no_vesa_0x13: |
mov si, mode0 |
jmp .print |
.no_vesa_0x12: |
mov si, mode9 |
.print: |
call printplain |
ret |
;----------------------------------------------------------------------------- |
check_first_parm: |
mov si, word [preboot_graph] |
test si, si |
jnz .no_zero ;if no zero |
.zerro: |
; mov ax,modes_table |
; mov word [cursor_pos],ax |
; mov word [home_cursor],ax |
; mov word [preboot_graph],ax |
;SET default video of mode first probe will fined a move of work 1024x768@32 |
mov ax, 1024 |
mov bx, 768 |
mov si, modes_table |
call .loops |
test ax, ax |
jz .ok_found_mode |
mov ax, 800 |
mov bx, 600 |
mov si, modes_table |
call .loops |
test ax, ax |
jz .ok_found_mode |
mov ax, 640 |
mov bx, 480 |
mov si, modes_table |
call .loops |
test ax, ax |
jz .ok_found_mode |
mov si, modes_table |
jmp .ok_found_mode |
.no_zero: |
mov bp, word [number_vm] |
cmp bp, word [es:si+6] |
jz .ok_found_mode |
mov ax, word [x_save] |
mov bx, word [y_save] |
mov si, modes_table |
call .loops |
test ax, ax |
jz .ok_found_mode |
mov si, modes_table |
; cmp ax,modes_table |
; jb .zerro ;check on correct if bellow |
; cmp ax,word [end_cursor] |
; ja .zerro ;check on correct if anymore |
.ok_found_mode: |
mov word [home_cursor], si |
; mov word [cursor_pos],si |
mov word [preboot_graph], si |
mov ax, si |
mov ecx, long_v_table |
.loop: |
add ax, size_of_step |
cmp ax, word [end_cursor] |
jae .next_step |
loop .loop |
.next_step: |
sub ax, size_of_step*long_v_table |
cmp ax, modes_table |
jae @f |
mov ax, modes_table |
@@: |
mov word [home_cursor], ax |
mov si, [preboot_graph] |
mov word [cursor_pos], si |
push word [es:si] |
pop word [x_save] |
push word [es:si+2] |
pop word [y_save] |
push word [es:si+6] |
pop word [number_vm] |
ret |
;;;;;;;;;;;;;;;;;;;;;;;;;;; |
.loops: |
cmp ax, word [es:si] |
jne .next |
cmp bx, word [es:si+2] |
jne .next |
cmp word [es:si+8], 32 |
je .ok |
cmp word [es:si+8], 24 |
je .ok |
.next: |
add si, size_of_step |
cmp word [es:si], -1 |
je .exit |
jmp .loops |
.ok: |
xor ax, ax |
ret |
.exit: |
or ax, -1 |
ret |
;----------------------------------------------------------------------------- |
;default_vmode: |
;----------------------------------------------------------------------------- |
draw_vmodes_table: |
_setcursor 9, 2 |
mov si, gr_mode |
call printplain |
mov si, _st |
call printplain |
push word [cursor_pos] |
pop ax |
push word [home_cursor] |
pop si |
mov cx, si |
cmp ax, si |
je .ok |
jb .low |
add cx, size_of_step*long_v_table |
cmp ax, cx |
jb .ok |
sub cx, size_of_step*long_v_table |
add cx, size_of_step |
cmp cx, word[end_cursor] |
jae .ok |
add si, size_of_step |
push si |
pop word [home_cursor] |
jmp .ok |
.low: |
sub cx, size_of_step |
cmp cx, modes_table |
jb .ok |
push cx |
push cx |
pop word [home_cursor] |
pop si |
.ok: |
; calculate scroll position |
push si |
mov ax, [end_cursor] |
sub ax, modes_table |
mov bx, size_of_step |
cwd |
div bx |
mov si, ax ; si = size of list |
mov ax, [home_cursor] |
sub ax, modes_table |
cwd |
div bx |
mov di, ax |
mov ax, scroll_area_size*long_v_table |
cwd |
div si |
test ax, ax |
jnz @f |
inc ax |
@@: |
cmp al, scroll_area_size |
jb @f |
mov al, scroll_area_size |
@@: |
mov cx, ax |
; cx = scroll height |
; calculate scroll pos |
xor bx, bx ; initialize scroll pos |
sub al, scroll_area_size+1 |
neg al |
sub si, long_v_table-1 |
jbe @f |
mul di |
div si |
mov bx, ax |
@@: |
inc bx |
imul ax, bx, size_of_step |
add ax, [home_cursor] |
mov [scroll_start], ax |
imul cx, size_of_step |
add ax, cx |
mov [scroll_end], ax |
pop si |
mov bp, long_v_table ;show rows |
.@@_next_bit: |
;clear cursor |
mov ax, ' ' |
mov word[ds:_r1+21], ax |
mov word[ds:_r1+50], ax |
mov word[ds:_r2+21], ax |
mov word[ds:_r2+45], ax |
mov word[ds:_rs+21], ax |
mov word[ds:_rs+46], ax |
; draw string |
cmp word [es:si+6], 0x12 |
je .show_0x12 |
cmp word [es:si+6], 0x13 |
je .show_0x13 |
movzx eax, word[es:si] |
cmp ax, -1 |
je .@@_end |
mov di, _rs+23 |
mov ecx, 10 |
mov bl, 4 |
call int2str |
movzx eax, word[es:si+2] |
inc di |
mov bl, 4 |
call int2str |
movzx eax, word[es:si+8] |
inc di |
mov bl, 2 |
call int2str |
cmp si, word [cursor_pos] |
jne .next |
;draw cursor |
mov word[ds:_rs+21], '>>' |
mov word[ds:_rs+46], '<<' |
.next: |
push si |
mov si, _rs |
.@@_sh: |
; add to the string pseudographics for scrollbar |
pop bx |
push bx |
mov byte [si+53], ' ' |
cmp bx, [scroll_start] |
jb @f |
cmp bx, [scroll_end] |
jae @f |
mov byte [si+53], 0xDB ; filled bar |
@@: |
push bx |
add bx, size_of_step |
cmp bx, [end_cursor] |
jnz @f |
mov byte [si+53], 31 ; 'down arrow' symbol |
@@: |
sub bx, [home_cursor] |
cmp bx, size_of_step*long_v_table |
jnz @f |
mov byte [si+53], 31 ; 'down arrow' symbol |
@@: |
pop bx |
cmp bx, [home_cursor] |
jnz @f |
mov byte [si+53], 30 ; 'up arrow' symbol |
@@: |
call printplain |
pop si |
add si, size_of_step |
dec bp |
jnz .@@_next_bit |
.@@_end: |
mov si, _bt |
call printplain |
ret |
.show_0x13: |
push si |
cmp si, word [cursor_pos] |
jne @f |
mov word[ds:_r1+21], '>>' |
mov word[ds:_r1+50], '<<' |
@@: |
mov si, _r1 |
jmp .@@_sh |
.show_0x12: |
push si |
cmp si, word [cursor_pos] |
jne @f |
mov word[ds:_r2+21], '>>' |
mov word[ds:_r2+45], '<<' |
@@: |
mov si, _r2 |
jmp .@@_sh |
;----------------------------------------------------------------------------- |
;Clear arrea of current video page (0xb800) |
clear_vmodes_table: |
pusha |
; draw frames |
push es |
push 0xb800 |
pop es |
mov di, 1444 |
xor ax, ax |
mov ah, 1*16+15 |
mov cx, 70 |
mov bp, 12 |
.loop_start: |
rep stosw |
mov cx, 70 |
add di, 20 |
dec bp |
jns .loop_start |
pop es |
popa |
ret |
;----------------------------------------------------------------------------- |
set_vmode: |
push 0 ;0;x1000 |
pop es |
mov si, word [preboot_graph] ;[preboot_graph] |
mov cx, word [es:si+6] ; number of mode |
mov ax, word [es:si+0] ; resolution X |
mov bx, word [es:si+2] ; resolution Y |
mov word [es:BOOT_X_RES], ax ; resolution X |
mov word [es:BOOT_Y_RES], bx ; resolution Y |
mov word [es:BOOT_VESA_MODE], cx ; number of mode |
cmp cx, 0x12 |
je .mode0x12_0x13 |
cmp cx, 0x13 |
je .mode0x12_0x13 |
cmp byte [s_vesa.ver], '2' |
jb .vesa12 |
; VESA 2 and Vesa 3 |
mov ax, 0x4f01 |
and cx, 0xfff |
mov di, mi;0xa000 |
int 0x10 |
; LFB |
mov eax, [es:mi.PhysBasePtr];di+0x28] |
mov [es:BOOT_LFB], eax |
; ---- vbe voodoo |
BytesPerLine equ 0x10 |
mov ax, [es:di+BytesPerLine] |
mov [es:BOOT_PITCH], ax |
; BPP |
cmp [es:mi.BitsPerPixel], 16 |
jne .l0 |
cmp [es:mi.GreenMaskSize], 5 |
jne .l0 |
mov [es:mi.BitsPerPixel], 15 |
.l0: |
mov al, byte [es:di+0x19] |
mov [es:BOOT_BPP], al |
jmp .exit |
.mode0x12_0x13: |
mov byte [es:BOOT_BPP], 32 |
or dword [es:BOOT_LFB], 0xFFFFFFFF; 0x800000 |
; VESA 1.2 PM BANK SWITCH ADDRESS |
.vesa12: |
mov ax, 0x4f0A |
xor bx, bx |
int 0x10 |
xor eax, eax |
xor ebx, ebx |
mov ax, es |
shl eax, 4 |
mov bx, di |
add eax, ebx |
movzx ebx, word[es:di] |
add eax, ebx |
push 0x0000 |
pop es |
mov [es:0x9014], eax |
.exit: |
ret |
;============================================================================= |
;============================================================================= |
;============================================================================= |
/kernel/branches/Kolibri-acpi/sec_loader/trunk/kolibri_ldm/kolibri_ldm.asm |
---|
0,0 → 1,814 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Last modify Alexey Teplov <Lrz> 2008. All rights reserved. ;; |
;; Copyright (C) KolibriOS team 2004-2007. All rights reserved. ;; |
;; Copyright (C) MenuetOS 2000-2004 Ville Mikael Turjanmaa ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; kolibri_ldm.asm the module for Secondary Loader ;; |
;; ;; |
;; KolibriOS 16-bit loader module, ;; |
;; based on bootcode for KolibriOS ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
include "lang.inc" |
macro _setcursor row,column |
{ |
mov dx, row*256 + column |
call setcursor |
} |
long_v_table equ 9 ;long of visible video table |
size_of_step equ 10 |
d80x25_bottom_num equ 3 |
d80x25_top_num equ 4 |
;It's a module for Secondary Loader to load kolibri OS |
; |
start_of_code: |
cld |
; \begin{diamond}[02.12.2005] |
; if bootloader sets ax = 'KL', then ds:si points to loader block |
; cmp ax, 'KL' |
; jnz @f |
; mov word [cs:cfgmanager.loader_block], si |
; mov word [cs:cfgmanager.loader_block+2], ds |
;@@: |
; \end{diamond}[02.12.2005] |
; if bootloader sets cx = 'HA' and dx = 'RD', then bx contains identifier of source hard disk |
; (see comment to bx_from_load) |
; cmp cx, 'HA' |
; jnz no_hd_load |
; cmp dx,'RD' |
; jnz no_hd_load |
; mov word [cs:bx_from_load], bx ; {SPraid}[13.03.2007] |
;no_hd_load: |
; set up stack |
push cs |
pop ss |
xor ax, ax |
mov sp, ax |
; mov ax, 3000h |
; mov ss, ax |
; mov sp, 0EC00h |
; set up segment registers |
push cs |
pop ds |
push cs |
pop es |
; set videomode |
mov ax, 3 |
int 0x10 |
;if lang eq ru |
; Load & set russian VGA font (RU.INC) |
mov bp, RU_FNT1 ; RU_FNT1 - First part |
mov bx, 1000h ; 768 bytes |
mov cx, 30h ; 48 symbols |
mov dx, 80h ; 128 - position of first symbol |
mov ax, 1100h |
int 10h |
mov bp, RU_FNT2 ; RU_FNT2 -Second part |
mov bx, 1000h ; 512 bytes |
mov cx, 20h ; 32 symbols |
mov dx, 0E0h ; 224 - position of first symbol |
mov ax, 1100h |
int 10h |
; End set VGA russian font |
;else if lang eq et |
; mov bp, ET_FNT ; ET_FNT1 |
; mov bx, 1000h ; |
; mov cx, 255 ; 256 symbols |
; xor dx, dx ; 0 - position of first symbol |
; mov ax, 1100h |
; int 10h |
;end if |
; draw frames |
push 0xb800 |
pop es |
xor di, di |
mov ah, 1*16+15 |
; draw top |
mov si, d80x25_top |
mov cx, d80x25_top_num * 80 |
@@: |
lodsb |
stosw |
loop @b |
; draw spaces |
mov si, space_msg |
mov dx, 25 - d80x25_top_num - d80x25_bottom_num |
dfl1: |
push si |
mov cx, 80 |
@@: |
lodsb |
stosw |
loop @b |
pop si |
dec dx |
jnz dfl1 |
; draw bottom |
mov si, d80x25_bottom |
mov cx, d80x25_bottom_num * 80 |
@@: |
lodsb |
stosw |
loop @b |
mov byte [space_msg+80], 0 ; now space_msg is null terminated |
_setcursor d80x25_top_num,0 |
; TEST FOR 386+ |
mov bx, 0x4000 |
pushf |
pop ax |
mov dx, ax |
xor ax, bx |
push ax |
popf |
pushf |
pop ax |
and ax, bx |
and dx, bx |
cmp ax, dx |
jnz cpugood |
mov si, not386 |
sayerr: |
call print |
jmp $ |
cpugood: |
push 0 |
popf |
sti |
; set up esp |
movzx esp, sp |
push 0 |
pop es |
and word [es:BOOT_IDE_BASE_ADDR], 0 |
; \begin{Mario79} |
; find HDD IDE DMA PCI device |
; check for PCI BIOS |
mov ax, 0xB101 |
int 0x1A |
jc .nopci |
cmp edx, 'PCI ' |
jnz .nopci |
; find PCI class code |
; class 1 = mass storage |
; subclass 1 = IDE controller |
; a) class 1, subclass 1, programming interface 0x80 |
mov ax, 0xB103 |
mov ecx, 1*10000h + 1*100h + 0x80 |
xor si, si ; device index = 0 |
int 0x1A |
jnc .found |
; b) class 1, subclass 1, programming interface 0x8A |
mov ax, 0xB103 |
mov ecx, 1*10000h + 1*100h + 0x8A |
xor si, si ; device index = 0 |
int 0x1A |
jnc .found |
; c) class 1, subclass 1, programming interface 0x85 |
mov ax, 0xB103 |
mov ecx, 1*10000h + 1*100h + 0x85 |
xor si, si |
int 0x1A |
jc .nopci |
.found: |
; get memory base |
mov ax, 0xB10A |
mov di, 0x20 ; memory base is config register at 0x20 |
int 0x1A |
jc .nopci |
and cx, 0xFFF0 ; clear address decode type |
mov [es:BOOT_IDE_BASE_ADDR], cx |
.nopci: |
; \end{Mario79} |
mov al, 0xf6 ; Ñáðîñ êëàâèàòóðû, ðàçðåøèòü ñêàíèðîâàíèå |
out 0x60, al |
xor cx, cx |
wait_loop: ; variant 2 |
; reading state of port of 8042 controller |
in al, 64h |
and al, 00000010b ; ready flag |
; wait until 8042 controller is ready |
loopnz wait_loop |
;;;/diamond today 5.02.2008 |
; set keyboard typematic rate & delay |
mov al, 0xf3 |
out 0x60, al |
xor cx, cx |
@@: |
in al, 64h |
test al, 2 |
loopnz @b |
mov al, 0 |
out 0x60, al |
xor cx, cx |
@@: |
in al, 64h |
test al, 2 |
loopnz @b |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
; --------------- APM --------------------- |
and word [es:BOOT_APM_VERSION], 0 ; ver = 0.0 (APM not found) |
mov ax, 0x5300 |
xor bx, bx |
int 0x15 |
jc apm_end ; APM not found |
test cx, 2 |
jz apm_end ; APM 32-bit protected-mode interface not supported |
mov [es:BOOT_APM_VERSION], ax ; Save APM Version |
mov [es:BOOT_APM_FLAGS], cx ; Save APM flags |
; Write APM ver ---- |
and ax, 0xf0f |
add ax, '00' |
mov si, msg_apm |
mov [si + 5], ah |
mov [si + 7], al |
_setcursor 0, 3 |
call printplain |
; ------------------ |
mov ax, 0x5304 ; Disconnect interface |
xor bx, bx |
int 0x15 |
mov ax, 0x5303 ; Connect 32 bit mode interface |
xor bx, bx |
int 0x15 |
mov [es:BOOT_APM_ENTRY], ebx |
mov [es:BOOT_APM_CODE_32], ax |
mov [es:BOOT_APM_CODE_16], cx |
mov [es:BOOT_APM_DATA_16], dx |
apm_end: |
_setcursor d80x25_top_num, 0 |
;CHECK current of code |
cmp [cfgmanager.loader_block], -1 |
jz noloaderblock |
les bx, [cfgmanager.loader_block] |
cmp byte [es:bx], 1 |
mov si, loader_block_error |
jnz sayerr |
push 0 |
pop es |
noloaderblock: |
; DISPLAY VESA INFORMATION |
call print_vesa_info |
call calc_vmodes_table |
call check_first_parm ;check and enable cursor_pos |
; \begin{diamond}[30.11.2005] |
cfgmanager: |
; settings: |
; a) preboot_graph = graphical mode |
; preboot_gprobe = probe this mode? |
; b) preboot_dma = use DMA access? |
; c) preboot_vrrm = use VRR? |
; determine default settings |
mov [.bSettingsChanged], 0 |
;.preboot_gr_end: |
mov di, preboot_device |
; if image in memory is present and [preboot_device] is uninitialized, |
; set it to use this preloaded image |
cmp byte [di], 0 |
jnz .preboot_device_inited |
cmp [.loader_block], -1 |
jz @f |
les bx, [.loader_block] |
test byte [es:bx+1], 1 |
jz @f |
mov byte [di], 3 |
jmp .preboot_device_inited |
@@: |
; otherwise, set [preboot_device] to 1 (default value - boot from floppy) |
mov byte [di], 1 |
.preboot_device_inited: |
; following 6 lines set variables to 1 if its current value is 0 |
cmp byte [di+preboot_dma-preboot_device], 1 |
adc byte [di+preboot_dma-preboot_device], 0 |
cmp byte [di+preboot_biosdisk-preboot_device], 1 |
adc byte [di+preboot_biosdisk-preboot_device], 0 |
cmp byte [di+preboot_vrrm-preboot_device], 1 |
adc byte [di+preboot_vrrm-preboot_device], 0 |
; notify user |
_setcursor 5,2 |
mov si, linef |
call printplain |
mov si, start_msg |
call print |
mov si, time_msg |
call print |
; get start time |
call .gettime |
mov [.starttime], eax |
mov word [.timer], .newtimer |
mov word [.timer+2], cs |
.printcfg: |
_setcursor 9,0 |
mov si, current_cfg_msg |
call print |
mov si, curvideo_msg |
call print |
call draw_current_vmode |
mov si, usebd_msg |
cmp [preboot_biosdisk], 1 |
call .say_on_off |
mov si, vrrm_msg |
cmp [preboot_vrrm], 1 |
call .say_on_off |
; mov si, preboot_device_msg |
; call print |
; mov al, [preboot_device] |
; and eax, 7 |
; mov si, [preboot_device_msgs+eax*2] |
; call printplain |
.show_remarks: |
; show remarks in gray color |
mov di, ((21-num_remarks)*80 + 2)*2 |
push 0xB800 |
pop es |
mov cx, num_remarks |
mov si, remarks |
.write_remarks: |
lodsw |
push si |
xchg ax, si |
mov ah, 1*16+7 ; background: blue (1), foreground: gray (7) |
push di |
.write_remark: |
lodsb |
test al, al |
jz @f |
stosw |
jmp .write_remark |
@@: |
pop di |
pop si |
add di, 80*2 |
loop .write_remarks |
.wait: |
_setcursor 25,0 ; out of screen |
; set timer interrupt handler |
cli |
push 0 |
pop es |
push dword [es:8*4] |
pop dword [.oldtimer] |
push dword [.timer] |
pop dword [es:8*4] |
; mov eax, [es:8*4] |
; mov [.oldtimer], eax |
; mov eax, [.timer] |
; mov [es:8*4], eax |
sti |
; wait for keypressed |
xor ax, ax |
int 16h |
push ax |
; restore timer interrupt |
; push 0 |
; pop es |
mov eax, [.oldtimer] |
mov [es:8*4], eax |
mov [.timer], eax |
_setcursor 7,0 |
mov si, space_msg |
call printplain |
; clear remarks and restore normal attributes |
push es |
mov di, ((21-num_remarks)*80 + 2)*2 |
push 0xB800 |
pop es |
mov cx, num_remarks |
mov ax, ' ' + (1*16 + 15)*100h |
@@: |
push cx |
mov cx, 76 |
rep stosw |
pop cx |
add di, 4*2 |
loop @b |
pop es |
pop ax |
; switch on key |
cmp al, 13 |
jz .continue |
or al, 20h |
cmp al, 'a' |
jz .change_a |
cmp al, 'b' |
jz .change_b |
cmp al, 'c' |
jnz .show_remarks |
_setcursor 15,0 |
mov si, vrrmprint |
call print |
mov bx, '12' |
call getkey |
mov [preboot_vrrm], al |
_setcursor 12,0 |
.d: |
mov [.bSettingsChanged], 1 |
call clear_vmodes_table ;clear vmodes_table |
jmp .printcfg |
.change_a: |
.loops: |
call draw_vmodes_table |
_setcursor 25,0 ; out of screen |
xor ax, ax |
int 0x16 |
; call clear_table_cursor ;clear current position of cursor |
mov si, word [cursor_pos] |
cmp ah, 0x48;x,0x48E0 ; up |
jne .down |
cmp si, modes_table |
jbe .loops |
sub word [cursor_pos], size_of_step |
jmp .loops |
.down: |
cmp ah, 0x50;x,0x50E0 ; down |
jne .pgup |
cmp word[es:si+10], -1 |
je .loops |
add word [cursor_pos], size_of_step |
jmp .loops |
.pgup: |
cmp ah, 0x49 ; page up |
jne .pgdn |
sub si, size_of_step*long_v_table |
cmp si, modes_table |
jae @f |
mov si, modes_table |
@@: |
mov word [cursor_pos], si |
mov si, word [home_cursor] |
sub si, size_of_step*long_v_table |
cmp si, modes_table |
jae @f |
mov si, modes_table |
@@: |
mov word [home_cursor], si |
jmp .loops |
.pgdn: |
cmp ah, 0x51 ; page down |
jne .enter |
mov ax, [end_cursor] |
add si, size_of_step*long_v_table |
cmp si, ax |
jb @f |
mov si, ax |
sub si, size_of_step |
@@: |
mov word [cursor_pos], si |
mov si, word [home_cursor] |
sub ax, size_of_step*long_v_table |
add si, size_of_step*long_v_table |
cmp si, ax |
jb @f |
mov si, ax |
@@: |
mov word [home_cursor], si |
jmp .loops |
.enter: |
cmp al, 0x0D;x,0x1C0D ; enter |
jne .loops |
push word [cursor_pos] |
pop bp |
push word [es:bp] |
pop word [x_save] |
push word [es:bp+2] |
pop word [y_save] |
push word [es:bp+6] |
pop word [number_vm] |
mov word [preboot_graph], bp ;save choose |
jmp .d |
.change_b: |
_setcursor 15,0 |
; mov si, ask_dma |
; call print |
; mov bx, '13' |
; call getkey |
; mov [preboot_dma], al |
mov si, ask_bd |
call print |
mov bx, '12' |
call getkey |
mov [preboot_biosdisk], al |
_setcursor 11,0 |
jmp .d |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
.say_on_off: |
pushf |
call print |
mov si, on_msg |
popf |
jz @f |
mov si, off_msg |
@@: |
jmp printplain |
; novesa and vervesa strings are not used at the moment of executing this code |
virtual at novesa |
.oldtimer dd ? |
.starttime dd ? |
.bSettingsChanged db ? |
.timer dd ? |
end virtual |
.loader_block dd -1 |
.gettime: |
mov ah, 0 |
int 1Ah |
xchg ax, cx |
shl eax, 10h |
xchg ax, dx |
ret |
.newtimer: |
push ds |
push cs |
pop ds |
pushf |
call [.oldtimer] |
pushad |
call .gettime |
sub eax, [.starttime] |
sub ax, 18*5 |
jae .timergo |
neg ax |
add ax, 18-1 |
mov bx, 18 |
xor dx, dx |
div bx |
if lang eq ru |
; ¯®¤®¦¤¨â¥ 5 ᥪã¤, 4/3/2 ᥪã¤ë, 1 ᥪã¤ã |
cmp al, 5 |
mov cl, ' ' |
jae @f |
cmp al, 1 |
mov cl, 'ã' |
jz @f |
mov cl, 'ë' |
@@: |
mov [time_str+9], cl |
else if lang eq et |
cmp al, 1 |
ja @f |
mov [time_str+9], ' ' |
mov [time_str+10], ' ' |
@@: |
else |
; wait 5/4/3/2 seconds, 1 second |
cmp al, 1 |
mov cl, 's' |
ja @f |
mov cl, ' ' |
@@: |
mov [time_str+9], cl |
end if |
add al, '0' |
mov [time_str+1], al |
mov si, time_msg |
_setcursor 7,0 |
call print |
_setcursor 25,0 |
popad |
pop ds |
iret |
.timergo: |
push 0 |
pop es |
mov eax, [.oldtimer] |
mov [es:8*4], eax |
mov sp, 0EC00h |
.continue: |
sti |
_setcursor 6,0 |
mov si, space_msg |
call printplain |
call printplain |
_setcursor 6,0 |
mov si, loading_msg |
call print |
_setcursor 15,0 |
cmp [.bSettingsChanged], 0 |
jz .load |
cmp [.loader_block], -1 |
jz .load |
les bx, [.loader_block] |
mov eax, [es:bx+3] |
push ds |
pop es |
test eax, eax |
jz .load |
push eax |
mov si, save_quest |
call print |
.waityn: |
mov ah, 0 |
int 16h |
or al, 20h |
cmp al, 'n' |
jz .loadc |
cmp al, 'y' |
jnz .waityn |
call putchar |
mov byte [space_msg+80], 186 |
pop eax |
push cs |
push .cont |
push eax |
retf |
.loadc: |
pop eax |
.cont: |
push cs |
pop ds |
mov si, space_msg |
mov byte [si+80], 0 |
_setcursor 15,0 |
call printplain |
_setcursor 15,0 |
.load: |
; \end{diamond}[02.12.2005] |
; ASK GRAPHICS MODE |
call set_vmode |
; GRAPHICS ACCELERATION |
; force yes |
mov [es:BOOT_MTRR], byte 1 |
; DMA ACCESS TO HD |
mov al, [preboot_dma] |
mov [es:BOOT_DMA], al |
; VRR_M USE |
; mov al, [preboot_vrrm] |
; mov [es:0x9030], al |
; BOOT DEVICE |
mov al, [preboot_device] |
dec al |
mov [boot_dev], al |
;;;;;;;;;;; set videomode |
xor ax, ax |
mov es, ax |
mov ax, [es:BOOT_VESA_MODE] ; vga & 320x200 |
mov bx, ax |
cmp ax, 0x13 |
je setgr |
cmp ax, 0x12 |
je setgr |
mov ax, 0x4f02 ; Vesa |
setgr: |
int 0x10 |
test ah, ah |
mov si, fatalsel |
jnz v_mode_error |
; set mode 0x12 graphics registers: |
cmp bx, 0x12 |
jne gmok2 |
mov al, 0x05 |
mov dx, 0x03ce |
push dx |
out dx, al ; select GDC mode register |
mov al, 0x02 |
inc dx |
out dx, al ; set write mode 2 |
mov al, 0x02 |
mov dx, 0x03c4 |
out dx, al ; select VGA sequencer map mask register |
mov al, 0x0f |
inc dx |
out dx, al ; set mask for all planes 0-3 |
mov al, 0x08 |
pop dx |
out dx, al ; select GDC bit mask register |
; for writes to 0x03cf |
gmok2: |
push ds |
pop es |
jmp $ |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;data |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
include "lang.inc" |
include "bootstr.inc" ; language-independent boot messages |
;if lang eq en |
;include "booteng.inc" ; english system boot messages |
;else if lang eq ru |
include "bootru.inc" ; russian system boot messages |
include "ru.inc" ; Russian font |
;else if lang eq et |
;include "bootet.inc" ; estonian system boot messages |
;include "et.inc" ; Estonian font |
;else |
;include "bootge.inc" ; german system boot messages |
;end if |
include 'macros.inc' |
include 'bootvesa.inc' |
include "preboot.inc" |
setcursor: |
; in: dl=column, dh=row |
mov ah, 2 |
mov bh, 0 |
int 10h |
ret |
putchar: |
; in: al=character |
mov ah, 0Eh |
mov bh, 0 |
int 10h |
ret |
print: |
; in: si->string |
mov al, 186 |
call putchar |
mov al, ' ' |
call putchar |
printplain: |
; in: si->string |
pusha |
lodsb |
@@: |
call putchar |
lodsb |
cmp al, 0 |
jnz @b |
popa |
ret |
getkey: |
; get number in range [bl,bh] (bl,bh in ['0'..'9']) |
; in: bx=range |
; out: ax=digit (1..9, 10 for 0) |
mov ah, 0 |
int 16h |
cmp al, bl |
jb getkey |
cmp al, bh |
ja getkey |
push ax |
call putchar |
pop ax |
and ax, 0Fh |
jnz @f |
mov al, 10 |
@@: |
ret |
/kernel/branches/Kolibri-acpi/sec_loader/trunk/kolibri_ldm/macros.inc |
---|
0,0 → 1,86 |
; structure definition helper |
macro struct name, [arg] |
{ |
common |
name@struct equ name |
struc name arg { |
} |
macro struct_helper name |
{ |
match xname,name |
\{ |
virtual at 0 |
xname xname |
sizeof.#xname = $ - xname |
name equ sizeof.#xname |
end virtual |
\} |
} |
ends fix } struct_helper name@struct |
;// mike.dld, 2006-29-01 [ |
; macros definition |
macro diff16 title,l1,l2 |
{ |
local s,d |
s = l2-l1 |
display title,': 0x' |
repeat 16 |
d = 48 + s shr ((16-%) shl 2) and $0F |
if d > 57 |
d = d + 65-57-1 |
end if |
display d |
end repeat |
display 13,10 |
} |
macro diff10 title,l1,l2 |
{ |
local s,d,z,m |
s = l2-l1 |
z = 0 |
m = 1000000000 |
display title,': ' |
repeat 10 |
d = '0' + s / m |
s = s - (s/m)*m |
m = m / 10 |
if d <> '0' |
z = 1 |
end if |
if z <> 0 |
display d |
end if |
end repeat |
display 13,10 |
} |
; \begin{diamond}[29.09.2006] |
; may be useful for kernel debugging |
; example 1: |
; dbgstr 'Hello, World!' |
; example 2: |
; dbgstr 'Hello, World!', save_flags |
macro dbgstr string*, f |
{ |
local a |
iglobal_nested |
a db 'K : ',string,13,10,0 |
endg_nested |
if ~ f eq |
pushfd |
end if |
push esi |
mov esi, a |
call sys_msg_board_str |
pop esi |
if ~ f eq |
popfd |
end if |
} |
; \end{diamond}[29.09.2006] |
/kernel/branches/Kolibri-acpi/sec_loader/trunk/kolibri_ldm/preboot.inc |
---|
0,0 → 1,36 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2007. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
display_modechg db 0 ; display mode change for text, yes/no (0 or 2) |
; |
; !! Important note !! |
; |
; Must be set to 2, to avoid two screenmode |
; changes within a very short period of time. |
display_atboot db 0 ; show boot screen messages ( 2-no ) |
preboot_graph dw 0 ; graph mode |
x_save dw 0 ; x |
y_save dw 0 ; y |
number_vm dw 0 ; |
;pixel_save dw 0 ; per to pixel |
preboot_gprobe db 0 ; probe vesa3 videomodes (1-no, 2-yes) |
preboot_vrrm db 0 ; use VRR_M (1-yes, 2- no) |
preboot_dma db 0 ; use DMA for access to HDD (1-always, 2-only for read, 3-never) |
preboot_device db 0 ; boot device |
; (1-floppy 2-harddisk 3-kernel restart 4-format ram disk) |
;!!!! 0 - autodetect !!!! |
preboot_blogesc = 0 ; start immediately after bootlog |
preboot_biosdisk db 0 ; use V86 to access disks through BIOS (1-yes, 2-no) |
; if $>0x200 |
;ERROR: prebooting parameters must fit in first sector!!! |
; end if |
;hdsysimage db 'KOLIBRI IMG' ; load from |
;image_save db 'KOLIBRI IMG' ; save to |
/kernel/branches/Kolibri-acpi/sec_loader/trunk/kolibri_ldm/bootstr.inc |
---|
0,0 → 1,56 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2007. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
; boot data: common strings (for all languages) |
macro line_full_top { |
db 201 |
times 78 db 205 |
db 187 |
} |
macro line_full_bottom { |
db 200 |
times 78 db 205 |
db 188 |
} |
macro line_half { |
db 186,' ' |
times 76 db 0xc4 |
db ' ',186 |
} |
macro line_space { |
db 186 |
times 78 db 32 |
db 186 |
} |
d80x25_top: |
line_full_top |
cur_line_pos = 75 |
; store byte ' ' at d80x25_top+cur_line_pos+1 |
; store byte ' ' at d80x25_top+cur_line_pos |
; store dword ' SVN' at d80x25_top+cur_line_pos-4 |
space_msg: |
line_space |
;verstr: |
; line_space |
; version string |
; db 186,32 |
; repeat 78 |
; load a byte from version+%-1 |
; if a = 13 |
; break |
; end if |
; db a |
; end repeat |
; repeat 78 - ($-verstr) |
; db ' ' |
; end repeat |
; db 32,186 |
; line_half |
/kernel/branches/Kolibri-acpi/sec_loader/trunk/kolibri_ldm/rdload.inc |
---|
0,0 → 1,123 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2007. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
; READ RAMDISK IMAGE FROM HD |
cmp [boot_dev+OS_BASE+0x10000], 1 |
jne no_sys_on_hd |
test [DRIVE_DATA+1], byte 0x40 |
jz position_2 |
mov [hdbase], 0x1f0 |
mov [hdid], 0x0 |
mov [hdpos], 1 |
mov [fat32part], 0 |
position_1_1: |
inc [fat32part] |
call search_and_read_image |
cmp [image_retrieved], 1 |
je yes_sys_on_hd |
movzx eax, byte [DRIVE_DATA+2] |
cmp [fat32part], eax |
jle position_1_1 |
position_2: |
test [DRIVE_DATA+1], byte 0x10 |
jz position_3 |
mov [hdbase], 0x1f0 |
mov [hdid], 0x10 |
mov [hdpos], 2 |
mov [fat32part], 0 |
position_2_1: |
inc [fat32part] |
call search_and_read_image |
cmp [image_retrieved], 1 |
je yes_sys_on_hd |
movzx eax, byte [DRIVE_DATA+3] |
cmp eax, [fat32part] |
jle position_2_1 |
position_3: |
test [DRIVE_DATA+1], byte 0x4 |
jz position_4 |
mov [hdbase], 0x170 |
mov [hdid], 0x0 |
mov [hdpos], 3 |
mov [fat32part], 0 |
position_3_1: |
inc [fat32part] |
call search_and_read_image |
cmp [image_retrieved], 1 |
je yes_sys_on_hd |
movzx eax, byte [DRIVE_DATA+4] |
cmp eax, [fat32part] |
jle position_3_1 |
position_4: |
test [DRIVE_DATA+1], byte 0x1 |
jz no_sys_on_hd |
mov [hdbase], 0x170 |
mov [hdid], 0x10 |
mov [hdpos], 4 |
mov [fat32part], 0 |
position_4_1: |
inc [fat32part] |
call search_and_read_image |
cmp [image_retrieved], 1 |
je yes_sys_on_hd |
movzx eax, byte [DRIVE_DATA+5] |
cmp eax, [fat32part] |
jle position_4_1 |
jmp yes_sys_on_hd |
search_and_read_image: |
call set_FAT32_variables |
mov edx, bootpath |
call read_image |
test eax, eax |
jz image_present |
mov edx, bootpath2 |
call read_image |
test eax, eax |
jz image_present |
ret |
image_present: |
mov [image_retrieved], 1 |
ret |
read_image: |
mov eax, hdsysimage+OS_BASE+0x10000 |
mov ebx, 1474560/512 |
mov ecx, RAMDISK |
mov esi, 0 |
mov edi, 12 |
call file_read |
ret |
image_retrieved db 0 |
counter_of_partitions db 0 |
no_sys_on_hd: |
; test_to_format_ram_disk (need if not using ram disk) |
cmp [boot_dev+OS_BASE+0x10000], 3 |
jne not_format_ram_disk |
; format_ram_disk |
mov edi, RAMDISK |
mov ecx, 0x1080 |
xor eax, eax |
@@: |
stosd |
loop @b |
mov ecx, 0x58F7F |
mov eax, 0xF6F6F6F6 |
@@: |
stosd |
loop @b |
mov [RAMDISK+0x200], dword 0xFFFFF0 ; fat table |
mov [RAMDISK+0x4200], dword 0xFFFFF0 |
not_format_ram_disk: |
yes_sys_on_hd: |
/kernel/branches/Kolibri-acpi/sec_loader/trunk/kolibri_ldm/shutdown.inc |
---|
0,0 → 1,207 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2007. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; Shutdown for Menuet ;; |
;; ;; |
;; Distributed under General Public License ;; |
;; See file COPYING for details. ;; |
;; Copyright 2003 Ville Turjanmaa ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
pr_mode_exit: |
; setup stack |
mov ax, 0x3000 |
mov ss, ax |
mov esp, 0x0EC00 |
; setup ds |
push cs |
pop ds |
lidt [old_ints_h] |
;remap IRQs |
mov al, 0x11 |
out 0x20, al |
call rdelay |
out 0xA0, al |
call rdelay |
mov al, 0x08 |
out 0x21, al |
call rdelay |
mov al, 0x70 |
out 0xA1, al |
call rdelay |
mov al, 0x04 |
out 0x21, al |
call rdelay |
mov al, 0x02 |
out 0xA1, al |
call rdelay |
mov al, 0x01 |
out 0x21, al |
call rdelay |
out 0xA1, al |
call rdelay |
mov al, 0xB8 |
out 0x21, al |
call rdelay |
mov al, 0xBD |
out 0xA1, al |
sti |
temp_3456: |
xor ax, ax |
mov es, ax |
mov al, byte [es:0x9030] |
cmp al, 1 |
jl nbw |
cmp al, 4 |
jle nbw32 |
nbw: |
in al, 0x60 |
cmp al, 6 |
jae nbw |
mov bl, al |
nbw2: |
in al, 0x60 |
cmp al, bl |
je nbw2 |
cmp al, 240;ax,240 |
jne nbw31 |
mov al, bl |
dec ax |
jmp nbw32 |
nbw31: |
add bl, 128 |
cmp al, bl |
jne nbw |
sub al, 129 |
nbw32: |
dec ax |
dec ax ; 2 = power off |
jnz no_apm_off |
call APM_PowerOff |
jmp $ |
no_apm_off: |
dec ax ; 3 = reboot |
jnz restart_kernel ; 4 = restart kernel |
push 0x40 |
pop ds |
mov word[0x0072], 0x1234 |
jmp 0xF000:0xFFF0 |
rdelay: |
ret |
APM_PowerOff: |
mov ax, 5304h |
xor bx, bx |
int 15h |
;!!!!!!!!!!!!!!!!!!!!!!!! |
mov ax, 0x5300 |
xor bx, bx |
int 0x15 |
push ax |
mov ax, 0x5301 |
xor bx, bx |
int 0x15 |
mov ax, 0x5308 |
mov bx, 1 |
mov cx, bx |
int 0x15 |
mov ax, 0x530E |
xor bx, bx |
pop cx |
int 0x15 |
mov ax, 0x530D |
mov bx, 1 |
mov cx, bx |
int 0x15 |
mov ax, 0x530F |
mov bx, 1 |
mov cx, bx |
int 0x15 |
mov ax, 0x5307 |
mov bx, 1 |
mov cx, 3 |
int 0x15 |
;!!!!!!!!!!!!!!!!!!!!!!!! |
ret |
restart_kernel: |
mov ax, 0x0003 ; set text mode for screen |
int 0x10 |
jmp 0x4000:0000 |
restart_kernel_4000: |
cli |
push ds |
pop es |
mov cx, 0x8000 |
push cx |
push 0x7000 |
pop ds |
xor si, si |
xor di, di |
rep movsw |
pop cx |
mov ds, cx |
push 0x2000 |
pop es |
rep movsw |
push 0x9000 |
pop ds |
push 0x3000 |
pop es |
mov cx, 0xE000/2 |
rep movsw |
wbinvd ; write and invalidate cache |
mov al, 00110100b |
out 43h, al |
jcxz $+2 |
mov al, 0xFF |
out 40h, al |
jcxz $+2 |
out 40h, al |
jcxz $+2 |
sti |
; (hint by Black_mirror) |
; We must read data from keyboard port, |
; because there may be situation when previous keyboard interrupt is lost |
; (due to return to real mode and IRQ reprogramming) |
; and next interrupt will not be generated (as keyboard waits for handling) |
in al, 0x60 |
; bootloader interface |
push 0x1000 |
pop ds |
mov si, kernel_restart_bootblock |
mov ax, 'KL' |
jmp 0x1000:0000 |
/kernel/branches/Kolibri-acpi/sec_loader/trunk/kolibri_ldm/booteng.inc |
---|
0,0 → 1,98 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2007. All rights reserved. ;; |
;; Copyright (C) MenuetOS 2000-2004 Ville Mikael Turjanmaa ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; booteng.asm the module for Secondary Loader ;; |
;; ;; |
;; KolibriOS 16-bit loader module, ;; |
;; based on bootcode for KolibriOS ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;====================================================================== |
; |
; BOOT DATA |
; |
;====================================================================== |
d80x25_bottom: |
db 186,' KolibriOS is based on MenuetOS and comes with ABSOLUTELY ' |
db 'NO WARRANTY ',186 |
db 186,' See file COPYING for details ' |
db ' ',186 |
line_full_bottom |
d80x25_bottom_num = 3 |
msg_apm db " APM x.x ", 0 |
vervesa db "Version of Vesa: Vesa x.x",13,10,0 |
novesa db "Display: EGA/CGA",13,10,0 |
s_vesa db "Version of VESA: " |
.ver db "?.?",13,10,0 |
gr_mode db "Select a videomode: ",13,10,0 |
vrrmprint db "Apply VRR? (picture frequency greater than 60Hz" |
db " only for transfers:",13,10 |
db 186," 1024*768->800*600 and 800*600->640*480) [1-yes,2-no]:",0 |
ask_bd db "Add disks visible by BIOS emulated in V86-mode? [1-yes, 2-no]: ",0 |
bdev db "Load ramdisk from [1-floppy; 2-C:\kolibri.img (FAT32);" |
db 13,10,186," " |
db "3-use preloaded ram-image from kernel restart;" |
db 13,10,186," " |
db "4-create blank image]: ",0 |
probetext db 13,10,13,10,186," Use standart graphics mode? [1-yes, " |
db "2-probe bios (Vesa 3.0)]: ",0 |
prnotfnd db "Fatal - Videomode not found.",0 |
not386 db "Fatal - CPU 386+ required.",0 |
btns db "Fatal - Can't determine color depth.",0 |
fatalsel db "Fatal - Graphics mode not supported by hardware.",0 |
pres_key db "Press any key to choose a new videomode.",0 |
badsect db 13,10,186," Fatal - Bad sector. Replace floppy.",0 |
memmovefailed db 13,10,186," Fatal - Int 0x15 move failed.",0 |
okt db " ... OK" |
linef db 13,10,0 |
diskload db "Loading diskette: 00 %",8,8,8,8,0 |
pros db "00" |
backspace2 db 8,8,0 |
boot_dev db 0 ; 0=floppy, 1=hd |
start_msg db "Press [abc] to change settings, press [Enter] to continue booting",13,10,0 |
time_msg db " or wait " |
time_str db " 5 seconds" |
db " before automatical continuation",13,10,0 |
current_cfg_msg db "Current settings:",13,10,0 |
curvideo_msg db " [a] Videomode: ",0 |
mode0 db "320x200, EGA/CGA 256 colors",13,10,0 |
mode9 db "640x480, VGA 16 colors",13,10,0 |
usebd_msg db " [b] Add disks visible by BIOS:",0 |
on_msg db " on",13,10,0 |
off_msg db " off",13,10,0 |
;readonly_msg db " only for reading",13,10,0 |
vrrm_msg db " [c] Use VRR:",0 |
preboot_device_msg db " [d] Floppy image: ",0 |
preboot_device_msgs dw 0,pdm1,pdm2,pdm3 |
pdm1 db "real floppy",13,10,0 |
pdm2 db "C:\kolibri.img (FAT32)",13,10,0 |
pdm3 db "use already loaded image",13,10,0 |
pdm4 db "create blank image",13,10,0 |
loading_msg db "Loading KolibriOS...",0 |
save_quest db "Remember current settings? [y/n]: ",0 |
loader_block_error db "Bootloader data invalid, I cannot continue. Stopped.",0 |
_st db 186,' ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄ¿',13,10,0 |
_r1 db 186,' ³ 320x200 EGA/CGA 256 colors ³ ³',13,10,0 |
_r2 db 186,' ³ 640x480 VGA 16 colors ³ ³',13,10,0 |
_rs db 186,' ³ ????x????@?? SVGA VESA ³ ³',13,10,0 |
_bt db 186,' ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÙ',13,10,0 |
remark1 db "Default values were selected to match most of configurations, but not all.",0 |
remark2 db "If you have LCD-monitor, disable VRR in the item [c] - you do not need it.",0 |
remark3 db "If the system does not boot, try to disable the item [b].",0 |
remarks dw remark1, remark2, remark3 |
num_remarks = 3 |
/kernel/branches/Kolibri-acpi/sec_loader/trunk/kolibri_ldm/bootru.inc |
---|
0,0 → 1,87 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2008. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;================================================================= |
; |
; BOOT DATA |
; |
;================================================================= |
d80x25_bottom: |
db 186,' Kolibri OS ®á®¢ Menuet OS ¨ ¥ ¯à¥¤®áâ ¢«ï¥â ' |
db '¨ª ª¨å £ àa⨩. ',186 |
db 186,' ®¤à®¡¥¥ ᬮâà¨â¥ ¢ ä ©«¥ COPYING.TXT ' |
db ' ',186 |
line_full_bottom |
msg_apm db " APM x.x ", 0 |
novesa db "¨¤¥®ª àâ : EGA/CGA",13,10,0 |
s_vesa db "¥àá¨ï VESA: " |
.ver db "?.?",13,10,0 |
gr_mode db "ë¡¥à¨â¥ ¢¨¤¥®à¥¦¨¬: ",13,10,0 |
vrrmprint db "ᯮ«ì§®¢ âì VRR? (ç áâ®â ª ¤à®¢ ¢ëè¥ 60 æ" |
db " ⮫쪮 ¤«ï ¯¥à¥å®¤®¢:",13,10 |
db 186," 1024*768>800*600 ¨ 800*600>640*480) [1-¤ , 2-¥â]: ",0 |
;ask_dma db "ᯮ«ì§®¢ âì DMA ¤«ï ¤®áâ㯠ª HDD? [1-¤ , 2-⮫쪮 ç⥨¥, 3-¥â]: ",0 |
ask_bd db "®¡ ¢¨âì ¤¨áª¨, ¢¨¤¨¬ë¥ ç¥à¥§ BIOS ¢ ०¨¬¥ V86? [1-¤ , 2-¥â]: ",0 |
bdev db " £à㧨âì ®¡à § ¨§ [1-¤¨áª¥â ; 2-C:\kolibri.img (FAT32);" |
db 13,10,186," " |
db "3-¨á¯®«ì§®¢ âì 㦥 § £àã¦¥ë© ®¡à §;" |
db 13,10,186," " |
db "4-ᮧ¤ âì ç¨áâë© ®¡à §]: ",0 |
prnotfnd db "訡ª - ¨¤¥®à¥¦¨¬ ¥ ©¤¥.",0 |
not386 db "訡ª - ॡã¥âáï ¯à®æ¥áá®à 386+.",0 |
fatalsel db "訡ª - ë¡à ë© ¢¨¤¥®à¥¦¨¬ ¥ ¯®¤¤¥à¦¨¢ ¥âáï.",0 |
pres_key db " ¦¨¬¨â¥ «î¡ãî ª« ¢¨èã, ¤«ï ¯¥à¥å®¤ ¢ ¢ë¡®à ०¨¬®¢.",0 |
badsect db 13,10,186," 訡ª - ¨áª¥â ¯®¢à¥¦¤¥ . ®¯à®¡ã©â¥ ¤àã£ãî.",0 |
memmovefailed db 13,10,186," 訡ª - Int 0x15 move failed.",0 |
okt db " ... OK" |
linef db 13,10,0 |
diskload db " £à㧪 ¤¨áª¥âë: 00 %",8,8,8,8,0 |
pros db "00" |
backspace2 db 8,8,0 |
boot_dev db 0 |
start_msg db " ¦¬¨â¥ [abc] ¤«ï ¨§¬¥¥¨ï áâ஥ª, [Enter] ¤«ï ¯à®¤®«¦¥¨ï § £à㧪¨",13,10,0 |
time_msg db " ¨«¨ ¯®¤®¦¤¨â¥ " |
time_str db " 5 ᥪ㭤 " |
db " ¤® ¢â®¬ â¨ç¥áª®£® ¯à®¤®«¦¥¨ï",13,10,0 |
current_cfg_msg db "¥ªã騥 áâனª¨:",13,10,0 |
curvideo_msg db " [a] ¨¤¥®à¥¦¨¬: ",0 |
mode0 db "320x200, EGA/CGA 256 梥⮢",13,10,0 |
mode9 db "640x480, VGA 16 梥⮢",13,10,0 |
usebd_msg db " [b] ®¡ ¢¨âì ¤¨áª¨, ¢¨¤¨¬ë¥ ç¥à¥§ BIOS:",0 |
on_msg db " ¢ª«",13,10,0 |
off_msg db " ¢ëª«",13,10,0 |
readonly_msg db " ⮫쪮 ç⥨¥",13,10,0 |
vrrm_msg db " [c] ᯮ«ì§®¢ ¨¥ VRR:",0 |
;preboot_device_msg db " [d] ¡à § ¤¨áª¥âë: ",0 |
;preboot_device_msgs dw 0,pdm1,pdm2,pdm3,pdm4 |
;pdm1 db " áâ®ïé ï ¤¨áª¥â ",13,10,0 |
;pdm2 db "C:\kolibri.img (FAT32)",13,10,0 |
;pdm3 db "¨á¯®«ì§®¢ âì 㦥 § £àã¦¥ë© ®¡à §",13,10,0 |
;pdm4 db "ᮧ¤ âì ç¨áâë© ®¡à §",13,10,0 |
loading_msg db "¤ñâ § £à㧪 KolibriOS...",0 |
save_quest db " ¯®¬¨âì ⥪ã騥 áâனª¨? [y/n]: ",0 |
loader_block_error db "訡ª ¢ ¤ ëå ç «ì®£® § £àã§ç¨ª , ¯à®¤®«¦¥¨¥ ¥¢®§¬®¦®.",0 |
_st db 186,' ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄ¿ ',13,10,0 |
_r1 db 186,' ³ 320x200 EGA/CGA 256 梥⮢ ³ ³ ',13,10,0 |
_r2 db 186,' ³ 640x480 VGA 16 梥⮢ ³ ³ ',13,10,0 |
_rs db 186,' ³ ????x????@?? SVGA VESA ³ ³ ',13,10,0 |
_bt db 186,' ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÙ ',13,10,0 |
remark1 db " ç¥¨ï ¯® 㬮«ç ¨î ¢ë¡à ë ¤«ï 㤮¡á⢠¡®«ìè¨á⢠, ® ¥ ¢á¥å.",0 |
remark2 db " ᫨ ã á LCD-¬®¨â®à, ®âª«îç¨â¥ VRR ¢ ¯ãªâ¥ [c] - ® ¬ ¥ 㦥.",0 |
remark3 db " ᫨ ã á ¥ £à㧨âáï á¨á⥬ , ¯®¯à®¡ã©â¥ ®âª«îç¨âì ¯ãªâ [b].",0 |
remarks dw remark1, remark2, remark3 |
num_remarks = 3 |
/kernel/branches/Kolibri-acpi/sec_loader/trunk/kolibri_ldm/ETFONT.FNT |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/kernel/branches/Kolibri-acpi/sec_loader/trunk/kolibri_ldm/build_ru.bat |
---|
0,0 → 1,89 |
@echo off |
set languages=en ru ge et |
call :Check_Lang %1 |
for %%a in (ru) do if %%a==%target% |
call :Target_%target% |
if ERRORLEVEL 0 goto Exit_OK |
echo There was an error executing script. |
echo For any help, please send a report. |
pause |
goto :eof |
:Check_Lang |
set res=%1 |
:Check_Lang_loop |
for %%a in (%languages%) do if %%a==%res% set lang=%res% |
if defined lang call :make_all goto :eof |
echo Language '%res%' is incorrect |
echo Enter valid language [ %languages% ]: |
set /P res="> |
goto Check_Lang_loop |
goto :eof |
:make_all |
echo *** building module Kolibri.ldm for Secondary Loader with language '%lang%' ... |
if not exist bin mkdir bin |
echo lang fix %lang% > lang.inc |
fasm -m 65536 kolibri_ldm.asm bin\kolibri.ldm |
if not %errorlevel%==0 goto :Error_FasmFailed |
erase lang.inc |
goto Exit_OK |
:Target_all |
call :Target_kernel |
call :Target_drivers |
call :Target_skins |
goto :eof |
:Target_drivers |
echo *** building drivers ... |
if not exist bin\drivers mkdir bin\drivers |
cd drivers |
for %%a in (%drivers%) do ( |
fasm -m 65536 %%a.asm ..\bin\drivers\%%a.obj |
if not %errorlevel%==0 goto :Error_FasmFailed |
) |
cd .. |
move bin\drivers\vmode.obj bin\drivers\vmode.mdr |
goto :eof |
:Target_skins |
echo *** building skins ... |
if not exist bin\skins mkdir bin\skins |
cd skin |
fasm -m 65536 default.asm ..\bin\skins\default.skn |
if not %errorlevel%==0 goto :Error_FasmFailed |
cd .. |
goto :eof |
:Target_clean |
echo *** cleaning ... |
rmdir /S /Q bin |
goto :Exit_OK |
:Error_FasmFailed |
echo error: fasm execution failed |
erase lang.inc |
pause |
exit 1 |
:Exit_OK |
echo all operations has been done |
pause |
exit 0 |
/kernel/branches/Kolibri-acpi/sec_loader/trunk/kolibri_ldm/et.inc |
---|
0,0 → 1,14 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2007. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
; Full ASCII code font |
; only õ and ä added |
; Kaitz |
ET_FNT: |
fontfile file "ETFONT.FNT" |
/kernel/branches/Kolibri-acpi/sec_loader/trunk/kolibri_ldm/ru.inc |
---|
0,0 → 1,100 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2007. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
; Generated by RUFNT.EXE |
; By BadBugsKiller (C) |
; Modifyed by BadBugsKiller 12.01.2004 17:45 |
; Øðèôò óìåíüøåí â ðàçìåðå è òåïåðü ñîñòîèò èç 2-óõ ÷àñòåé, |
; ñîäåðæàùèõ òîëüêî ñèìâîëû ðóññêîãî àëôàâèòà. |
; ñèìâîëû â êîäèðîâêå ASCII (ÄÎÑ'îâñêàÿ), êîäîâàÿ ñòðàíèöà 866. |
RU_FNT1: |
db 0x00, 0x00, 0x1E, 0x36, 0x66, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0xFE, 0x62, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x66, 0xFC, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x66, 0x66, 0xFC, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0xFE, 0x66, 0x62, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x1E, 0x36, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0xFF, 0xC3, 0x81, 0x00, 0x00 |
db 0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0xDB, 0xDB, 0x5A, 0x5A, 0x7E, 0x7E, 0x5A, 0xDB, 0xDB, 0xDB, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x7C, 0xC6, 0x06, 0x06, 0x3C, 0x06, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xCE, 0xDE, 0xF6, 0xE6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00 |
db 0x6C, 0x38, 0xC6, 0xC6, 0xC6, 0xCE, 0xDE, 0xF6, 0xE6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0xE6, 0x66, 0x6C, 0x6C, 0x78, 0x78, 0x6C, 0x6C, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x1F, 0x36, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0xCF, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC0, 0xC0, 0xC0, 0xC0, 0xC2, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0xFF, 0xDB, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x7E, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0x7E, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0xC6, 0xC6, 0x6C, 0x7C, 0x38, 0x38, 0x7C, 0x6C, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xFF, 0x03, 0x03, 0x00, 0x00 |
db 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xFE, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xFF, 0x03, 0x03, 0x00, 0x00 |
db 0x00, 0x00, 0xF8, 0xF0, 0xB0, 0x30, 0x3E, 0x33, 0x33, 0x33, 0x33, 0x7E, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0xC3, 0xC3, 0xC3, 0xC3, 0xF3, 0xDB, 0xDB, 0xDB, 0xDB, 0xF3, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0xF0, 0x60, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x66, 0xFC, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x7C, 0xC6, 0x06, 0x26, 0x3E, 0x26, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0xCE, 0xDB, 0xDB, 0xDB, 0xFB, 0xDB, 0xDB, 0xDB, 0xDB, 0xCE, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x3F, 0x66, 0x66, 0x66, 0x3E, 0x3E, 0x66, 0x66, 0x66, 0xE7, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x02, 0x06, 0x7C, 0xC0, 0xC0, 0xFC, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x62, 0x62, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x36, 0x66, 0x66, 0x66, 0x66, 0xFF, 0xC3, 0xC3, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xFE, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xD6, 0xD6, 0x54, 0x7C, 0x54, 0xD6, 0xD6, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0x06, 0x3C, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xCE, 0xD6, 0xE6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x6C, 0x38, 0xC6, 0xC6, 0xCE, 0xD6, 0xE6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x36, 0x66, 0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xD6, 0xC6, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00 |
RU_FNT2: |
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00 |
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC0, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x06, 0xC6, 0x7C, 0x00 |
db 0x00, 0x00, 0x00, 0x3C, 0x18, 0x7E, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0x7E, 0x18, 0x18, 0x3C, 0x00 |
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x38, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xFF, 0x03, 0x03, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xFE, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xFE, 0x03, 0x03, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xB0, 0xB0, 0x3E, 0x33, 0x33, 0x7E, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xF6, 0xDE, 0xDE, 0xF6, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0xFC, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0x06, 0x3E, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xCE, 0xDB, 0xDB, 0xFB, 0xDB, 0xDB, 0xCE, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xC6, 0xC6, 0x7E, 0x36, 0x66, 0xE7, 0x00, 0x00, 0x00, 0x00 |
db 0x6C, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x6C, 0x00, 0x7C, 0xC6, 0xC6, 0xFC, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x7C, 0xC6, 0xC0, 0xC8, 0xF8, 0xC8, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC0, 0xF8, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00 |
db 0x66, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x6C, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00 |
db 0x6C, 0x38, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x6C, 0x38, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x06, 0xC6, 0x7C, 0x00 |
db 0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0xEC, 0x6C, 0x3C, 0x1C, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0xCF, 0xCD, 0xEF, 0xEC, 0xFF, 0xDC, 0xDC, 0xCC, 0xCC, 0xCC, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0xC6, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0xC6, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00 |
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
/kernel/branches/Kolibri-acpi/sec_loader/trunk/kolibri_ldm |
---|
Property changes: |
Added: tsvn:logminsize |
+5 |
\ No newline at end of property |
/kernel/branches/Kolibri-acpi/drivers/usbstor.asm |
---|
0,0 → 1,1618 |
; standard driver stuff |
format MS COFF |
DEBUG = 1 |
DUMP_PACKETS = 0 |
; this is for DEBUGF macro from 'fdo.inc' |
__DEBUG__ = 1 |
__DEBUG_LEVEL__ = 1 |
include 'proc32.inc' |
include 'imports.inc' |
include 'fdo.inc' |
public START |
public version |
; USB constants |
DEVICE_DESCR_TYPE = 1 |
CONFIG_DESCR_TYPE = 2 |
STRING_DESCR_TYPE = 3 |
INTERFACE_DESCR_TYPE = 4 |
ENDPOINT_DESCR_TYPE = 5 |
DEVICE_QUALIFIER_DESCR_TYPE = 6 |
CONTROL_PIPE = 0 |
ISOCHRONOUS_PIPE = 1 |
BULK_PIPE = 2 |
INTERRUPT_PIPE = 3 |
; USB structures |
virtual at 0 |
config_descr: |
.bLength db ? |
.bDescriptorType db ? |
.wTotalLength dw ? |
.bNumInterfaces db ? |
.bConfigurationValue db ? |
.iConfiguration db ? |
.bmAttributes db ? |
.bMaxPower db ? |
.sizeof: |
end virtual |
virtual at 0 |
interface_descr: |
.bLength db ? |
.bDescriptorType db ? |
.bInterfaceNumber db ? |
.bAlternateSetting db ? |
.bNumEndpoints db ? |
.bInterfaceClass db ? |
.bInterfaceSubClass db ? |
.bInterfaceProtocol db ? |
.iInterface db ? |
.sizeof: |
end virtual |
virtual at 0 |
endpoint_descr: |
.bLength db ? |
.bDescriptorType db ? |
.bEndpointAddress db ? |
.bmAttributes db ? |
.wMaxPacketSize dw ? |
.bInterval db ? |
.sizeof: |
end virtual |
; Mass storage protocol constants, USB layer |
REQUEST_GETMAXLUN = 0xFE ; get max lun |
REQUEST_BORESET = 0xFF ; bulk-only reset |
; Mass storage protocol structures, USB layer |
; Sent from host to device in the first stage of an operation. |
struc command_block_wrapper |
{ |
.Signature dd ? ; the constant 'USBC' |
.Tag dd ? ; identifies response with request |
.Length dd ? ; length of data-transport phase |
.Flags db ? ; one of CBW_FLAG_* |
CBW_FLAG_OUT = 0 |
CBW_FLAG_IN = 80h |
.LUN db ? ; addressed unit |
.CommandLength db ? ; the length of the following field |
.Command rb 16 |
.sizeof: |
} |
virtual at 0 |
command_block_wrapper command_block_wrapper |
end virtual |
; Sent from device to host in the last stage of an operation. |
struc command_status_wrapper |
{ |
.Signature dd ? ; the constant 'USBS' |
.Tag dd ? ; identifies response with request |
.LengthRest dd ? ; .Length - (size of data which were transferred) |
.Status db ? ; one of CSW_STATUS_* |
CSW_STATUS_OK = 0 |
CSW_STATUS_FAIL = 1 |
CSW_STATUS_FATAL = 2 |
.sizeof: |
} |
virtual at 0 |
command_status_wrapper command_status_wrapper |
end virtual |
; Constants of SCSI layer |
SCSI_REQUEST_SENSE = 3 |
SCSI_INQUIRY = 12h |
SCSI_READ_CAPACITY = 25h |
SCSI_READ10 = 28h |
SCSI_WRITE10 = 2Ah |
; Result of SCSI REQUEST SENSE command. |
SENSE_UNKNOWN = 0 |
SENSE_RECOVERED_ERROR = 1 |
SENSE_NOT_READY = 2 |
SENSE_MEDIUM_ERROR = 3 |
SENSE_HARDWARE_ERROR = 4 |
SENSE_ILLEGAL_REQUEST = 5 |
SENSE_UNIT_ATTENTION = 6 |
SENSE_DATA_PROTECT = 7 |
SENSE_BLANK_CHECK = 8 |
; 9 is vendor-specific |
SENSE_COPY_ABORTED = 10 |
SENSE_ABORTED_COMMAND = 11 |
SENSE_EQUAL = 12 |
SENSE_VOLUME_OVERFLOW = 13 |
SENSE_MISCOMPARE = 14 |
; 15 is reserved |
; Structures of SCSI layer |
; Result of SCSI INQUIRY request. |
struc inquiry_data |
{ |
.PeripheralDevice db ? ; lower 5 bits are PeripheralDeviceType |
; upper 3 bits are PeripheralQualifier |
.RemovableMedium db ? ; upper bit is RemovableMedium |
; other bits are for compatibility |
.Version db ? ; lower 3 bits are ANSI-Approved version |
; next 3 bits are ECMA version |
; upper 2 bits are ISO version |
.ResponseDataFormat db ? ; lower 4 bits are ResponseDataFormat |
; bit 6 is TrmIOP |
; bit 7 is AENC |
.AdditionalLength db ? |
dw ? ; reserved |
.Flags db ? |
.VendorID rb 8 ; vendor ID, big-endian |
.ProductID rb 16 ; product ID, big-endian |
.ProductRevBE dd ? ; product revision, big-endian |
.sizeof: |
} |
virtual at 0 |
inquiry_data inquiry_data |
end virtual |
struc sense_data |
{ |
.ErrorCode db ? ; lower 7 bits are error code: |
; 70h = current error, |
; 71h = deferred error |
; upper bit is InformationValid |
.SegmentNumber db ? ; number of segment descriptor |
; for commands COPY [+VERIFY], COMPARE |
.SenseKey db ? ; bits 0-3 are one of SENSE_* |
; bit 4 is reserved |
; bit 5 is IncorrectLengthIndicator |
; bits 6 and 7 are used by |
; sequential-access devices |
.Information dd ? ; command-specific |
.AdditionalLength db ? ; length of data starting here |
.CommandInformation dd ? ; command-specific |
.AdditionalSenseCode db ? ; \ more detailed error code |
.AdditionalSenseQual db ? ; / standard has a large table of them |
.FRUCode db ? ; which part of device has failed |
; (device-specific, not regulated) |
.SenseKeySpecific rb 3 ; depends on SenseKey |
.sizeof: |
} |
virtual at 0 |
sense_data sense_data |
end virtual |
; Device data |
; USB Mass storage device has one or more logical units, identified by LUN, |
; logical unit number. The highest value of LUN, that is, number of units |
; minus 1, can be obtained via control request Get Max LUN. |
virtual at 0 |
usb_device_data: |
.ConfigPipe dd ? ; configuration pipe |
.OutPipe dd ? ; pipe for OUT bulk endpoint |
.InPipe dd ? ; pipe for IN bulk endpoint |
.MaxLUN dd ? ; maximum Logical Unit Number |
.LogicalDevices dd ? ; pointer to array of usb_unit_data |
; 1 for a connected USB device, 1 for each disk device |
; the structure can be freed when .NumReferences decreases to zero |
.NumReferences dd ? ; number of references |
.ConfigRequest rb 8 ; buffer for configuration requests |
.LengthRest dd ? ; Length - (size of data which were transferred) |
; All requests to a given device are serialized, |
; only one request to a given device can be processed at a time. |
; The current request and all pending requests are organized in the following |
; queue, the head being the current request. |
; NB: the queue must be device-wide due to the protocol: |
; data stage is not tagged (unlike command_*_wrapper), so the only way to know |
; what request the data are associated with is to guarantee that only one |
; request is processing at the time. |
.RequestsQueue rd 2 |
.QueueLock rd 3 ; protects .RequestsQueue |
.InquiryData inquiry_data ; information about device |
; data for the current request |
.Command command_block_wrapper |
.DeviceDisconnected db ? |
.Status command_status_wrapper |
.Sense sense_data |
.sizeof: |
end virtual |
; Information about one logical device. |
virtual at 0 |
usb_unit_data: |
.Parent dd ? ; pointer to parent usb_device_data |
.LUN db ? ; index in usb_device_data.LogicalDevices array |
.DiskIndex db ? ; for name "usbhd<index>" |
.MediaPresent db ? |
db ? ; alignment |
.DiskDevice dd ? ; handle of disk device or NULL |
.SectorSize dd ? ; sector size |
; For some devices, the first request to the medium fails with 'unit not ready'. |
; When the code sees this status, it retries the command several times. |
; Two following variables track the retry count and total time for those; |
; total time is currently used only for debug output. |
.UnitReadyAttempts dd ? |
.TimerTicks dd ? |
.sizeof: |
end virtual |
; This is the structure for items in the queue usb_device_data.RequestsQueue. |
virtual at 0 |
request_queue_item: |
.Next dd ? ; next item in the queue |
.Prev dd ? ; prev item in the queue |
.ReqBuilder dd ? ; procedure to fill command_block_wrapper |
.Buffer dd ? ; input or output data |
; (length is command_block_wrapper.Length) |
.Callback dd ? ; procedure to call in the end of transfer |
.UserData dd ? ; passed as-is to .Callback |
; There are 3 possible stages of any request, one of them optional: |
; command stage (host sends command_block_wrapper to device), |
; optional data stage, |
; status stage (device sends command_status_wrapper to host). |
; Also, if a request fails, the code queues additional request |
; SCSI_REQUEST_SENSE; sense_data from SCSI_REQUEST_SENSE |
; contains some information about the error. |
.Stage db ? |
.sizeof: |
end virtual |
section '.flat' code readable align 16 |
; The start procedure. |
proc START |
virtual at esp |
dd ? ; return address |
.reason dd ? ; DRV_ENTRY or DRV_EXIT |
end virtual |
; 1. Test whether the procedure is called with the argument DRV_ENTRY. |
; If not, return 0. |
xor eax, eax ; initialize return value |
cmp [.reason], 1 ; compare the argument |
jnz .nothing |
; 2. Initialize: we have one global mutex. |
mov ecx, free_numbers_lock |
call MutexInit |
; 3. Register self as a USB driver. |
; The name is my_driver = 'usbstor'; IOCTL interface is not supported; |
; usb_functions is an offset of a structure with callback functions. |
stdcall RegUSBDriver, my_driver, 0, usb_functions |
; 4. Return the returned value of RegUSBDriver. |
.nothing: |
ret 4 |
endp |
; Helper procedures to work with requests queue. |
; Add a request to the queue. Stdcall with 5 arguments. |
proc queue_request |
push ebx esi |
virtual at esp |
rd 2 ; saved registers |
dd ? ; return address |
.device dd ? ; pointer to usb_device_data |
.ReqBuilder dd ? ; request_queue_item.ReqBuilder |
.Buffer dd ? ; request_queue_item.Buffer |
.Callback dd ? ; request_queue_item.Callback |
.UserData dd ? ; request_queue_item.UserData |
end virtual |
; 1. Allocate the memory for the request description. |
movi eax, request_queue_item.sizeof |
call Kmalloc |
test eax, eax |
jnz @f |
mov esi, nomemory |
call SysMsgBoardStr |
pop esi ebx |
ret 20 |
@@: |
; 2. Fill user-provided parts of the request description. |
push edi |
xchg eax, ebx |
lea esi, [.ReqBuilder+4] |
lea edi, [ebx+request_queue_item.ReqBuilder] |
movsd ; ReqBuilder |
movsd ; Buffer |
movsd ; Callback |
movsd ; UserData |
pop edi |
; 3. Set stage to zero: not started. |
mov [ebx+request_queue_item.Stage], 0 |
; 4. Lock the queue. |
mov esi, [.device] |
lea ecx, [esi+usb_device_data.QueueLock] |
call MutexLock |
; 5. Insert the request to the tail of the queue. |
add esi, usb_device_data.RequestsQueue |
mov edx, [esi+request_queue_item.Prev] |
mov [ebx+request_queue_item.Next], esi |
mov [ebx+request_queue_item.Prev], edx |
mov [edx+request_queue_item.Next], ebx |
mov [esi+request_queue_item.Prev], ebx |
; 6. Test whether the queue was empty |
; and the request should be started immediately. |
cmp [esi+request_queue_item.Next], ebx |
jnz .unlock |
; 8. If the step 6 shows that the request is the first in the queue, |
; start it. |
sub esi, usb_device_data.RequestsQueue |
call setup_request |
jmp .nothing |
.unlock: |
call MutexUnlock |
; 9. Return. |
.nothing: |
pop esi ebx |
ret 20 |
endp |
; The current request is completed. Call the callback, |
; remove the request from the queue, start the next |
; request if there is one. |
; esi points to usb_device_data |
proc complete_request |
; 1. Print common debug messages on fails. |
if DEBUG |
cmp [esi+usb_device_data.Status.Status], CSW_STATUS_FAIL |
jb .normal |
jz .fail |
DEBUGF 1, 'K : Fatal error during execution of command %x\n', [esi+usb_device_data.Command.Command]:2 |
jmp .normal |
.fail: |
DEBUGF 1, 'K : Command %x failed\n', [esi+usb_device_data.Command.Command]:2 |
.normal: |
end if |
; 2. Get the current request. |
mov ebx, [esi+usb_device_data.RequestsQueue+request_queue_item.Next] |
; 3. Call the callback. |
stdcall [ebx+request_queue_item.Callback], esi, [ebx+request_queue_item.UserData] |
; 4. Lock the queue. |
lea ecx, [esi+usb_device_data.QueueLock] |
call MutexLock |
; 5. Remove the request. |
lea edx, [esi+usb_device_data.RequestsQueue] |
mov eax, [ebx+request_queue_item.Next] |
mov [eax+request_queue_item.Prev], edx |
mov [edx+request_queue_item.Next], eax |
; 6. Free the request memory. |
push eax edx |
xchg eax, ebx |
call Kfree |
pop edx ebx |
; 7. If there is a next request, start processing. |
cmp ebx, edx |
jnz setup_request |
; 8. Unlock the queue and return. |
lea ecx, [esi+usb_device_data.QueueLock] |
call MutexUnlock |
ret |
endp |
; Start processing the request. Called either by queue_request |
; or when the previous request has been processed. |
; Do not call directly, use queue_request. |
; Must be called when queue is locked; unlocks the queue when returns. |
proc setup_request |
xor eax, eax |
; 1. If DeviceDisconnected has been run, then all handles of pipes |
; are invalid, so we must fail immediately. |
; (That is why this function needs the locked queue: this |
; guarantee that either DeviceDisconnected has been already run, or |
; DeviceDisconnected will not return before the queue is unlocked.) |
cmp [esi+usb_device_data.DeviceDisconnected], al |
jnz .fatal |
; 2. If the previous command has encountered a fatal error, |
; perform reset recovery. |
cmp [esi+usb_device_data.Status.Status], CSW_STATUS_FATAL |
jb .norecovery |
; 2a. Send Bulk-Only Mass Storage Reset command to config pipe. |
lea edx, [esi+usb_device_data.ConfigRequest] |
mov word [edx], (REQUEST_BORESET shl 8) + 21h ; class request |
mov word [edx+6], ax ; length = 0 |
stdcall USBControlTransferAsync, [esi+usb_device_data.ConfigPipe], edx, eax, eax, recovery_callback1, esi, eax |
; 2b. Fail here = fatal error. |
test eax, eax |
jz .fatal |
; 2c. Otherwise, unlock the queue and return. recovery_callback1 will continue processing. |
.unlock_return: |
lea ecx, [esi+usb_device_data.QueueLock] |
call MutexUnlock |
ret |
.norecovery: |
; 3. Send the command. Fail (no memory or device disconnected) = fatal error. |
; Otherwise, go to 2c. |
call request_stage1 |
test eax, eax |
jnz .unlock_return |
.fatal: |
; 4. Fatal error. Set status = FATAL, unlock the queue, complete the request. |
mov [esi+usb_device_data.Status.Status], CSW_STATUS_FATAL |
lea ecx, [esi+usb_device_data.QueueLock] |
call MutexUnlock |
jmp complete_request |
endp |
; Initiate USB transfer for the first stage of a request (send command). |
proc request_stage1 |
mov ebx, [esi+usb_device_data.RequestsQueue+request_queue_item.Next] |
; 1. Set the stage to 1 = command stage. |
inc [ebx+request_queue_item.Stage] |
; 2. Generate the command. Zero-initialize and use the caller-provided proc. |
lea edx, [esi+usb_device_data.Command] |
xor eax, eax |
mov [edx+command_block_wrapper.CommandLength], 12 |
mov dword [edx+command_block_wrapper.Command], eax |
mov dword [edx+command_block_wrapper.Command+4], eax |
mov dword [edx+command_block_wrapper.Command+8], eax |
mov dword [edx+command_block_wrapper.Command+12], eax |
inc [edx+command_block_wrapper.Tag] |
stdcall [ebx+request_queue_item.ReqBuilder], edx, [ebx+request_queue_item.UserData] |
; 4. Initiate USB transfer. |
lea edx, [esi+usb_device_data.Command] |
if DUMP_PACKETS |
DEBUGF 1,'K : USBSTOR out:' |
mov eax, edx |
mov ecx, command_block_wrapper.sizeof |
call debug_dump |
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 |
if DUMP_PACKETS |
proc debug_dump |
test ecx, ecx |
jz .done |
.loop: |
test ecx, 0Fh |
jnz @f |
DEBUGF 1,'\nK :' |
@@: |
DEBUGF 1,' %x',[eax]:2 |
inc eax |
dec ecx |
jnz .loop |
.done: |
ret |
endp |
end if |
; Called when the Reset command is completed, |
; either successfully or not. |
proc recovery_callback1 |
virtual at esp |
dd ? ; return address |
.pipe dd ? |
.status dd ? |
.buffer dd ? |
.length dd ? |
.calldata dd ? |
end virtual |
cmp [.status], 0 |
jnz .error |
; todo: reset pipes |
push ebx esi |
mov esi, [.calldata+8] |
call request_stage1 |
pop esi ebx |
test eax, eax |
jz .error |
ret 20 |
.error: |
DEBUGF 1, 'K : error %d while resetting', [.status] |
jmp request_callback1.common_error |
endp |
; Called when the first stage of request is completed, |
; either successfully or not. |
proc request_callback1 |
virtual at esp |
dd ? ; return address |
.pipe dd ? |
.status dd ? |
.buffer dd ? |
.length dd ? |
.calldata dd ? |
end virtual |
; 1. Initialize. |
mov ecx, [.calldata] |
mov eax, [.status] |
; 2. Test for error. |
test eax, eax |
jnz .error |
; No error. |
; 3. Increment the stage. |
mov edx, [ecx+usb_device_data.RequestsQueue+request_queue_item.Next] |
inc [edx+request_queue_item.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. |
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. The status stage goes to the same direction, enqueue it now. |
mov ecx, [.calldata] |
jmp ..enqueue_status |
.nothing: |
ret 20 |
.error: |
; Error. |
; 7. Print debug message and complete the request as failed. |
DEBUGF 1,'K : error %d after %d bytes in request stage\n',eax,[.length] |
.common_error: |
; TODO: add recovery after STALL |
mov ecx, [.calldata] |
mov [ecx+usb_device_data.Status.Status], CSW_STATUS_FATAL |
push ebx esi |
mov esi, ecx |
call complete_request |
pop esi ebx |
ret 20 |
endp |
; Called when the second stage of request is completed, |
; either successfully or not. |
proc request_callback2 |
virtual at esp |
dd ? ; return address |
.pipe dd ? |
.status dd ? |
.buffer dd ? |
.length dd ? |
.calldata dd ? |
end virtual |
if DUMP_PACKETS |
mov eax, [.calldata] |
mov eax, [eax+usb_device_data.InPipe] |
cmp [.pipe], eax |
jnz @f |
DEBUGF 1,'K : USBSTOR in:' |
push eax ecx |
mov eax, [.buffer+8] |
mov ecx, [.length+8] |
call debug_dump |
pop ecx eax |
DEBUGF 1,'\n' |
@@: |
end if |
; 1. Initialize. |
mov ecx, [.calldata] |
mov eax, [.status] |
; 2. Test for error. |
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. |
; 7. Print debug message and complete the request as failed. |
DEBUGF 1,'K : error %d after %d bytes in data stage\n',eax,[.length] |
jmp request_callback1.common_error |
endp |
; Called when the third stage of request is completed, |
; either successfully or not. |
proc request_callback3 |
virtual at esp |
dd ? ; return address |
.pipe dd ? |
.status dd ? |
.buffer dd ? |
.length dd ? |
.calldata dd ? |
end virtual |
if DUMP_PACKETS |
DEBUGF 1,'K : USBSTOR in:' |
mov eax, [.buffer] |
mov ecx, [.length] |
call debug_dump |
DEBUGF 1,'\n' |
end if |
; 1. Initialize. |
mov eax, [.status] |
; 2. Test for error. |
test eax, eax |
jnz .transfer_error |
; Transfer is OK. |
; 3. Validate the status. Invalid status = fatal error. |
push ebx esi |
mov esi, [.calldata+8] |
mov ebx, [esi+usb_device_data.RequestsQueue+request_queue_item.Next] |
cmp [esi+usb_device_data.Status.Signature], 'USBS' |
jnz .invalid |
mov eax, [esi+usb_device_data.Command.Tag] |
cmp [esi+usb_device_data.Status.Tag], eax |
jnz .invalid |
cmp [esi+usb_device_data.Status.Status], CSW_STATUS_FATAL |
ja .invalid |
; 4. The status block is valid. Check the status code. |
jz .complete |
; 5. If this command was not REQUEST_SENSE, copy status data to safe place. |
; Otherwise, the original command has failed, so restore the fail status. |
cmp byte [esi+usb_device_data.Command.Command], SCSI_REQUEST_SENSE |
jz .request_sense |
mov eax, [esi+usb_device_data.Status.LengthRest] |
mov [esi+usb_device_data.LengthRest], eax |
cmp [esi+usb_device_data.Status.Status], CSW_STATUS_FAIL |
jz .fail |
.complete: |
call complete_request |
.nothing: |
pop esi ebx |
ret 20 |
.request_sense: |
mov [esi+usb_device_data.Status.Status], CSW_STATUS_FAIL |
jmp .complete |
.invalid: |
; 6. Invalid status block. Say error, set status to fatal and complete request. |
push esi |
mov esi, invresponse |
call SysMsgBoardStr |
pop esi |
mov [esi+usb_device_data.Status.Status], CSW_STATUS_FATAL |
jmp .complete |
.fail: |
; 7. The command has failed. |
; If this command was not REQUEST_SENSE, schedule the REQUEST_SENSE command |
; to determine the reason of fail. Otherwise, assume that there is no error data. |
cmp [esi+usb_device_data.Command.Command], SCSI_REQUEST_SENSE |
jz .fail_request_sense |
mov [ebx+request_queue_item.ReqBuilder], request_sense_req |
lea eax, [esi+usb_device_data.Sense] |
mov [ebx+request_queue_item.Buffer], eax |
call request_stage1 |
test eax, eax |
jnz .nothing |
.fail_request_sense: |
DEBUGF 1,'K : fail during REQUEST SENSE\n' |
mov byte [esi+usb_device_data.Sense], 0 |
jmp .complete |
.transfer_error: |
; TODO: add recovery after STALL |
DEBUGF 1,'K : error %d after %d bytes in status stage\n',eax,[.length] |
jmp request_callback1.common_error |
endp |
; Builder for SCSI_REQUEST_SENSE request. |
; edx = first argument = pointer to usb_device_data.Command, |
; second argument = custom data given to queue_request (ignored). |
proc request_sense_req |
mov [edx+command_block_wrapper.Length], sense_data.sizeof |
mov [edx+command_block_wrapper.Flags], CBW_FLAG_IN |
mov byte [edx+command_block_wrapper.Command+0], SCSI_REQUEST_SENSE |
mov byte [edx+command_block_wrapper.Command+4], sense_data.sizeof |
ret 8 |
endp |
; This procedure is called when new mass-storage device is detected. |
; It initializes the device. |
; Technically, initialization implies sending several USB queries, |
; so it is split in several procedures. The first is AddDevice, |
; other are callbacks which will be called at some time in the future, |
; when the device will respond. |
; The general scheme: |
; * AddDevice parses descriptors, opens pipes; if everything is ok, |
; AddDevice sends REQUEST_GETMAXLUN with callback known_lun_callback; |
; * known_lun_callback allocates memory for LogicalDevices and sends |
; SCSI_TEST_UNIT_READY to all logical devices with test_unit_ready_callback; |
; * test_unit_ready_callback checks whether the unit is ready; |
; if not, it repeats the same request several times; |
; if ok or there were too many attempts, it sends SCSI_INQUIRY with |
; callback inquiry_callback; |
; * inquiry_callback checks that a logical device is a block device |
; and the unit was ready; if so, it notifies the kernel about new disk device. |
proc AddDevice |
push ebx esi |
virtual at esp |
rd 2 ; saved registers ebx, esi |
dd ? ; return address |
.pipe0 dd ? ; handle of the config pipe |
.config dd ? ; pointer to config_descr |
.interface dd ? ; pointer to interface_descr |
end virtual |
; 1. Check device type. Currently only SCSI-command-set Bulk-only devices |
; are supported. |
; 1a. Get the subclass and the protocol. Since bInterfaceSubClass and |
; bInterfaceProtocol are subsequent in interface_descr, just one |
; memory reference is used for both. |
mov esi, [.interface] |
xor ebx, ebx |
mov cx, word [esi+interface_descr.bInterfaceSubClass] |
; 1b. For Mass-storage SCSI-command-set Bulk-only devices subclass must be 6 |
; and protocol must be 50h. Check. |
cmp cx, 0x5006 |
jz .known |
; There are devices with subclass 5 which use the same protocol 50h. |
; The difference is not important for the code except for this test, |
; so allow them to proceed also. |
cmp cx, 0x5005 |
jz .known |
; 1c. If the device is unknown, print a message and go to 11c. |
mov esi, unkdevice |
call SysMsgBoardStr |
jmp .nothing |
; 1d. If the device uses known command set, print a message and continue |
; configuring. |
.known: |
push esi |
mov esi, okdevice |
call SysMsgBoardStr |
pop esi |
; 2. Allocate memory for internal device data. |
; 2a. Call the kernel. |
mov eax, usb_device_data.sizeof |
call Kmalloc |
; 2b. Check return value. |
test eax, eax |
jnz @f |
; 2c. If failed, say a message and go to 11c. |
mov esi, nomemory |
call SysMsgBoardStr |
jmp .nothing |
@@: |
; 2d. If succeeded, zero the contents and continue configuring. |
xchg ebx, eax ; ebx will point to usb_device_data |
xor eax, eax |
mov [ebx+usb_device_data.OutPipe], eax |
mov [ebx+usb_device_data.InPipe], eax |
mov [ebx+usb_device_data.MaxLUN], eax |
mov [ebx+usb_device_data.LogicalDevices], eax |
mov dword [ebx+usb_device_data.ConfigRequest], eax |
mov dword [ebx+usb_device_data.ConfigRequest+4], eax |
mov [ebx+usb_device_data.Status.Status], al |
mov [ebx+usb_device_data.DeviceDisconnected], al |
; 2e. There is one reference: a connected USB device. |
inc eax |
mov [ebx+usb_device_data.NumReferences], eax |
; 2f. Save handle of configuration pipe for reset recovery. |
mov eax, [.pipe0] |
mov [ebx+usb_device_data.ConfigPipe], eax |
; 2g. Save the interface number for configuration requests. |
mov al, [esi+interface_descr.bInterfaceNumber] |
mov [ebx+usb_device_data.ConfigRequest+4], al |
; 2h. Initialize common fields in command wrapper. |
mov [ebx+usb_device_data.Command.Signature], 'USBC' |
mov [ebx+usb_device_data.Command.Tag], 'xxxx' |
; 2i. Initialize requests queue. |
lea eax, [ebx+usb_device_data.RequestsQueue] |
mov [eax+request_queue_item.Next], eax |
mov [eax+request_queue_item.Prev], eax |
lea ecx, [ebx+usb_device_data.QueueLock] |
call MutexInit |
; Bulk-only mass storage devices use one OUT bulk endpoint for sending |
; command/data and one IN bulk endpoint for receiving data/status. |
; Look for those endpoints. |
; 3. Get the upper bound of all descriptors' data. |
mov edx, [.config] ; configuration descriptor |
movzx ecx, [edx+config_descr.wTotalLength] |
add edx, ecx |
; 4. Loop over all descriptors until |
; either end-of-data reached - this is fail |
; or interface descriptor found - this is fail, all further data |
; correspond to that interface |
; or both endpoint descriptors found. |
; 4a. Loop start: esi points to the interface descriptor, |
.lookep: |
; 4b. Get next descriptor. |
movzx ecx, byte [esi] ; the first byte of all descriptors is length |
add esi, ecx |
; 4c. Check that at least two bytes are readable. The opposite is an error. |
inc esi |
cmp esi, edx |
jae .errorep |
dec esi |
; 4d. Check that this descriptor is not interface descriptor. The opposite is |
; an error. |
cmp byte [esi+endpoint_descr.bDescriptorType], INTERFACE_DESCR_TYPE |
jz .errorep |
; 4e. Test whether this descriptor is an endpoint descriptor. If not, continue |
; the loop. |
cmp byte [esi+endpoint_descr.bDescriptorType], ENDPOINT_DESCR_TYPE |
jnz .lookep |
; 5. Check that the descriptor contains all required data and all data are |
; readable. The opposite is an error. |
cmp byte [esi+endpoint_descr.bLength], endpoint_descr.sizeof |
jb .errorep |
lea ecx, [esi+endpoint_descr.sizeof] |
cmp ecx, edx |
ja .errorep |
; 6. Check that the endpoint is bulk endpoint. The opposite is an error. |
mov cl, [esi+endpoint_descr.bmAttributes] |
and cl, 3 |
cmp cl, BULK_PIPE |
jnz .errorep |
; 7. Get the direction of this endpoint. |
movzx ecx, [esi+endpoint_descr.bEndpointAddress] |
shr ecx, 7 |
; 8. Test whether a pipe for this direction is already opened. If so, continue |
; the loop. |
cmp [ebx+usb_device_data.OutPipe+ecx*4], 0 |
jnz .lookep |
; 9. Open pipe for this endpoint. |
; 9a. Save registers. |
push ecx edx |
; 9b. Load parameters from the descriptor. |
movzx ecx, [esi+endpoint_descr.bEndpointAddress] |
movzx edx, [esi+endpoint_descr.wMaxPacketSize] |
movzx eax, [esi+endpoint_descr.bInterval] ; not used for USB1, may be important for USB2 |
; 9c. Call the kernel. |
stdcall USBOpenPipe, [ebx+usb_device_data.ConfigPipe], ecx, edx, BULK_PIPE, eax |
; 9d. Restore registers. |
pop edx ecx |
; 9e. Check result. If failed, go to 11b. |
test eax, eax |
jz .free |
; 9f. Save result. |
mov [ebx+usb_device_data.OutPipe+ecx*4], eax |
; 10. Test whether the second pipe is already opened. If not, continue loop. |
xor ecx, 1 |
cmp [ebx+usb_device_data.OutPipe+ecx*4], 0 |
jz .lookep |
jmp .created |
; 11. An error occured during processing endpoint descriptor. |
.errorep: |
; 11a. Print a message. |
DEBUGF 1,'K : error: invalid endpoint descriptor\n' |
.free: |
; 11b. Free the allocated usb_device_data. |
xchg eax, ebx |
call Kfree |
.nothing: |
; 11c. Return an error. |
xor eax, eax |
jmp .return |
.created: |
; 12. Pipes are opened. Send GetMaxLUN control request. |
lea eax, [ebx+usb_device_data.ConfigRequest] |
mov byte [eax], 0A1h ; class request from interface |
mov byte [eax+1], REQUEST_GETMAXLUN |
mov byte [eax+6], 1 ; transfer 1 byte |
lea ecx, [ebx+usb_device_data.MaxLUN] |
if DUMP_PACKETS |
DEBUGF 1,'K : GETMAXLUN: %x %x %x %x %x %x %x %x\n',[eax]:2,[eax+1]:2,[eax+2]:2,[eax+3]:2,[eax+4]:2,[eax+5]:2,[eax+6]:2,[eax+7]:2 |
end if |
stdcall USBControlTransferAsync, [ebx+usb_device_data.ConfigPipe], eax, ecx, 1, known_lun_callback, ebx, 0 |
; 13. Return with pointer to device data as returned value. |
xchg eax, ebx |
.return: |
pop esi ebx |
ret 12 |
endp |
; This function is called when REQUEST_GETMAXLUN is done, |
; either successful or unsuccessful. |
proc known_lun_callback |
push ebx esi |
virtual at esp |
rd 2 ; saved registers |
dd ? ; return address |
.pipe dd ? |
.status dd ? |
.buffer dd ? |
.length dd ? |
.calldata dd ? |
end virtual |
; 1. Check the status. If the request failed, assume that MaxLUN is zero. |
mov ebx, [.calldata] |
mov eax, [.status] |
test eax, eax |
jz @f |
DEBUGF 1, 'K : GETMAXLUN failed with status %d, assuming zero\n', eax |
mov [ebx+usb_device_data.MaxLUN], 0 |
@@: |
; 2. Allocate the memory for logical devices. |
mov eax, [ebx+usb_device_data.MaxLUN] |
inc eax |
DEBUGF 1,'K : %d logical unit(s)\n',eax |
imul eax, usb_unit_data.sizeof |
push ebx |
call Kmalloc |
pop ebx |
; If failed, print a message and do nothing. |
test eax, eax |
jnz @f |
mov esi, nomemory |
call SysMsgBoardStr |
pop esi ebx |
ret 20 |
@@: |
mov [ebx+usb_device_data.LogicalDevices], eax |
; 3. Initialize logical devices and initiate TEST_UNIT_READY request. |
xchg esi, eax |
xor ecx, ecx |
.looplun: |
mov [esi+usb_unit_data.Parent], ebx |
mov [esi+usb_unit_data.LUN], cl |
xor eax, eax |
mov [esi+usb_unit_data.MediaPresent], al |
mov [esi+usb_unit_data.DiskDevice], eax |
mov [esi+usb_unit_data.SectorSize], eax |
mov [esi+usb_unit_data.UnitReadyAttempts], eax |
push ecx |
call GetTimerTicks |
mov [esi+usb_unit_data.TimerTicks], eax |
stdcall queue_request, ebx, test_unit_ready_req, 0, test_unit_ready_callback, esi |
pop ecx |
inc ecx |
add esi, usb_unit_data.sizeof |
cmp ecx, [ebx+usb_device_data.MaxLUN] |
jbe .looplun |
; 4. Return. |
pop esi ebx |
ret 20 |
endp |
; Builder for SCSI INQUIRY request. |
; edx = first argument = pointer to usb_device_data.Command, |
; second argument = custom data given to queue_request. |
proc inquiry_req |
mov eax, [esp+8] |
mov al, [eax+usb_unit_data.LUN] |
mov [edx+command_block_wrapper.Length], inquiry_data.sizeof |
mov [edx+command_block_wrapper.Flags], CBW_FLAG_IN |
mov [edx+command_block_wrapper.LUN], al |
mov byte [edx+command_block_wrapper.Command+0], SCSI_INQUIRY |
mov byte [edx+command_block_wrapper.Command+4], inquiry_data.sizeof |
ret 8 |
endp |
; Called when SCSI INQUIRY request is completed. |
proc inquiry_callback |
; 1. Check the status. |
mov ecx, [esp+4] |
cmp [ecx+usb_device_data.Status.Status], CSW_STATUS_OK |
jnz .fail |
; 2. The command has completed successfully. |
; Print a message showing device type, ignore anything but block devices. |
mov al, [ecx+usb_device_data.InquiryData.PeripheralDevice] |
and al, 1Fh |
DEBUGF 1,'K : peripheral device type is %x\n',al |
test al, al |
jnz .nothing |
DEBUGF 1,'K : direct-access mass storage device detected\n' |
; 3. We have found a new disk device. Increment number of references. |
lock inc [ecx+usb_device_data.NumReferences] |
; Unfortunately, we are now in the context of the USB thread, |
; so we can't notify the kernel immediately: it would try to do something |
; with a new disk, those actions would be synchronous and would require |
; waiting for results of USB requests, but we need to exit this callback |
; to allow the USB thread to continue working and handling those requests. |
; 4. Thus, create a temporary kernel thread which would do it. |
mov edx, [esp+8] |
push ebx ecx esi edi |
movi ebx, 1 |
mov ecx, new_disk_thread |
; edx = parameter |
call CreateThread |
pop edi esi ecx ebx |
cmp eax, -1 |
jnz .nothing |
; on error, reverse step 3 |
lock dec [ecx+usb_device_data.NumReferences] |
.nothing: |
ret 8 |
.fail: |
; 4. The command has failed. Print a message and do nothing. |
push esi |
mov esi, inquiry_fail |
call SysMsgBoardStr |
pop esi |
ret 8 |
endp |
; Builder for SCSI TEST_UNIT_READY request. |
; edx = first argument = pointer to usb_device_data.Command, |
; second argument = custom data given to queue_request. |
proc test_unit_ready_req |
mov eax, [esp+8] |
mov al, [eax+usb_unit_data.LUN] |
mov [edx+command_block_wrapper.Length], 0 |
mov [edx+command_block_wrapper.Flags], CBW_FLAG_IN |
mov [edx+command_block_wrapper.LUN], al |
ret 8 |
endp |
; Called when SCSI TEST_UNIT_READY request is completed. |
proc test_unit_ready_callback |
virtual at esp |
dd ? ; return address |
.device dd ? |
.calldata dd ? |
end virtual |
; 1. Check the status. |
mov ecx, [.device] |
mov edx, [.calldata] |
cmp [ecx+usb_device_data.Status.Status], CSW_STATUS_OK |
jnz .fail |
; 2. The command has completed successfully, |
; possibly after some repetitions. Print a debug message showing |
; number and time of those. Remember that media is ready and go to 4. |
DEBUGF 1,'K : media is ready\n' |
call GetTimerTicks |
sub eax, [edx+usb_unit_data.TimerTicks] |
DEBUGF 1,'K : %d attempts, %d ticks\n',[edx+usb_unit_data.UnitReadyAttempts],eax |
inc [edx+usb_unit_data.MediaPresent] |
jmp .inquiry |
.fail: |
; 3. The command has failed. |
; Retry the same request up to 3 times with 10ms delay; |
; if limit of retries is not reached, exit from the function. |
; Otherwise, go to 4. |
inc [edx+usb_unit_data.UnitReadyAttempts] |
cmp [edx+usb_unit_data.UnitReadyAttempts], 3 |
jz @f |
push ecx edx esi |
movi esi, 10 |
call Sleep |
pop esi edx ecx |
stdcall queue_request, ecx, test_unit_ready_req, 0, test_unit_ready_callback, edx |
ret 8 |
@@: |
DEBUGF 1,'K : media not ready\n' |
.inquiry: |
; 4. initiate INQUIRY request. |
lea eax, [ecx+usb_device_data.InquiryData] |
stdcall queue_request, ecx, inquiry_req, eax, inquiry_callback, edx |
ret 8 |
endp |
; Temporary thread for initial actions with a new disk device. |
proc new_disk_thread |
sub esp, 32 |
virtual at esp |
.name rb 32 ; device name |
.param dd ? ; contents of edx at the moment of int 0x40/eax=51 |
dd ? ; stack segment |
end virtual |
; We are ready to notify the kernel about a new disk device. |
mov esi, [.param] |
; 1. Generate name. |
; 1a. Find a free index. |
mov ecx, free_numbers_lock |
call MutexLock |
xor eax, eax |
@@: |
bsf edx, [free_numbers+eax] |
jnz @f |
add eax, 4 |
cmp eax, 4*4 |
jnz @b |
call MutexUnlock |
push esi |
mov esi, noindex |
call SysMsgBoardStr |
pop esi |
jmp .drop_reference |
@@: |
; 1b. Mark the index as busy. |
btr [free_numbers+eax], edx |
lea eax, [eax*8+edx] |
push eax |
call MutexUnlock |
pop eax |
; 1c. Generate a name of the form "usbhd<index>" in the stack. |
mov dword [esp], 'usbh' |
lea edi, [esp+5] |
mov byte [edi-1], 'd' |
push eax |
push -'0' |
movi ecx, 10 |
@@: |
cdq |
div ecx |
push edx |
test eax, eax |
jnz @b |
@@: |
pop eax |
add al, '0' |
stosb |
jnz @b |
pop ecx |
mov edx, esp |
; 3d. Store the index in usb_unit_data to free it later. |
mov [esi+usb_unit_data.DiskIndex], cl |
; 4. Notify the kernel about a new disk. |
; 4a. Add a disk. |
; stdcall queue_request, ecx, read_capacity_req, eax, read_capacity_callback, eax |
stdcall DiskAdd, disk_functions, edx, esi, 0 |
mov ebx, eax |
; 4b. If it failed, release the index and do nothing. |
test eax, eax |
jz .free_index |
; 4c. Notify the kernel that a media is present. |
stdcall DiskMediaChanged, eax, 1 |
; 5. Lock the requests queue, check that device is not disconnected, |
; store the disk handle, unlock the requests queue. |
mov ecx, [esi+usb_unit_data.Parent] |
add ecx, usb_device_data.QueueLock |
call MutexLock |
cmp byte [ecx+usb_device_data.DeviceDisconnected-usb_device_data.QueueLock], 0 |
jnz .disconnected |
mov [esi+usb_unit_data.DiskDevice], ebx |
call MutexUnlock |
jmp .exit |
.disconnected: |
call MutexUnlock |
stdcall disk_close, ebx |
jmp .exit |
.free_index: |
mov ecx, free_numbers_lock |
call MutexLock |
movzx eax, [esi+usb_unit_data.DiskIndex] |
bts [free_numbers], eax |
call MutexUnlock |
.drop_reference: |
mov esi, [esi+usb_unit_data.Parent] |
lock dec [esi+usb_device_data.NumReferences] |
jnz .exit |
mov eax, [esi+usb_device_data.LogicalDevices] |
call Kfree |
xchg eax, esi |
call Kfree |
.exit: |
or eax, -1 |
int 0x40 |
endp |
; This function is called when the device is disconnected. |
proc DeviceDisconnected |
push ebx esi |
virtual at esp |
rd 2 ; saved registers |
dd ? ; return address |
.device dd ? |
end virtual |
; 1. Say a message. |
mov esi, disconnectmsg |
call SysMsgBoardStr |
; 2. Lock the requests queue, set .DeviceDisconnected to 1, |
; unlock the requests queue. |
; Locking is required for synchronization with queue_request: |
; all USB callbacks are executed in the same thread and are |
; synchronized automatically, but queue_request can be running |
; from any thread which wants to do something with a filesystem. |
; Without locking, it would be possible that queue_request has |
; been started, has checked that device is not yet disconnected, |
; then DeviceDisconnected completes and all handles become invalid, |
; then queue_request tries to use them. |
mov esi, [.device] |
lea ecx, [esi+usb_device_data.QueueLock] |
call MutexLock |
mov [esi+usb_device_data.DeviceDisconnected], 1 |
call MutexUnlock |
; 3. Drop one reference to the structure and check whether |
; that was the last reference. |
lock dec [esi+usb_device_data.NumReferences] |
jz .free |
; 4. If not, there are some additional references due to disk devices; |
; notify the kernel that those disks are deleted. |
; Note that new disks cannot be added while we are looping here, |
; because new_disk_thread checks for .DeviceDisconnected. |
mov ebx, [esi+usb_device_data.MaxLUN] |
mov esi, [esi+usb_device_data.LogicalDevices] |
inc ebx |
.diskdel: |
mov eax, [esi+usb_unit_data.DiskDevice] |
test eax, eax |
jz @f |
stdcall DiskDel, eax |
@@: |
add esi, usb_unit_data.sizeof |
dec ebx |
jnz .diskdel |
; In this case, some operations with those disks are still possible, |
; so we can't do anything more now. disk_close will take care of the rest. |
.return: |
pop esi ebx |
ret 4 |
; 5. If there are no disk devices, free all resources which were allocated. |
.free: |
mov eax, [esi+usb_device_data.LogicalDevices] |
test eax, eax |
jz @f |
call Kfree |
@@: |
xchg eax, esi |
call Kfree |
jmp .return |
endp |
; Disk functions. |
DISK_STATUS_OK = 0 ; success |
DISK_STATUS_GENERAL_ERROR = -1; if no other code is suitable |
DISK_STATUS_INVALID_CALL = 1 ; invalid input parameters |
DISK_STATUS_NO_MEDIA = 2 ; no media present |
DISK_STATUS_END_OF_MEDIA = 3 ; end of media while reading/writing data |
; Called when all operations with the given disk are done. |
proc disk_close |
push ebx esi |
virtual at esp |
rd 2 ; saved registers |
dd ? ; return address |
.userdata dd ? |
end virtual |
mov esi, [.userdata] |
mov ecx, free_numbers_lock |
call MutexLock |
movzx eax, [esi+usb_unit_data.DiskIndex] |
bts [free_numbers], eax |
call MutexUnlock |
mov esi, [esi+usb_unit_data.Parent] |
lock dec [esi+usb_device_data.NumReferences] |
jnz .nothing |
mov eax, [esi+usb_device_data.LogicalDevices] |
call Kfree |
xchg eax, esi |
call Kfree |
.nothing: |
pop esi ebx |
ret 4 |
endp |
; Returns sector size, capacity and flags of the media. |
proc disk_querymedia stdcall uses ebx esi edi, \ |
userdata:dword, mediainfo:dword |
; 1. Create event for waiting. |
xor esi, esi |
xor ecx, ecx |
call CreateEvent |
test eax, eax |
jz .generic_fail |
push eax |
push edx |
push ecx |
push 0 |
push 0 |
virtual at ebp-.localsize |
.locals: |
; two following dwords are the output of READ_CAPACITY |
.LastLBABE dd ? |
.SectorSizeBE dd ? |
.Status dd ? |
; two following dwords identify an event |
.event_code dd ? |
.event dd ? |
rd 3 ; saved registers |
.localsize = $ - .locals |
dd ? ; saved ebp |
dd ? ; return address |
.userdata dd ? |
.mediainfo dd ? |
end virtual |
; 2. Initiate SCSI READ_CAPACITY request. |
mov eax, [userdata] |
mov ecx, [eax+usb_unit_data.Parent] |
mov edx, esp |
stdcall queue_request, ecx, read_capacity_req, edx, read_capacity_callback, edx |
; 3. Wait for event. This destroys it. |
mov eax, [.event] |
mov ebx, [.event_code] |
call WaitEvent |
; 4. Get the status and results. |
pop ecx |
bswap ecx ; .LastLBA |
pop edx |
bswap edx ; .SectorSize |
pop eax ; .Status |
; 5. If the request has completed successfully, store results. |
test eax, eax |
jnz @f |
DEBUGF 1,'K : sector size is %d, last sector is %d\n',edx,ecx |
mov ebx, [mediainfo] |
mov [ebx], eax ; flags = 0 |
mov [ebx+4], edx ; sectorsize |
add ecx, 1 |
adc eax, 0 |
mov [ebx+8], ecx |
mov [ebx+12], eax ; capacity |
mov eax, [userdata] |
mov [eax+usb_unit_data.SectorSize], edx |
xor eax, eax |
@@: |
; 6. Restore the stack and return. |
pop ecx |
pop ecx |
ret |
.generic_fail: |
or eax, -1 |
ret |
endp |
; Builder for SCSI READ_CAPACITY request. |
; edx = first argument = pointer to usb_device_data.Command, |
; second argument = custom data given to queue_request, |
; pointer to disk_querymedia.locals. |
proc read_capacity_req |
mov eax, [esp+8] |
mov eax, [eax+disk_querymedia.userdata-disk_querymedia.locals] |
mov al, [eax+usb_unit_data.LUN] |
mov [edx+command_block_wrapper.Length], 8 |
mov [edx+command_block_wrapper.Flags], CBW_FLAG_IN |
mov [edx+command_block_wrapper.LUN], al |
mov byte [edx+command_block_wrapper.Command+0], SCSI_READ_CAPACITY |
ret 8 |
endp |
; Called when SCSI READ_CAPACITY request is completed. |
proc read_capacity_callback |
; Transform the status to return value of disk_querymedia |
; and set the event. |
mov ecx, [esp+4] |
xor eax, eax |
cmp [ecx+usb_device_data.Status.Status], al |
jz @f |
or eax, -1 |
@@: |
mov ecx, [esp+8] |
mov [ecx+disk_querymedia.Status-disk_querymedia.locals], eax |
push ebx esi edi |
mov eax, [ecx+disk_querymedia.event-disk_querymedia.locals] |
mov ebx, [ecx+disk_querymedia.event_code-disk_querymedia.locals] |
xor edx, edx |
xor esi, esi |
call RaiseEvent |
pop edi esi ebx |
ret 8 |
endp |
disk_write: |
mov al, SCSI_WRITE10 |
jmp disk_read_write |
disk_read: |
mov al, SCSI_READ10 |
; Reads from the device or writes to the device. |
proc disk_read_write stdcall uses ebx esi edi, \ |
userdata:dword, buffer:dword, startsector:qword, numsectors:dword |
; 1. Initialize. |
push eax ; .command |
mov eax, [userdata] |
mov eax, [eax+usb_unit_data.SectorSize] |
push eax ; .SectorSize |
push 0 ; .processed |
mov eax, [numsectors] |
mov eax, [eax] |
; 2. The transfer length for SCSI_{READ,WRITE}10 commands can not be greater |
; than 0xFFFF, so split the request to slices with <= 0xFFFF sectors. |
max_sectors_at_time = 0xFFFF |
.split: |
push eax ; .length_rest |
cmp eax, max_sectors_at_time |
jb @f |
mov eax, max_sectors_at_time |
@@: |
sub [esp], eax |
push eax ; .length_cur |
; 3. startsector must fit in 32 bits, otherwise abort the request. |
cmp dword [startsector+4], 0 |
jnz .generic_fail |
; 4. Create event for waiting. |
xor esi, esi |
xor ecx, ecx |
call CreateEvent |
test eax, eax |
jz .generic_fail |
push eax ; .event |
push edx ; .event_code |
push ecx ; .status |
virtual at ebp-.localsize |
.locals: |
.status dd ? |
.event_code dd ? |
.event dd ? |
.length_cur dd ? |
.length_rest dd ? |
.processed dd ? |
.SectorSize dd ? |
.command db ? |
rb 3 |
rd 3 ; saved registers |
.localsize = $ - .locals |
dd ? ; saved ebp |
dd ? ; return address |
.userdata dd ? |
.buffer dd ? |
.startsector dq ? |
.numsectors dd ? |
end virtual |
; 5. Initiate SCSI READ10 or WRITE10 request. |
mov eax, [userdata] |
mov ecx, [eax+usb_unit_data.Parent] |
stdcall queue_request, ecx, read_write_req, [buffer], read_write_callback, esp |
; 6. Wait for event. This destroys it. |
mov eax, [.event] |
mov ebx, [.event_code] |
call WaitEvent |
; 7. Get the status. If the operation has failed, abort. |
pop eax ; .status |
pop ecx ecx ; cleanup .event_code, .event |
pop ecx ; .length_cur |
test eax, eax |
jnz .return |
; 8. Otherwise, continue the loop started at step 2. |
add dword [startsector], ecx |
adc dword [startsector+4], eax |
imul ecx, [.SectorSize] |
add [buffer], ecx |
pop eax |
test eax, eax |
jnz .split |
push eax |
.return: |
; 9. Restore the stack, store .processed to [numsectors], return. |
pop ecx ; .length_rest |
pop ecx ; .processed |
mov edx, [numsectors] |
mov [edx], ecx |
pop ecx ; .SectorSize |
pop ecx ; .command |
ret |
.generic_fail: |
or eax, -1 |
pop ecx ; .length_cur |
jmp .return |
endp |
; Builder for SCSI READ10 or WRITE10 request. |
; edx = first argument = pointer to usb_device_data.Command, |
; second argument = custom data given to queue_request, |
; pointer to disk_read_write.locals. |
proc read_write_req |
mov eax, [esp+8] |
mov ecx, [eax+disk_read_write.userdata-disk_read_write.locals] |
mov cl, [ecx+usb_unit_data.LUN] |
mov [edx+command_block_wrapper.LUN], cl |
mov ecx, [eax+disk_read_write.length_cur-disk_read_write.locals] |
imul ecx, [eax+disk_read_write.SectorSize-disk_read_write.locals] |
mov [edx+command_block_wrapper.Length], ecx |
mov cl, [eax+disk_read_write.command-disk_read_write.locals] |
mov [edx+command_block_wrapper.Flags], CBW_FLAG_OUT |
cmp cl, SCSI_READ10 |
jnz @f |
mov [edx+command_block_wrapper.Flags], CBW_FLAG_IN |
@@: |
mov byte [edx+command_block_wrapper.Command], cl |
mov ecx, dword [eax+disk_read_write.startsector-disk_read_write.locals] |
bswap ecx |
mov dword [edx+command_block_wrapper.Command+2], ecx |
mov ecx, [eax+disk_read_write.length_cur-disk_read_write.locals] |
xchg cl, ch |
mov word [edx+command_block_wrapper.Command+7], cx |
ret 8 |
endp |
; Called when SCSI READ10 or WRITE10 request is completed. |
proc read_write_callback |
; 1. Initialize. |
push ebx esi edi |
virtual at esp |
rd 3 ; saved registers |
dd ? ; return address |
.device dd ? |
.calldata dd ? |
end virtual |
mov ecx, [.device] |
mov esi, [.calldata] |
; 2. Get the number of sectors which were read. |
; If the status is OK or FAIL, the field .LengthRest is valid. |
; Otherwise, it is invalid, so assume zero sectors. |
xor eax, eax |
cmp [ecx+usb_device_data.Status.Status], CSW_STATUS_FAIL |
ja .sectors_calculated |
mov eax, [ecx+usb_device_data.LengthRest] |
xor edx, edx |
div [esi+disk_read_write.SectorSize-disk_read_write.locals] |
test edx, edx |
jz @f |
inc eax |
@@: |
mov edx, eax |
mov eax, [esi+disk_read_write.length_cur-disk_read_write.locals] |
sub eax, edx |
jae .sectors_calculated |
xor eax, eax |
.sectors_calculated: |
; 3. Increase the total number of processed sectors. |
add [esi+disk_read_write.processed-disk_read_write.locals], eax |
; 4. Set status to OK if all sectors were read, to ERROR otherwise. |
cmp eax, [esi+disk_read_write.length_cur-disk_read_write.locals] |
setz al |
movzx eax, al |
dec eax |
mov [esi+disk_read_write.status-disk_read_write.locals], eax |
; 5. Set the event. |
mov eax, [esi+disk_read_write.event-disk_read_write.locals] |
mov ebx, [esi+disk_read_write.event_code-disk_read_write.locals] |
xor edx, edx |
xor esi, esi |
call RaiseEvent |
; 6. Return. |
pop edi esi ebx |
ret 8 |
endp |
; strings |
my_driver db 'usbstor',0 |
disconnectmsg db 'K : USB mass storage device disconnected',13,10,0 |
nomemory db 'K : no memory',13,10,0 |
unkdevice db 'K : unknown mass storage device',13,10,0 |
okdevice db 'K : USB mass storage device detected',13,10,0 |
transfererror db 'K : USB transfer error, disabling mass storage',13,10,0 |
invresponse db 'K : invalid response from mass storage device',13,10,0 |
fatalerr db 'K : mass storage device reports fatal error',13,10,0 |
inquiry_fail db 'K : INQUIRY command failed',13,10,0 |
;read_capacity_fail db 'K : READ CAPACITY command failed',13,10,0 |
;read_fail db 'K : READ command failed',13,10,0 |
noindex db 'K : failed to generate disk name',13,10,0 |
; Exported variable: kernel API version. |
align 4 |
version dd 50005h |
; Structure with callback functions. |
usb_functions: |
dd usb_functions_end - usb_functions |
dd AddDevice |
dd DeviceDisconnected |
usb_functions_end: |
disk_functions: |
dd disk_functions_end - disk_functions |
dd disk_close |
dd 0 ; closemedia |
dd disk_querymedia |
dd disk_read |
dd disk_write |
dd 0 ; flush |
dd 0 ; adjust_cache_size: use default cache |
disk_functions_end: |
free_numbers_lock rd 3 |
; 128 devices should be enough for everybody |
free_numbers dd -1, -1, -1, -1 |
; for DEBUGF macro |
include_debug_strings |
; for uninitialized data |
section '.data' data readable writable align 16 |
/kernel/branches/Kolibri-acpi/drivers/agp.asm |
---|
0,0 → 1,310 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; simple AGP driver for KolibriOS ;; |
;; ;; |
;; Written by hidnplayr@kolibrios.org ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
format MS COFF |
DEBUG equ 1 |
FAST_WRITE equ 0 ; may cause problems with some motherboards |
include 'proc32.inc' |
include 'imports.inc' |
struc IOCTL |
{ .handle dd ? |
.io_code dd ? |
.input dd ? |
.inp_size dd ? |
.output dd ? |
.out_size dd ? |
} |
virtual at 0 |
IOCTL IOCTL |
end virtual |
public START |
public service_proc |
public version |
DRV_ENTRY equ 1 |
DRV_EXIT equ -1 |
SRV_GETVERSION equ 0 |
SRV_DETECT equ 1 |
API_VERSION equ 1 |
section '.flat' code readable align 16 |
proc START stdcall, state:dword |
cmp [state], 1 |
jne .exit |
.entry: |
if DEBUG |
mov esi, msgInit |
call SysMsgBoardStr |
end if |
stdcall RegService, my_service, service_proc |
ret |
.fail: |
.exit: |
xor eax, eax |
ret |
endp |
handle equ IOCTL.handle |
io_code equ IOCTL.io_code |
input equ IOCTL.input |
inp_size equ IOCTL.inp_size |
output equ IOCTL.output |
out_size equ IOCTL.out_size |
align 4 |
proc service_proc stdcall, ioctl:dword |
mov ebx, [ioctl] |
mov eax, [ebx+io_code] |
cmp eax, SRV_GETVERSION |
jne @F |
mov eax, [ebx+output] |
cmp [ebx+out_size], 4 |
jne .fail |
mov [eax], dword API_VERSION |
xor eax, eax |
ret |
@@: |
mov ebx, [ioctl] |
mov eax, [ebx+io_code] |
cmp eax, SRV_DETECT |
jne @F |
call detect |
@@: |
.fail: |
or eax, -1 |
ret |
endp |
restore handle |
restore io_code |
restore input |
restore inp_size |
restore output |
restore out_size |
align 4 |
proc detect |
locals |
last_bus dd ? |
endl |
mov esi, msgSearch |
call SysMsgBoardStr |
xor eax, eax |
mov [bus], eax |
inc eax |
call PciApi ; get last bus |
cmp eax, -1 |
je .error |
mov [last_bus], eax |
.next_bus: |
and [devfn], 0 |
.next_dev: |
stdcall PciRead16, [bus], [devfn], dword 0x0a ; read class/subclass |
cmp ax, 0x0300 ; display controller - vga compatable controller |
je .found |
cmp ax, 0x0302 ; display controller - 3d controller |
je .found |
cmp ax, 0x0380 ; display controller - other display controller |
je .found |
.next: |
inc [devfn] |
cmp [devfn], 256 |
jb .next_dev |
mov eax, [bus] |
inc eax |
mov [bus], eax |
cmp eax, [last_bus] |
jna .next_bus |
.error: |
mov esi, msgFail |
call SysMsgBoardStr |
xor eax, eax |
inc eax |
ret |
.found: |
stdcall PciRead8, [bus], [devfn], dword 0x06 ; read prog IF |
test al, 1 shl 4 ; got capabilities list? |
jnz .got_capabilities_list |
; TODO: Do it the old way: detect device and check with a list of known capabilities |
; stupid pre PCI 2.2 board.... |
jmp .next |
.got_capabilities_list: |
stdcall PciRead8, [bus], [devfn], dword 0x34 ; read capabilities offset |
and eax, 11111100b ; always dword aligned |
mov edi, eax |
.read_capability: |
stdcall PciRead32, [bus], [devfn], edi ; read capability |
cmp al, 0x02 ; AGP |
je .got_agp |
movzx edi, ah ; pointer to next capability |
test edi, edi |
jnz .read_capability |
jmp .next |
.got_agp: |
shr eax, 16 |
mov [revision], al ; high nibble = major revision |
; low nibble = minor revision |
add edi, 4 |
and al, 0xf0 |
cmp al, 0x30 |
je .agp_3 |
.agp_2: |
mov esi, msgAGP2 |
call SysMsgBoardStr |
stdcall PciRead32, [bus], [devfn], edi ; read AGP status |
.agp_2_: |
test al, 100b |
jnz .100b |
test al, 10b |
jnz .010b |
test al, 1b |
jz .error |
.001b: |
mov [cmd], 001b |
mov esi, msg1 |
call SysMsgBoardStr |
jmp .agp_go |
.010b: |
mov [cmd], 010b |
mov esi, msg2 |
call SysMsgBoardStr |
jmp .agp_go |
.100b: |
mov [cmd], 100b |
mov esi, msg4 |
call SysMsgBoardStr |
jmp .agp_go |
.agp_2m: |
mov esi, msgAGP2m |
call SysMsgBoardStr |
jmp .agp_2_ |
.agp_3: |
mov esi, msgAGP3 |
call SysMsgBoardStr |
stdcall PciRead32, [bus], [devfn], edi ; read AGP status |
test al, 1 shl 3 |
jz .agp_2m |
test eax, 10b |
jnz .8x |
mov [cmd], 01b |
mov esi, msg4 |
call SysMsgBoardStr |
jmp .agp_go |
.8x: |
mov [cmd], 10b |
mov esi, msg8 |
call SysMsgBoardStr |
.agp_go: |
if FAST_WRITE |
test ax, 1 shl 4 |
jz @f |
or [cmd], 1 shl 4 |
mov esi, msgfast |
call SysMsgBoardStr |
@@: |
end if |
test ax, 1 shl 9 ; Side band addressing |
jz @f |
or [cmd], 1 shl 9 |
mov esi, msgside |
call SysMsgBoardStr |
@@: |
add edi, 4 |
mov eax, [cmd] |
or eax, 1 shl 8 ; enable AGP |
stdcall PciWrite32, [bus], [devfn], edi, eax ; write AGP cmd |
mov esi, msgOK |
call SysMsgBoardStr |
ret |
endp |
; initialized data |
align 4 |
version dd (5 shl 16) or (API_VERSION and 0xFFFF) |
my_service db 'AGP', 0 ; max 16 chars include zero |
msgInit db 'AGP driver loaded.', 13, 10, 0 |
msgSearch db 'Searching for AGP card...', 13, 10, 0 |
msgFail db 'device not found', 13, 10, 0 |
msgOK db 'AGP device enabled', 13, 10, 0 |
msgAGP2 db 'AGP2 device found', 13, 10, 0 |
msgAGP3 db 'AGP3 device found', 13, 10, 0 |
msgAGP2m db 'Running in AGP2 mode', 13, 10, 0 |
msg8 db '8x speed', 13, 10, 0 |
msg4 db '4x speed', 13, 10, 0 |
msg2 db '2x speed', 13, 10, 0 |
msg1 db '1x speed', 13, 10, 0 |
msgfast db 'Fast Write', 13, 10, 0 |
msgside db 'Side band addressing', 13, 10, 0 |
section '.data' data readable writable align 16 |
; uninitialized data |
revision db ? |
cmd dd ? |
bus dd ? |
devfn dd ? |
/kernel/branches/Kolibri-acpi/drivers/apm.asm |
---|
0,0 → 1,350 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2009-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
; 11.09.2009 staper@inbox.ru |
; see kernel\docs\apm.txt |
use32 |
org 0x0 |
db 'MENUET01' |
dd 0x1 |
dd START |
dd I_END |
dd (I_END+100) and not 3 |
dd (I_END+100) and not 3 |
dd 0x0,0x0 |
include 'macros.inc' |
START: |
mcall 40,0x7 |
mcall 49,0x0001,0x0001,0x5308 ;CX = FFFFh APM v1.0 |
; mcall 49,0x0001,0x0001,0x530d |
; mcall 49,0x0001,0x0001,0x530f |
; mcall 49,0x0000,,0x5310 ;bl - number of batteries |
redraw: |
mcall 49,0x0000,,0x530c |
dec cl |
jz still |
mcall 49,0x0001,0x0001,0x5308 |
mcall 49,0x01ff,,0x530c |
test cl, cl |
jz @f |
mcall 49,0x0000,0x0001,0x530d |
mcall 49,0x0000,0x0000,0x5307 |
mcall 49,0x0000,0x0001,0x5308 |
@@: |
mcall 12,1 |
mcall 0,100*65536+235,100*65536+90,0x34ffffff,0x000000,title |
mcall 49,0x0000,,0x5300 |
jnc @f |
mcall 4,10*65536+3,0x80000000,text.4 |
bts [flags], 1 |
jmp .end |
@@: |
cmp al, 0 |
jne @f |
mov edx, text.1 |
jmp .0 |
@@: |
cmp al, 1 |
jne @f |
mov edx, text.2 |
jmp .0 |
@@: |
mov edx, text.3 |
.0: |
push edx |
mcall 4,169*65536+3,0x80dddddd,text.0 |
pop edx |
add ebx, 47*65536 |
mcall |
mcall 49,0x0001,,0x530a |
jc .error |
push si dx cx bx ;time of battery life, b. flag, b. status, AC line status |
;AC line status |
cmp bh, 0 |
jne @f |
mov edx, text.01 |
jmp .1 |
@@: |
cmp bh, 1 |
jne @f |
mov edx, text.02 |
jmp .1 |
@@: |
cmp bh, 2 |
jne @f |
mov edx, text.03 |
jmp .1 |
@@: |
mov edx, text.04 |
.1: |
push edx |
mcall 4,10*65536+10,0x80000000,text.00 |
pop edx |
mcall ,100*65536+10,;0x80000000 |
;battery status |
pop bx |
cmp bl, 0 |
jne @f |
mov edx, text.11 |
jmp .2 |
@@: |
cmp bl, 1 |
jne @f |
mov edx, text.12 |
jmp .2 |
@@: |
cmp bl, 2 |
jne @f |
mov edx, text.13 |
jmp .2 |
@@: |
cmp bl, 3 |
jne @f |
mov edx, text.14 |
jmp .2 |
@@: |
mov edx, text.04 |
.2: |
push edx |
mcall 4,10*65536+20,0x80000000,text.10 |
pop edx |
mcall ,100*65536+20, |
;battery life, percentage and minutes/seconds |
mcall ,10*65536+30,,text.20 |
pop cx |
cmp cl, 0xff |
jne @f |
mcall ,100*65536+30,0x80000000,text.04 |
pop eax |
jmp .end |
@@: |
shl ecx, 24 |
shr ecx, 24 |
mcall 47,0x80030000,,100*65536+30,0x347636 |
.3: |
mcall 4,115*65536+30,0x80000000,text.15 |
mov dx, [esp] |
shl edx, 17 |
shr edx, 17 |
mov ecx, edx |
mcall 47,0x80030000,,140*65536+30 |
pop cx |
mov edx, text.21 |
bt cx, 15 |
jc @f |
mov edx, text.22 |
@@: |
mcall 4,160*65536+30,0x80000000 |
pop si |
.error: |
.end: |
;buttons |
mcall 8,148*65536+16,45*65536+15,3,0x00677ab0 |
mcall ,166*65536+16,,4, |
mcall ,184*65536+16,,5, |
mcall ,202*65536+16,,6, |
bt [flags], 1 |
jc @f |
mcall ,65*65536+45,,2, |
@@: |
mcall 4,10*65536+50,0x80564242,text.30 |
mcall 12,2 |
still: |
; mcall 10 |
mcall 23,12000 |
test eax, eax |
jz redraw |
dec al |
jz redraw |
dec al |
jz key |
dec al |
jz button |
jmp still |
key: |
mcall 2 |
jmp still |
button: |
mcall 17 |
cmp ah, 1 |
jne @f |
mcall -1 |
@@: |
cmp ah, 2 |
jne @f |
mcall 5,50 |
mcall 49,0x0001,0x0001,0x5307 |
jmp redraw |
@@: |
cmp ah, 4 |
jg @f |
mov edx, 0x01f7 ;primary chan. |
call reserv_ports |
jc redraw |
sub bh, 3 |
.1: |
call set_drive |
btc [flags], 2 |
jnc .2 |
call device_reset |
jmp .3 |
.2: |
call standby_hdd |
.3: |
call free_ports |
jmp redraw |
@@: |
cmp ah, 6 |
jg redraw |
mov edx, 0x0177 ;secondary chan. |
call reserv_ports |
jc redraw |
sub bh, 5 |
jmp .1 |
set_drive: |
dec dx |
in al, dx |
test bh, bh |
jnz @f |
btr ax, 4 |
.1: |
out dx, al |
inc dx |
ret |
@@: |
bts ax, 4 |
jmp .1 |
standby_hdd: |
; 94h E0h nondata standby immediate |
; 95h E1h nondata idle immediate |
; 96h E2h nondata standby |
; 97h E3h nondata idle |
; 98h E5h nondata check power mode |
; 99h E6h nondata set sleep mode |
xor ecx, ecx |
@@: |
in al, dx |
dec cx |
jz @f |
bt ax, 6 |
jnc @b |
mov al, 0x96 |
out dx, al |
mov al, 0xe2 |
out dx, al |
@@: |
ret |
reserv_ports: |
mov ecx, edx |
dec ecx |
push ax |
mcall 46,0 |
test al, al |
jnz @f |
pop bx |
clc |
ret |
@@: |
pop bx |
stc |
ret |
device_reset: |
xor ecx, ecx |
@@: |
in al, dx |
dec cx |
jz @f |
bt ax, 6 |
jnc @b |
mov al, 0x10 |
out dx, al |
@@: |
ret |
free_ports: |
mov ecx, edx |
dec ecx |
mcall 46,1 |
ret |
; ДАННЫЕ ПРОГРАММЫ |
title db '',0 |
flags dw 0 |
text: |
.0: |
db 'APM v.1.',0 |
.1: |
db '0',0 |
.2: |
db '1',0 |
.3: |
db '2',0 |
.4: |
db 'APM not supported',0 |
.00: |
db 'power status:',0 |
.01: |
db 'off-line',0 |
.02: |
db 'on-line',0 |
.03: |
db 'on backup power',0 |
.04: |
db 'unknown',0 |
.10: |
db 'battery flag:',0 |
.11: |
db 'high',0 |
.12: |
db 'low',0 |
.13: |
db 'critical',0 |
.14: |
db 'charging',0 |
.15: |
db ' % ,',0 |
.20: |
db 'battery life:',0 |
.21: |
db 'min',0 |
.22: |
db 'sec',0 |
.30: |
db 'STAND-BY: SYSTEM HDD: 0 1 2 3',0 |
I_END: |
/kernel/branches/Kolibri-acpi/drivers/fdo.inc |
---|
0,0 → 1,453 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2007. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
_esp equ esp |
; |
; Formatted Debug Output (FDO) |
; Copyright (c) 2005-2006, mike.dld |
; Created: 2005-01-29, Changed: 2006-11-10 |
; |
; For questions and bug reports, mail to mike.dld@gmail.com |
; |
; Available format specifiers are: %s, %d, %u, %x (with partial width support) |
; |
; to be defined: |
; __DEBUG__ equ 1 |
; __DEBUG_LEVEL__ equ 5 |
; MOV Immediate. |
; Useful for things like movi eax,10: |
; shorter than regular mov, but slightly slower, |
; do not use it in performance-critical places. |
macro movi dst, imm |
{ |
if imm >= -0x80 & imm <= 0x7F |
push imm |
pop dst |
else |
mov dst, imm |
end if |
} |
macro debug_func name { |
if used name |
name@of@func equ name |
} |
macro debug_beginf { |
align 4 |
name@of@func: |
} |
debug_endf fix end if |
macro DEBUGS _sign,[_str] { |
common |
local tp |
tp equ 0 |
match _arg:_num,_str \{ |
DEBUGS_N _sign,_num,_arg |
tp equ 1 |
\} |
match =0 _arg,tp _str \{ |
DEBUGS_N _sign,,_arg |
\} |
} |
macro DEBUGS_N _sign,_num,[_str] { |
common |
pushf |
pushad |
local ..str,..label,is_str |
is_str = 0 |
forward |
if _str eqtype '' |
is_str = 1 |
end if |
common |
if is_str = 1 |
jmp ..label |
..str db _str,0 |
..label: |
mov edx, ..str |
else |
esp equ esp+4*8+4 |
mov edx, _str |
esp equ _esp |
end if |
if ~_num eq |
if _num eqtype eax |
if _num in <eax,ebx,ecx,edx,edi,ebp,esp> |
mov esi, _num |
else if ~_num eq esi |
movzx esi, _num |
end if |
else if _num eqtype 0 |
mov esi, _num |
else |
local tp |
tp equ 0 |
match [_arg],_num \{ |
mov esi, dword[_arg] |
tp equ 1 |
\} |
match =0 =dword[_arg],tp _num \{ |
mov esi, dword[_arg] |
tp equ 1 |
\} |
match =0 =word[_arg],tp _num \{ |
movzx esi, word[_arg] |
tp equ 1 |
\} |
match =0 =byte[_arg],tp _num \{ |
movzx esi, byte[_arg] |
tp equ 1 |
\} |
match =0,tp \{ |
'Error: specified string width is incorrect' |
\} |
end if |
else |
mov esi, 0x7FFFFFFF |
end if |
call fdo_debug_outstr |
popad |
popf |
} |
macro DEBUGD _sign,_dec { |
local tp |
tp equ 0 |
match _arg:_num,_dec \{ |
DEBUGD_N _sign,_num,_arg |
tp equ 1 |
\} |
match =0 _arg,tp _dec \{ |
DEBUGD_N _sign,,_arg |
\} |
} |
macro DEBUGD_N _sign,_num,_dec { |
pushf |
pushad |
if (~_num eq) |
if (_dec eqtype eax | _dec eqtype 0) |
'Error: precision allowed only for in-memory variables' |
end if |
if (~_num in <1,2,4>) |
if _sign |
'Error: 1, 2 and 4 are only allowed for precision in %d' |
else |
'Error: 1, 2 and 4 are only allowed for precision in %u' |
end if |
end if |
end if |
if _dec eqtype eax |
if _dec in <ebx,ecx,edx,esi,edi,ebp,esp> |
mov eax, _dec |
else if ~_dec eq eax |
if _sign = 1 |
movsx eax, _dec |
else |
movzx eax, _dec |
end if |
end if |
else if _dec eqtype 0 |
mov eax, _dec |
else |
esp equ esp+4*8+4 |
if _num eq |
mov eax, dword _dec |
else if _num = 1 |
if _sign = 1 |
movsx eax, byte _dec |
else |
movzx eax, byte _dec |
end if |
else if _num = 2 |
if _sign = 1 |
movsx eax, word _dec |
else |
movzx eax, word _dec |
end if |
else |
mov eax, dword _dec |
end if |
esp equ _esp |
end if |
mov cl, _sign |
call fdo_debug_outdec |
popad |
popf |
} |
macro DEBUGH _sign,_hex { |
local tp |
tp equ 0 |
match _arg:_num,_hex \{ |
DEBUGH_N _sign,_num,_arg |
tp equ 1 |
\} |
match =0 _arg,tp _hex \{ |
DEBUGH_N _sign,,_arg |
\} |
} |
macro DEBUGH_N _sign,_num,_hex { |
pushf |
pushad |
if (~_num eq) & (~_num in <1,2,3,4,5,6,7,8>) |
'Error: 1..8 are only allowed for precision in %x' |
end if |
if _hex eqtype eax |
if _hex in <eax,ebx,ecx,edx,esi,edi,ebp,esp> |
if ~_hex eq eax |
mov eax, _hex |
end if |
mov edx, 8 |
else if _hex in <ax,bx,cx,dx,si,di,bp,sp> |
if ~_hex eq ax |
movzx eax, _hex |
end if |
if (_num eq) |
mov edx, 4 |
end if |
else if _hex in <al,ah,bl,bh,cl,ch,dl,dh> |
if ~_hex eq al |
movzx eax, _hex |
end if |
if (_num eq) |
mov edx, 2 |
end if |
end if |
else if _hex eqtype 0 |
mov eax, _hex |
else |
esp equ esp+4*8+4 |
mov eax, dword _hex |
esp equ _esp |
end if |
if ~_num eq |
mov edx, _num |
else |
if ~_hex eqtype eax |
mov edx, 8 |
end if |
end if |
call fdo_debug_outhex |
popad |
popf |
} |
;----------------------------------------------------------------------------- |
debug_func fdo_debug_outchar |
debug_beginf |
pushad |
movzx ecx, al |
mov ebx, 1 |
; mov ecx,sys_msg_board |
; call ecx ; sys_msg_board |
stdcall SysMsgBoard |
popad |
ret |
debug_endf |
debug_func fdo_debug_outstr |
debug_beginf |
mov ebx, 1 |
.l1: |
dec esi |
js .l2 |
movzx ecx, byte[edx] |
or cl, cl |
jz .l2 |
; mov ecx,sys_msg_board |
; call ecx ; sys_msg_board |
stdcall SysMsgBoard |
inc edx |
jmp .l1 |
.l2: |
ret |
debug_endf |
debug_func fdo_debug_outdec |
debug_beginf |
or cl, cl |
jz @f |
or eax, eax |
jns @f |
neg eax |
push eax |
mov al, '-' |
call fdo_debug_outchar |
pop eax |
@@: |
movi ecx, 10 |
push -'0' |
.l1: |
xor edx, edx |
div ecx |
push edx |
test eax, eax |
jnz .l1 |
.l2: |
pop eax |
add al, '0' |
jz .l3 |
call fdo_debug_outchar |
jmp .l2 |
.l3: |
ret |
debug_endf |
debug_func fdo_debug_outhex |
__fdo_hexdigits db '0123456789ABCDEF' |
debug_beginf |
mov cl, dl |
neg cl |
add cl, 8 |
shl cl, 2 |
rol eax, cl |
.l1: |
rol eax, 4 |
push eax |
and eax, 0x0000000F |
mov al, [__fdo_hexdigits+eax] |
call fdo_debug_outchar |
pop eax |
dec edx |
jnz .l1 |
ret |
debug_endf |
;----------------------------------------------------------------------------- |
macro DEBUGF _level,_format,[_arg] { |
common |
if __DEBUG__ = 1 & _level >= __DEBUG_LEVEL__ |
local ..f1,f2,a1,a2,c1,c2,c3,..lbl |
_debug_str_ equ __debug_str_ # a1 |
a1 = 0 |
c2 = 0 |
c3 = 0 |
f2 = 0 |
repeat ..lbl-..f1 |
virtual at 0 |
db _format,0,0 |
load c1 word from %-1 |
end virtual |
if c1 = '%s' |
virtual at 0 |
db _format,0,0 |
store word 0 at %-1 |
load c1 from f2-c2 |
end virtual |
if c1 <> 0 |
DEBUGS 0,_debug_str_+f2-c2 |
end if |
c2 = c2 + 1 |
f2 = %+1 |
DEBUGF_HELPER S,a1,0,_arg |
else if c1 = '%x' |
virtual at 0 |
db _format,0,0 |
store word 0 at %-1 |
load c1 from f2-c2 |
end virtual |
if c1 <> 0 |
DEBUGS 0,_debug_str_+f2-c2 |
end if |
c2 = c2 + 1 |
f2 = %+1 |
DEBUGF_HELPER H,a1,0,_arg |
else if c1 = '%d' | c1 = '%u' |
local c4 |
if c1 = '%d' |
c4 = 1 |
else |
c4 = 0 |
end if |
virtual at 0 |
db _format,0,0 |
store word 0 at %-1 |
load c1 from f2-c2 |
end virtual |
if c1 <> 0 |
DEBUGS 0,_debug_str_+f2-c2 |
end if |
c2 = c2 + 1 |
f2 = %+1 |
DEBUGF_HELPER D,a1,c4,_arg |
else if c1 = '\n' |
c3 = c3 + 1 |
end if |
end repeat |
virtual at 0 |
db _format,0,0 |
load c1 from f2-c2 |
end virtual |
if (c1<>0)&(f2<>..lbl-..f1-1) |
DEBUGS 0,_debug_str_+f2-c2 |
end if |
virtual at 0 |
..f1 db _format,0 |
..lbl: |
__debug_strings equ __debug_strings,_debug_str_,<_format>,..lbl-..f1-1-c2-c3 |
end virtual |
end if |
} |
macro __include_debug_strings dummy,[_id,_fmt,_len] { |
common |
local c1,a1,a2 |
forward |
if defined _len & ~_len eq |
_id: |
a1 = 0 |
a2 = 0 |
repeat _len |
virtual at 0 |
db _fmt,0,0 |
load c1 word from %+a2-1 |
end virtual |
if (c1='%s')|(c1='%x')|(c1='%d')|(c1='%u') |
db 0 |
a2 = a2 + 1 |
else if (c1='\n') |
dw $0A0D |
a1 = a1 + 1 |
a2 = a2 + 1 |
else |
db c1 and 0x0FF |
end if |
end repeat |
db 0 |
end if |
} |
macro DEBUGF_HELPER _letter,_num,_sign,[_arg] { |
common |
local num |
num = 0 |
forward |
if num = _num |
DEBUG#_letter _sign,_arg |
end if |
num = num+1 |
common |
_num = _num+1 |
} |
macro include_debug_strings { |
if __DEBUG__ = 1 |
match dbg_str,__debug_strings \{ |
__include_debug_strings dbg_str |
\} |
end if |
} |
/kernel/branches/Kolibri-acpi/drivers/usbhid/keyboard.inc |
---|
0,0 → 1,475 |
; HID keyboard driver, part of USBHID driver. |
; Global constants. |
; They are assembled in a macro to separate code and data; |
; the code is located at the point of "include 'keyboard.inc'", |
; the data are collected when workers_globals is instantiated. |
macro workers_globals |
{ |
; include global constants from previous workers |
workers_globals |
align 4 |
; Callbacks for HID layer. |
keyboard_driver: |
dd keyboard_driver_add_device |
dd keyboard_driver_disconnect |
dd keyboard_driver_begin_packet |
dd keyboard_driver_array_overflow? |
dd keyboard_driver_input_field |
dd keyboard_driver_end_packet |
; Callbacks for keyboard layer. |
kbd_functions: |
dd 12 |
dd CloseKeyboard |
dd SetKeyboardLights |
; Kernel keyboard layer takes input in form of PS/2 scancodes. |
; data for keyboard: correspondence between HID usage keys and PS/2 scancodes. |
EX = 80h ; if set, precede the scancode with special scancode 0xE0 |
label control_keys byte |
; Usages 700E0h ... 700E7h: LCtrl, LShift, LAlt, LWin, RCtrl, RShift, RAlt, RWin |
db 1Dh, 2Ah, 38h, 5Bh+EX, 1Dh+EX, 36h, 38h+EX, 5Ch+EX |
; Usages 70004h ... 70004h + normal_keys_number - 1 |
label normal_keys byte |
db 1Eh, 30h, 2Eh, 20h, 12h, 21h, 22h, 23h, 17h, 24h, 25h, 26h, 32h, 31h, 18h, 19h |
db 10h, 13h, 1Fh, 14h, 16h, 2Fh, 11h, 2Dh, 15h, 2Ch, 02h, 03h, 04h, 05h, 06h, 07h |
db 08h, 09h, 0Ah, 0Bh, 1Ch, 01h, 0Eh, 0Fh, 39h, 0Ch, 0Dh, 1Ah, 1Bh, 2Bh, 0, 27h |
db 28h, 29h, 33h, 34h, 35h, 3Ah, 3Bh, 3Ch, 3Dh, 3Eh, 3Fh, 40h, 41h, 42h, 43h, 44h |
db 57h, 58h,37h+EX,46h,0,52h+EX,47h+EX,49h+EX,53h+EX,4Fh+EX,51h+EX,4Dh+EX,4Bh+EX,50h+EX,48h+EX,45h |
db 35h+EX,37h,4Ah,4Eh,1Ch+EX,4Fh,50h, 51h, 4Bh, 4Ch, 4Dh, 47h, 48h, 49h, 52h, 53h |
db 0,5Dh+EX,5Eh+EX |
normal_keys_number = $ - normal_keys |
} |
; Data that are specific for one keyboard device. |
struct keyboard_device_data |
handle dd ? ; keyboard handle from RegKeyboard |
timer dd ? ; auto-repeat timer handle |
repeatkey db ? ; auto-repeat key code |
rb 3 ; padding |
usbdev dd ? ; pointer to device_data of USB and HID layers |
modifiers dd ? ; state of LCtrl ... RWin |
led_report dd ? ; output report for LEDs state |
numlock_bit dd ? ; position of NumLock bit in LED output report |
capslock_bit dd ? |
scrolllock_bit dd ? ; guess what |
ends |
; This procedure is called when HID layer detects a new keyboard. |
; in: ebx -> usb_device_data, edi -> collection |
; out: eax = device-specific data or NULL on error |
proc keyboard_driver_add_device |
; 1. Allocate memory for keyboard_device_data. If failed, return NULL. |
movi eax, sizeof.keyboard_device_data |
call Kmalloc |
test eax, eax |
jz .nothing |
; 2. Initialize keyboard_device_data: store pointer to USB layer data, |
; zero some fields, initialize bit positions to -1. |
mov [eax+keyboard_device_data.usbdev], ebx |
xor ecx, ecx |
mov [eax+keyboard_device_data.timer], ecx |
mov [eax+keyboard_device_data.repeatkey], cl |
mov [eax+keyboard_device_data.modifiers], ecx |
mov [eax+keyboard_device_data.led_report], ecx |
dec ecx |
mov [eax+keyboard_device_data.numlock_bit], ecx |
mov [eax+keyboard_device_data.capslock_bit], ecx |
mov [eax+keyboard_device_data.scrolllock_bit], ecx |
; 3. Look for LED report and bits corresponding to indicators. |
; For now, assume that all LEDs are set by the same report. |
; 3a. Save registers. |
push ebx esi |
; 3b. Prepare for loop over output reports: get the first output report. |
; If there are no output records, skip step 3; |
; default values of led_report and *_bit were set in step 2. |
mov edx, [edi+collection.output.first_report] |
test edx, edx |
jz .led_report_set |
.scan_led_report: |
; Process one output report. |
; 3c. Prepare for loop over field groups in the current report: |
; get the first field group. |
mov ecx, [edx+report.first_field] |
.scan_led_field: |
; Process one field group. |
; 3d. If there are no more field groups, exit the loop over field groups. |
test ecx, ecx |
jz .next_led_report |
; For now, assume that all LEDs are plain variable fields, not arrays. |
; 3e. Ignore array field groups. |
test byte [ecx+report_field_group.flags], HID_FIELD_VARIABLE |
jz .next_led_field |
; 3f. Loop over all fields in the current group. |
push [ecx+report_field_group.count] |
; esi = pointer to usage of the current field |
lea esi, [ecx+report_field_group.common_sizeof] |
; ebx = bit position of the current field |
mov ebx, [ecx+report_field_group.offset] |
; if report is numbered, add extra byte in the start of report |
cmp [edx+report.id], 0 |
jz .scan_led_usage |
add ebx, 8 |
.scan_led_usage: |
; for USAGE_LED_*LOCK, store the current bit position in the corresponding field |
; and store the current report as the LED report |
cmp dword [esi], USAGE_LED_NUMLOCK |
jz .numlock |
cmp dword [esi], USAGE_LED_CAPSLOCK |
jz .capslock |
cmp dword [esi], USAGE_LED_SCROLLLOCK |
jnz .next_field |
.scrolllock: |
mov [eax+keyboard_device_data.scrolllock_bit], ebx |
jmp @f |
.capslock: |
mov [eax+keyboard_device_data.capslock_bit], ebx |
jmp @f |
.numlock: |
mov [eax+keyboard_device_data.numlock_bit], ebx |
@@: |
mov [eax+keyboard_device_data.led_report], edx |
.next_field: |
add esi, 4 |
add ebx, [ecx+report_field_group.size] |
dec dword [esp] |
jnz .scan_led_usage |
pop ebx |
.next_led_field: |
; 3g. Continue loop over field groups: get next field group. |
mov ecx, [ecx+report_field_group.next] |
jmp .scan_led_field |
.next_led_report: |
; 3h. If the LED report has been set, break from the loop over reports. |
; Otherwise, get the next report and continue if the current report is not |
; the last for this collection. |
cmp [eax+keyboard_device_data.led_report], 0 |
jnz .led_report_set |
cmp edx, [edi+collection.output.last_report] |
mov edx, [edx+report.next] |
jnz .scan_led_report |
.led_report_set: |
; 3i. Restore registers. |
pop esi ebx |
; 4. Register keyboard in the kernel. |
; store pointer to keyboard_device_data in the stack |
push eax |
; call kernel API |
stdcall RegKeyboard, kbd_functions, eax |
; restore pointer to keyboard_device_data from the stack, |
; putting keyboard handle from API to the stack |
xchg eax, [esp] |
; put keyboard handle from API from the stack to keyboard_device_data field |
pop [eax+keyboard_device_data.handle] |
; If failed, free keyboard_device_data and return NULL. |
cmp [eax+keyboard_device_data.handle], 0 |
jz .fail_free |
; 5. Return pointer to keyboard_device_data. |
.nothing: |
ret |
.fail_free: |
call Kfree |
xor eax, eax |
ret |
endp |
; This procedure is called when HID layer detects disconnect of a previously |
; connected keyboard. |
; in: edi -> keyboard_device_data (pointer returned from keyboard_driver_add_device) |
proc keyboard_driver_disconnect |
; 1. If an autorepeat timer is active, stop it. |
cmp [edi+keyboard_device_data.timer], 0 |
jz @f |
stdcall CancelTimerHS, [edi+keyboard_device_data.timer] |
@@: |
; 2. Unregister keyboard in the kernel. |
stdcall DelKeyboard, [edi+keyboard_device_data.handle] |
; We should free data in CloseKeyboard, not here. |
ret |
endp |
; This procedure is called when HID layer starts processing a new input packet |
; from a keyboard. |
; in: edi -> keyboard_device_data (pointer returned from keyboard_driver_add_device) |
proc keyboard_driver_begin_packet |
; Nothing to do. |
ret |
endp |
; This procedure is called when HID layer processes every non-empty array field group. |
; in: edi -> keyboard_device_data (pointer returned from keyboard_driver_add_device) |
; in: ecx = fields count (always nonzero), edx = pointer to fields values |
; in: esi -> report_field_group |
; out: CF set => group is ok, CF cleared => group should be ignored |
proc keyboard_driver_array_overflow? |
; The keyboard signals array overflow by filling the entire array with |
; USAGE_KBD_ROLLOVER codes. |
mov eax, [edx] ; eax = first field in the array |
sub eax, USAGE_KBD_ROLLOVER ; eax = 0 if overflow, nonzero otherwise |
neg eax ; CF cleared if eax was zero, CF set if eax was nonzero |
ret |
endp |
; This procedure is called from HID layer for every field. |
; in: edi -> keyboard_device_data (pointer returned from keyboard_driver_add_device) |
; in: ecx = field usage, edx = value, esi -> report_field_group |
proc keyboard_driver_input_field |
if HID_DUMP_UNCLAIMED |
.unclaimed = default_driver_input_field |
end if |
; 1. Process normal keys: |
; from USAGE_KBD_FIRST_KEY to USAGE_KBD_FIRST_KEY + normal_keys_number - 1, |
; excluding zeroes in [normal_keys]. |
; 1a. Test whether usage is in the range. |
lea eax, [ecx-USAGE_KBD_FIRST_KEY] |
cmp eax, normal_keys_number |
jae .not_normal_key |
; 1b. If the corresponding entry in [normal_keys] is zero, |
; pass this field to the default handler - if HID_DUMP_UNCLAIMED is enabled, |
; default handler is default_driver_input_field, otherwise just ignore the field. |
cmp [normal_keys + eax], 0 |
jz .unclaimed |
; 1c. Get the scancode. |
movzx ecx, [normal_keys + eax] |
; 1d. Further actions are slightly different for key press and key release. |
; Decide what to do. |
test edx, edx |
jz .normal_key_released |
.normal_key_pressed: |
; The key is pressed. |
; 1e. Store the last pressed key for autorepeat. |
mov [edi+keyboard_device_data.repeatkey], cl |
; 1f. Copy bit 7 to CF and send scancode with bit 7 cleared. |
btr ecx, 7 |
call .send_key |
; 1g. Stop the previous autorepeat timer, if any. |
mov eax, [edi+keyboard_device_data.timer] |
test eax, eax |
jz @f |
stdcall CancelTimerHS, eax |
@@: |
; 1h. Start the new autorepeat timer with 250 ms initial delay |
; and 50 ms subsequent delays. |
stdcall TimerHS, 25, 5, autorepeat_timer, edi |
mov [edi+keyboard_device_data.timer], eax |
if ~HID_DUMP_UNCLAIMED |
.unclaimed: |
end if |
ret |
.normal_key_released: |
; The key is released. |
; 1i. Stop the autorepeat timer if it is autorepeating the released key. |
cmp [edi+keyboard_device_data.repeatkey], cl |
jnz .no_stop_timer |
push ecx |
mov [edi+keyboard_device_data.repeatkey], 0 |
mov eax, [edi+keyboard_device_data.timer] |
test eax, eax |
jz @f |
stdcall CancelTimerHS, eax |
mov [edi+keyboard_device_data.timer], 0 |
@@: |
pop ecx |
.no_stop_timer: |
; 1j. Copy bit 7 to CF and send scancode with bit 7 set. |
bts ecx, 7 |
call .send_key |
ret |
.not_normal_key: |
; 2. USAGE_KBD_NOEVENT is simply a filler for free array fields, |
; ignore it. |
cmp ecx, USAGE_KBD_NOEVENT |
jz .nothing |
; 3. Process modifiers: 8 keys starting at USAGE_KBD_LCTRL. |
; 3a. Test whether usage is in range. |
; If not, we don't know what this field means, so pass it to the default handler. |
lea eax, [ecx-USAGE_KBD_LCTRL] |
cmp eax, 8 |
jae .unclaimed |
; 3b. Further actions are slightly different for modifier press |
; and modifier release. Decide what to do. |
test edx, edx |
jz .modifier_not_pressed |
.modifier_pressed: |
; The modifier is pressed. |
; 3c. Set the corresponding status bit. |
; If it was not set, send the corresponding scancode to the kernel |
; with bit 7 cleared. |
bts [edi+keyboard_device_data.modifiers], eax |
jc @f |
movzx ecx, [control_keys+eax] |
btr ecx, 7 |
call .send_key |
@@: |
.nothing: |
ret |
.modifier_not_pressed: |
; The modifier is not pressed. |
; 3d. Clear the correspodning status bit. |
; If it was set, send the corresponding scancode to the kernel |
; with bit 7 set. |
btr [edi+keyboard_device_data.modifiers], eax |
jnc @f |
movzx ecx, [control_keys+eax] |
bts ecx, 7 |
call .send_key |
@@: |
ret |
; Helper procedure. Sends scancode from cl to the kernel. |
; If CF is set, precede it with special code 0xE0. |
.send_key: |
jnc @f |
push ecx |
mov ecx, 0xE0 |
call SetKeyboardData |
pop ecx |
@@: |
call SetKeyboardData |
ret |
endp |
; This procedure is called when HID layer ends processing a new input packet |
; from a keyboard. |
; in: edi -> keyboard_device_data (pointer returned from keyboard_driver_add_device) |
proc keyboard_driver_end_packet |
; Nothing to do. |
ret |
endp |
; Timer callback for SetTimerHS. |
proc autorepeat_timer |
virtual at esp |
dd ? ; return address |
.data dd ? |
end virtual |
; Just resend the last pressed key. |
mov eax, [.data] |
movzx ecx, [eax+keyboard_device_data.repeatkey] |
; Copy bit 7 to CF and send scancode with bit 7 cleared. |
btr ecx, 7 |
call keyboard_driver_input_field.send_key |
ret 4 |
endp |
; This function is called from the keyboard layer |
; when it is safe to free keyboard data. |
proc CloseKeyboard |
virtual at esp |
dd ? ; return address |
.device_data dd ? |
end virtual |
mov eax, [.device_data] |
call Kfree |
ret 4 |
endp |
; This function is called from the keyboard layer |
; to update LED state on the keyboard. |
proc SetKeyboardLights stdcall uses ebx esi edi, device_data, led_state |
locals |
size dd ? |
endl |
; 1. Get the pointer to the LED report. |
; If there is no LED report, exit from the function. |
mov ebx, [device_data] |
mov esi, [ebx+keyboard_device_data.led_report] |
test esi, esi |
jz .nothing |
; 2. Get report size in bytes. |
; report.size is size in bits without possible report ID; |
; if an ID is assigned, the size is one byte greater. |
mov eax, [esi+report.size] |
add eax, 7 |
shr eax, 3 |
cmp [esi+report.id], 0 |
jz @f |
inc eax |
@@: |
mov [size], eax |
; 3. Allocate memory for report + 8 bytes for setup packet. |
; Dword-align size for subsequent rep stosd and bts. |
; If failed, exit from the function. |
add eax, 8 + 3 |
and eax, not 3 |
push eax |
call Kmalloc |
pop ecx |
test eax, eax |
jz .nothing |
; 4. Zero-initialize output report. |
push eax |
mov edi, eax |
shr ecx, 2 |
xor eax, eax |
rep stosd |
pop edi |
add edi, 8 |
; 5. Store report ID, if assigned. If not assigned, that would just write zero |
; over zeroes. |
mov edx, [esi+report.id] |
mov [edi], edx |
; 6. Set report bits corresponding to active indicators. |
mov eax, [led_state] |
test al, 1 ; PS/2 Scroll Lock |
jz @f |
mov ecx, [ebx+keyboard_device_data.scrolllock_bit] |
test ecx, ecx |
js @f |
bts [edi], ecx |
@@: |
test al, 2 ; PS/2 Num Lock |
jz @f |
mov ecx, [ebx+keyboard_device_data.numlock_bit] |
test ecx, ecx |
js @f |
bts [edi], ecx |
@@: |
test al, 4 ; PS/2 Caps Lock |
jz @f |
mov ecx, [ebx+keyboard_device_data.capslock_bit] |
test ecx, ecx |
js @f |
bts [edi], ecx |
@@: |
; 7. Fill setup packet. |
shl edx, 16 ; move Report ID to byte 2 |
or edx, 21h + \ ; Class-specific request to Interface |
(9 shl 8) + \ ; SET_REPORT |
(2 shl 24) ; Report Type = Output |
lea eax, [edi-8] |
mov ebx, [ebx+keyboard_device_data.usbdev] |
mov dword [eax], edx |
mov edx, [size] |
shl edx, 16 ; move Size to last word |
or edx, [ebx+usb_device_data.interface_number] |
mov [eax+4], edx |
; 8. Submit output control request. |
stdcall USBControlTransferAsync, [ebx+usb_device_data.configpipe], \ |
eax, edi, [size], after_set_keyboard_lights, ebx, 0 |
; If failed, free the buffer now. |
; If succeeded, the callback will free the buffer. |
test eax, eax |
jnz .nothing |
lea eax, [edi-8] |
call Kfree |
.nothing: |
ret |
endp |
; This procedure is called from the USB subsystem when the request initiated by |
; SetKeyboardLights is completed, either successfully or unsuccessfully. |
proc after_set_keyboard_lights |
virtual at esp |
dd ? ; return address |
.pipe dd ? |
.status dd ? |
.buffer dd ? |
.length dd ? |
.calldata dd ? |
end virtual |
; Ignore status, just free the buffer allocated by SetKeyboardLights. |
mov eax, [.buffer] |
sub eax, 8 |
call Kfree |
ret 20 |
endp |
/kernel/branches/Kolibri-acpi/drivers/usbhid/mouse.inc |
---|
0,0 → 1,155 |
; HID mouse driver, part of USBHID driver. |
; Global constants. |
; They are assembled in a macro to separate code and data; |
; the code is located at the point of "include 'mouse.inc'", |
; the data are collected when workers_globals is instantiated. |
macro workers_globals |
{ |
; include global constants from previous workers |
workers_globals |
align 4 |
; Callbacks for HID layer. |
mouse_driver: |
dd mouse_driver_add_device |
dd mouse_driver_disconnect |
dd mouse_driver_begin_packet |
dd mouse_driver_array_overflow? |
dd mouse_driver_input_field |
dd mouse_driver_end_packet |
} |
; Data that are specific for one mouse device. |
struct mouse_device_data |
buttons dd ? ; buttons that are currently pressed |
dx dd ? ; current x moving |
dy dd ? ; current y moving |
wheel dd ? ; current wheel moving |
hwheel dd ? |
ends |
; This procedure is called when HID layer detects a new mouse. |
; in: ebx -> device_data from USB layer, edi -> collection |
; out: eax = device-specific data or NULL on error |
proc mouse_driver_add_device |
; Just allocate memory; no initialization needed. |
movi eax, sizeof.mouse_device_data |
call Kmalloc |
ret |
endp |
; This procedure is called when HID layer detects disconnect of a previously |
; connected mouse. |
; in: edi -> mouse_device_data (pointer returned from mouse_driver_add_device) |
proc mouse_driver_disconnect |
; Free the allocated memory. |
mov eax, edi |
call Kfree |
ret |
endp |
; This procedure is called when HID layer starts processing a new input packet |
; from a mouse. |
; in: edi -> mouse_device_data (pointer returned from mouse_driver_add_device) |
proc mouse_driver_begin_packet |
; Zero all variables describing the current state. |
mov [edi+mouse_device_data.buttons], 0 |
mov [edi+mouse_device_data.dx], 0 |
mov [edi+mouse_device_data.dy], 0 |
mov [edi+mouse_device_data.wheel], 0 |
mov [edi+mouse_device_data.hwheel], 0 |
ret |
endp |
; This procedure is called when HID layer processes every non-empty array field group. |
; in: edi -> mouse_device_data (pointer returned from mouse_driver_add_device) |
; in: ecx = fields count (always nonzero), edx = pointer to fields values |
; in: esi -> report_field_group |
; out: CF set => array is ok, CF cleared => array should be ignored |
proc mouse_driver_array_overflow? |
; no array fields, no overflows |
stc |
ret |
endp |
; This procedure is called from HID layer for every field. |
; in: edi -> mouse_device_data (pointer returned from mouse_driver_add_device) |
; in: ecx = field usage, edx = value, esi -> report_field_group |
proc mouse_driver_input_field |
; 1. Determine the handler. We process x/y moving, wheel and up to 32 buttons. |
; Pass other fields to the default handler - default_driver_input_field if |
; HID_DUMP_UNCLAIMED is enabled, just ignore otherwise. |
cmp ecx, USAGE_GD_X |
jz .x |
cmp ecx, USAGE_GD_Y |
jz .y |
cmp ecx, USAGE_GD_WHEEL |
jz .wheel |
cmp ecx, 0xC0238 |
jz .hwheel |
sub ecx, USAGE_BUTTON_PAGE + 1 |
jb .unclaimed |
cmp ecx, 32 |
jae .unclaimed |
; 2. This is a button. |
; If a button is pressed, set the corresponding bit in the state. |
; If a button is not pressed, do nothing. |
test edx, edx |
jz @f |
bts [edi+mouse_device_data.buttons], ecx |
@@: |
if ~HID_DUMP_UNCLAIMED |
.unclaimed: |
end if |
ret |
if HID_DUMP_UNCLAIMED |
.unclaimed: |
add ecx, USAGE_BUTTON_PAGE + 1 |
jmp default_driver_input_field |
end if |
.x: |
; 3. This is x moving. For relative fields, store the value in the state. |
; Pass absolute field to the default handler. |
test byte [esi+report_field_group.flags], HID_FIELD_RELATIVE |
jz .unclaimed |
mov [edi+mouse_device_data.dx], edx |
ret |
.y: |
; 4. This is y moving. For relative fields, store the value in the state, |
; changing the sign: HID uses "mathematics" scheme with Y axis increasing from |
; bottom to top, the kernel expects "programming" PS/2-style with Y axis |
; increasing from top to bottom. |
; Pass absolute fields to the default handler. |
test byte [esi+report_field_group.flags], HID_FIELD_RELATIVE |
jz .unclaimed |
neg edx |
mov [edi+mouse_device_data.dy], edx |
ret |
.wheel: |
; 5. This is wheel event. For relative fields, store the value in the state, |
; changing the sign. Pass absolute fields to the default handler. |
test byte [esi+report_field_group.flags], HID_FIELD_RELATIVE |
jz .unclaimed |
neg edx |
mov [edi+mouse_device_data.wheel], edx |
ret |
.hwheel: |
test byte [esi+report_field_group.flags], HID_FIELD_RELATIVE |
jz .unclaimed |
mov [edi+mouse_device_data.hwheel], edx |
ret |
endp |
; This procedure is called when HID layer ends processing a new input packet |
; from a mouse. |
; in: edi -> mouse_device_data (pointer returned from mouse_driver_add_device) |
proc mouse_driver_end_packet |
; Call the kernel, passing collected state. |
stdcall SetMouseData, \ |
[edi+mouse_device_data.buttons], \ |
[edi+mouse_device_data.dx], \ |
[edi+mouse_device_data.dy], \ |
[edi+mouse_device_data.wheel], \ |
[edi+mouse_device_data.hwheel] |
ret |
endp |
/kernel/branches/Kolibri-acpi/drivers/usbhid/report.inc |
---|
0,0 → 1,1442 |
; Parser of HID structures: parse HID report descriptor, |
; parse/generate input/output/feature reports. |
; ============================================================================= |
; ================================= Constants ================================= |
; ============================================================================= |
; Usage codes from HID specification |
; Generic Desktop usage page |
USAGE_GD_POINTER = 10001h |
USAGE_GD_MOUSE = 10002h |
USAGE_GD_JOYSTICK = 10004h |
USAGE_GD_GAMEPAD = 10005h |
USAGE_GD_KEYBOARD = 10006h |
USAGE_GD_KEYPAD = 10007h |
USAGE_GD_X = 10030h |
USAGE_GD_Y = 10031h |
USAGE_GD_Z = 10032h |
USAGE_GD_RX = 10033h |
USAGE_GD_RY = 10034h |
USAGE_GD_RZ = 10035h |
USAGE_GD_SLIDER = 10036h |
USAGE_GD_DIAL = 10037h |
USAGE_GD_WHEEL = 10038h |
; Keyboard/Keypad usage page |
USAGE_KBD_NOEVENT = 70000h |
USAGE_KBD_ROLLOVER = 70001h |
USAGE_KBD_POSTFAIL = 70002h |
USAGE_KBD_FIRST_KEY = 70004h ; this is 'A', actually |
USAGE_KBD_LCTRL = 700E0h |
USAGE_KBD_LSHIFT = 700E1h |
USAGE_KBD_LALT = 700E2h |
USAGE_KBD_LWIN = 700E3h |
USAGE_KBD_RCTRL = 700E4h |
USAGE_KBD_RSHIFT = 700E5h |
USAGE_KBD_RALT = 700E6h |
USAGE_KBD_RWIN = 700E7h |
; LED usage page |
USAGE_LED_NUMLOCK = 80001h |
USAGE_LED_CAPSLOCK = 80002h |
USAGE_LED_SCROLLLOCK = 80003h |
; Button usage page |
; First button is USAGE_BUTTON_PAGE+1, second - USAGE_BUTTON_PAGE+2 etc. |
USAGE_BUTTON_PAGE = 90000h |
; Flags for input/output/feature fields |
HID_FIELD_CONSTANT = 1 ; if not, then Data field |
HID_FIELD_VARIABLE = 2 ; if not, then Array field |
HID_FIELD_RELATIVE = 4 ; if not, then Absolute field |
HID_FIELD_WRAP = 8 |
HID_FIELD_NONLINEAR = 10h |
HID_FIELD_NOPREFERRED= 20h ; no preferred state |
HID_FIELD_HASNULL = 40h ; has null state |
HID_FIELD_VOLATILE = 80h ; for output/feature fields |
HID_FIELD_BUFBYTES = 100h; buffered bytes |
; Report descriptor can easily describe gigabytes of (meaningless) data. |
; Keep report size reasonable to avoid excessive memory allocations and |
; calculation overflows; 1 Kb is more than enough (typical size is 3-10 bytes). |
MAX_REPORT_BYTES = 1024 |
; ============================================================================= |
; ================================ Structures ================================= |
; ============================================================================= |
; Every meaningful report field group has one or more associated usages. |
; Usages can be individual or joined into continuous ranges. |
; This structure describes one range or one individual usage in a large array; |
; individual usage is equivalent to a range of length 1. |
struct usage_range |
offset dd ? |
; Sum of range sizes over all previous array items. |
; Size of range a equals |
; [a + sizeof.usage_range + usage_range.offset] - [a + usage_range.offset]. |
; The total sum over all array items immediately follows the array, |
; this field must be the first so that the formula above works for the last item. |
first_usage dd ? |
; Usage code for first item in the range. |
ends |
; This structure describes one group of report fields with identical properties. |
struct report_field_group |
next dd ? |
; All field groups in one report are organized in a single-linked list. |
; This is the next group in the report or 0 for the last group. |
size dd ? |
; Size in bits of one field. Cannot be zero or greater than 32. |
count dd ? ; field count, cannot be zero |
offset dd ? ; offset from report start, in bits |
; Following fields are decoded from report descriptor, see HID spec for details. |
flags dd ? |
logical_minimum dd ? |
logical_maximum dd ? |
physical_minimum dd ? |
physical_maximum dd ? |
unit_exponent dd ? |
unit dd ? |
; Following fields are used to speedup extract_field_value. |
mask dd ? |
; Bitmask for all data bits except sign bit: |
; (1 shl .size) - 1 for unsigned fields, (1 shl (.size-1)) - 1 for signed fields |
sign_mask dd ? |
; Zero for unsigned fields. Bitmask with sign bit set for signed fields. |
common_sizeof rd 0 |
; Variable and Array field groups differ significantly. |
; Variable field groups are simple. There are .count fields, each field has |
; predefined Usage, the content of a field is its value. Each field is |
; always present in the report. For Variable field groups, we just keep |
; additional .count dwords with usages for individual fields. |
; Array field groups are complicated. There are .count uniform fields. |
; The content of a field determines Usage; Usages which are currently presented |
; in the report have value = 1, other Usages have value = 0. The number of |
; possible Usages is limited only by field .size; 32-bit field could encode any |
; Usage, so it is unreasonable to keep all Usages in the plain array, as with |
; Variable fields. However, many unrelated Usages in one group are meaningless, |
; so usually possible values are grouped in sequential ranges; number of ranges |
; is limited by report descriptor size (max 0xFFFF bytes should contain all |
; information, including usage ranges and field descriptions). |
; Also, for Array variables we pass changes in state to drivers, not the state |
; itself, because sending information about all possible Usages is inpractical; |
; so we should remember the previous state in addition to the current state. |
; Thus, for Array variables keep the following information, in this order: |
; * some members listed below; note that they do NOT exist for Variable groups; |
; * array of usage ranges in form of usage_range structures, including |
; an additional dword after array described in usage_range structure; |
; * allocated memory for current values of the report; |
; * values of the previous report. |
num_values_prev dd ? ; number of values in the previous report |
num_usage_ranges dd ? ; number of usage_range, always nonzero |
usages rd 0 |
ends |
; This structure describes one report. |
; All reports of one type are organized into a single-linked list. |
struct report |
next dd ? ; pointer to next report of the same type, if any |
size dd ? ; total size in bits |
first_field dd ? ; pointer to first report_field_group for this report |
last_field dd ? |
; pointer to last report_field_group for this report, if any; |
; address of .first_field, if .first_field is 0 |
id dd ? |
; Report ID, if assigned. Zero otherwise. |
top_level_collection dd ? ; top-level collection for this report |
ends |
; This structure describes a set of reports of the same type; |
; there are 3 sets (possibly empty), input, output and feature. |
struct report_set |
data dd ? |
; If .numbered is zero, this is zero for the empty set and |
; a pointer to the (only) report structure otherwise. |
; If .numbered is nonzero, this is a pointer to 256-dword array of pointers |
; to reports organized by report ID. |
first_report dd ? |
; Pointer to the first report or 0 for the empty set. |
numbered db ? |
; If zero, report IDs are not used, there can be at most one report in the set. |
; If nonzero, first byte of the report is report ID. |
rb 3 ; padding |
ends |
; This structure describes a range of reports of one type that belong to |
; some collection. |
struct collection_report_set |
first_report dd ? |
first_field dd ? |
last_report dd ? |
last_field dd ? |
ends |
; This structure defines driver callbacks which are used while |
; device is active; i.e. all callbacks except add_device. |
struct hid_driver_active_callbacks |
disconnect dd ? |
; Called when an existing HID device is disconnected. |
; |
; Four following functions are called when a new input packet arrives |
; in the following order: .begin_packet, then .input_field several times |
; for each input field, interleaved with .array_overflow? for array groups, |
; then .end_packet. |
begin_packet dd ? |
; edi -> driver data |
array_overflow? dd ? |
; edi -> driver data |
; out: CF cleared <=> ignore this array |
input_field dd ? |
; edi -> driver data, ecx = usage, edx = value |
end_packet dd ? |
; edi -> driver data |
ends |
; This structure describes one collection. |
struct collection |
next dd ? ; pointer to the next collection in the same level |
; must be the first field |
parent dd ? ; pointer to nesting collection |
first_child dd ? ; pointer to the first nested collection |
last_child dd ? ; pointer to the last nested collection |
; or to .first_child, if .first_child is zero |
type dd ? ; Application, Physical etc |
usage dd ? ; associated Usage code |
; Next fields are filled only for top-level collections. |
callbacks hid_driver_active_callbacks |
driver_data dd ? ; value to be passed as is to driver callbacks |
input collection_report_set |
output collection_report_set |
feature collection_report_set |
ends |
; This structure keeps all data used by the HID layer for one device. |
struct hid_data |
input report_set |
output report_set |
feature report_set |
first_collection dd ? |
ends |
; This structure defines callbacks required from the driver. |
struct hid_driver_callbacks |
add_device dd ? |
; Called when a new HID device is connected. |
active hid_driver_active_callbacks |
ends |
; Two following structures describe temporary data; |
; the corresponding objects cease to exist when HID parser completes |
; state of Global items |
struct global_items |
next dd ? |
usage_page dd ? |
logical_minimum dd ? |
logical_maximum dd ? |
physical_minimum dd ? |
physical_maximum dd ? |
unit_exponent dd ? |
unit dd ? |
report_size dd ? |
report_id dd ? |
report_count dd ? |
ends |
; one range of Usages |
struct usage_list_item |
next dd ? |
first_usage dd ? |
num_usages dd ? |
ends |
; ============================================================================= |
; =================================== Code ==================================== |
; ============================================================================= |
macro workers_globals |
{ |
workers_globals |
; Jump tables for switch'ing in the code. |
align 4 |
; jump table for two lower bits which encode size of item data |
parse_descr_label.fetch_jumps: |
dd parse_descr_label.fetch_none ; x0, x4, x8, xC |
dd parse_descr_label.fetch_byte ; x1, x5, x9, xD |
dd parse_descr_label.fetch_word ; x2, x6, xA, xE |
dd parse_descr_label.fetch_dword ; x3, x7, xB, xF |
; jump table for two next bits which encode item type |
parse_descr_label.type_jumps: |
dd parse_descr_label.parse_main |
dd parse_descr_label.parse_global |
dd parse_descr_label.parse_local |
dd parse_descr_label.parse_reserved |
; jump table for 4 upper bits in the case of Main item |
parse_descr_label.main_jumps: |
dd parse_descr_label.input ; 80...83 |
dd parse_descr_label.output ; 90...93 |
dd parse_descr_label.collection ; A0...A3 |
dd parse_descr_label.feature ; B0...B3 |
dd parse_descr_label.end_collection ; C0...C3 |
parse_descr_label.num_main_items = ($ - parse_descr_label.main_jumps) / 4 |
; jump table for 4 upper bits in the case of Global item |
parse_descr_label.global_jumps: |
dd parse_descr_label.usage_page ; 04...07 |
dd parse_descr_label.logical_minimum ; 14...17 |
dd parse_descr_label.logical_maximum ; 24...27 |
dd parse_descr_label.physical_minimum ; 34...37 |
dd parse_descr_label.physical_maximum ; 44...47 |
dd parse_descr_label.unit_exponent ; 54...57 |
dd parse_descr_label.unit ; 64...67 |
dd parse_descr_label.report_size ; 74...77 |
dd parse_descr_label.report_id ; 84...87 |
dd parse_descr_label.report_count ; 94...97 |
dd parse_descr_label.push ; A4...A7 |
dd parse_descr_label.pop ; B4...B7 |
parse_descr_label.num_global_items = ($ - parse_descr_label.global_jumps) / 4 |
; jump table for 4 upper bits in the case of Local item |
parse_descr_label.local_jumps: |
dd parse_descr_label.usage ; 08...0B |
dd parse_descr_label.usage_minimum ; 18...1B |
dd parse_descr_label.usage_maximum ; 28...2B |
dd parse_descr_label.item_parsed ; 38...3B = designator item; ignore |
dd parse_descr_label.item_parsed ; 48...4B = designator minimum; ignore |
dd parse_descr_label.item_parsed ; 58...5B = designator maximum; ignore |
dd parse_descr_label.item_parsed ; 68...6B not assigned |
dd parse_descr_label.item_parsed ; 78...7B = string index; ignore |
dd parse_descr_label.item_parsed ; 88...8B = string minimum; ignore |
dd parse_descr_label.item_parsed ; 98...9B = string maximum; ignore |
dd parse_descr_label.delimiter ; A8...AB |
parse_descr_label.num_local_items = ($ - parse_descr_label.local_jumps) / 4 |
} |
; Local variables for parse_descr. |
macro parse_descr_locals |
{ |
cur_item_size dd ? ; encoded size of data for current item |
report_ok db ? ; 0 on error, 1 if everything is ok |
field_type db ? ; 0/1/2 for input/output/feature fields |
rb 2 ; alignment |
field_data dd ? ; data for current item when it describes a field group |
last_reports rd 3 ; pointers to last input/output/feature records |
usage_minimum dd ? ; current value of Usage Minimum |
usage_list dd ? ; list head of usage_list_item |
usage_tail dd ? ; list tail of usage_list_item |
num_usage_ranges dd ? ; number of usage ranges, size of usage_list |
delimiter_depth dd ? ; normally 0; 1 inside of Delimiter(); |
; nested Delimiter()s are not allowed |
usage_variant dd ? ; 0 outside of Delimiter()s and for first Usage inside Delimiter(), |
; incremented with each new Usage inside Delimiter() |
cur_collection dd ? ; current collection |
last_collection dd ? ; last top-level collection |
} |
; Parse report descriptor. The caller should provide local variables |
; [buffer] = pointer to report descriptor, [length] = length of report descriptor, |
; [calldata] = pointer to hid_data (possibly wrapped in a large structure). |
macro parse_descr |
{ |
parse_descr_label: |
; 1. Initialize. |
; 1a. Set some variables to initial values. |
xor edi, edi |
mov dword [report_ok], edi |
mov [usage_list], edi |
mov [cur_collection], edi |
mov eax, [calldata] |
add eax, hid_data.input.first_report |
mov [last_reports+0*4], eax |
add eax, hid_data.output.first_report - hid_data.input.first_report |
mov [last_reports+1*4], eax |
add eax, hid_data.feature.first_report - hid_data.output.first_report |
mov [last_reports+2*4], eax |
add eax, hid_data.first_collection - hid_data.feature.first_report |
mov [last_collection], eax |
; 1b. Allocate state of global items. |
movi eax, sizeof.global_items |
call Kmalloc |
test eax, eax |
jz .memory_error |
; 1c. Zero-initialize it and move pointer to edi. |
push eax |
xchg eax, edi |
movi ecx, sizeof.global_items / 4 |
rep stosd |
pop edi |
; 1d. Load pointer to data into esi and make [length] point to end of data. |
mov esi, [buffer] |
add [length], esi |
; 2. Clear all local items. |
; This is needed in the beginning and after processing any Main item. |
.zero_local_items: |
mov eax, [usage_list] |
@@: |
test eax, eax |
jz @f |
push [eax+usage_list_item.next] |
call Kfree |
pop eax |
jmp @b |
@@: |
lea ecx, [usage_list] |
mov [usage_tail], ecx |
mov [ecx], eax |
mov [delimiter_depth], eax |
mov [usage_variant], eax |
mov [usage_minimum], eax |
mov [num_usage_ranges], eax |
; 3. Parse items until end of data found. |
cmp esi, [length] |
jae .parse_end |
.fetch_next_item: |
; --------------------------------- Parse item -------------------------------- |
; 4. Parse one item. |
; 4a. Get item data. eax = first item byte = code+type+size (4+2+2 bits), |
; ebx = item data interpreted as unsigned, |
; ecx = item data interpreted as signed. |
movzx eax, byte [esi] |
mov ecx, eax |
and ecx, 3 |
mov [cur_item_size], ecx |
jmp dword [.fetch_jumps+ecx*4] |
.invalid_report: |
mov esi, invalid_report_msg |
jmp .end_str |
.fetch_none: |
xor ebx, ebx |
xor ecx, ecx |
inc esi |
jmp .fetched |
.fetch_byte: |
add esi, 2 |
cmp esi, [length] |
ja .invalid_report |
movzx ebx, byte [esi-1] |
movsx ecx, bl |
jmp .fetched |
.fetch_word: |
add esi, 3 |
cmp esi, [length] |
ja .invalid_report |
movzx ebx, word [esi-2] |
movsx ecx, bx |
jmp .fetched |
.fetch_dword: |
add esi, 5 |
cmp esi, [length] |
ja .invalid_report |
mov ebx, dword [esi-4] |
mov ecx, ebx |
.fetched: |
; 4b. Select the branch according to item type. |
; For every type, select the concrete handler and go there. |
mov edx, eax |
shr edx, 2 |
and edx, 3 |
shr eax, 4 |
jmp dword [.type_jumps+edx*4] |
; -------------------------------- Main items --------------------------------- |
.parse_main: |
sub eax, 8 |
cmp eax, .num_main_items |
jae .item_parsed |
jmp dword [.main_jumps+eax*4] |
; There are 5 Main items. |
; Input/Output/Feature items create new field groups in the corresponding report; |
; Collection item opens a new collection (possibly nested), |
; End Collection item closes the most nested collection. |
.output: |
mov [field_type], 1 |
jmp .new_field |
.feature: |
mov [field_type], 2 |
jmp .new_field |
.input: |
mov [field_type], 0 |
.new_field: |
; Create a new field group. |
mov [field_data], ebx |
movzx ebx, [field_type] |
if sizeof.report_set = 12 |
lea ebx, [ebx*3] |
shl ebx, 2 |
else |
err Change the code |
end if |
add ebx, [calldata] |
; 5. Sanity checks: field size and fields count must be nonzero, |
; field size cannot be more than 32 bits, |
; if field count is more than MAX_REPORT_SIZE * 8, the report would be more than |
; MAX_REPORT_SIZE bytes, so it is invalid too. |
; More precise check for size occurs later; this check only guarantees that |
; there will be no overflows during subsequent calculations. |
cmp [edi+global_items.report_size], 0 |
jz .invalid_report |
cmp [edi+global_items.report_size], 32 |
ja .invalid_report |
; There are devices with Report Count(0) + Input(Constant Variable), |
; zero-length padding. Thus, do not consider descriptors with Report Count(0) |
; as invalid; instead, just ignore fields with Report Count(0). |
cmp [edi+global_items.report_count], 0 |
jz .zero_local_items |
cmp [edi+global_items.report_count], MAX_REPORT_BYTES * 8 |
ja .invalid_report |
; 6. Get the pointer to the place for the corresponding report in ebx. |
; 6a. If report ID is not assigned, ebx already points to report_set.data, |
; so go to 7. |
cmp [edi+global_items.report_id], 0 |
jz .report_ptr_found |
; 6b. If table for reports was already allocated, |
; go to 6d skipping the next substep. |
cmp [ebx+report_set.numbered], 0 |
jnz .report_set_allocated |
; 6c. This is the first report with ID; |
; allocate and zero-initialize table for reports. |
; Note: it is incorrect but theoretically possible that some fields were |
; already allocated in report without ID; if so, abort processing with error. |
cmp [ebx+report_set.data], 0 |
jnz .invalid_report |
mov eax, 256*4 |
call Kmalloc |
test eax, eax |
jz .memory_error |
mov [ebx+report_set.data], eax |
inc [ebx+report_set.numbered] |
push edi |
mov edi, eax |
mov ecx, 256 |
xor eax, eax |
rep stosd |
pop edi |
; 6d. Report ID is assigned, report table is allocated, |
; get the pointer to the corresponding item in the report table. |
.report_set_allocated: |
mov ebx, [ebx+report_set.data] |
mov ecx, [edi+global_items.report_id] |
lea ebx, [ebx+ecx*4] |
; 7. If the field group is the first one in the report, |
; allocate and initialize report without fields. |
.report_ptr_found: |
; 7a. Check whether the report has been allocated. |
cmp dword [ebx], 0 |
jnz .report_allocated |
; 7b. Allocate. |
movi eax, sizeof.report |
call Kmalloc |
test eax, eax |
jz .memory_error |
; 7c. Initialize. |
xor edx, edx |
lea ecx, [eax+report.first_field] |
mov [ebx], eax |
mov [eax+report.next], edx |
mov [eax+report.size], edx |
mov [ecx], edx |
mov [eax+report.last_field], ecx |
mov [eax+report.top_level_collection], edx |
mov ecx, [edi+global_items.report_id] |
mov [eax+report.id], ecx |
; 7d. Append to the overall list of reports. |
movzx edx, [field_type] |
lea edx, [last_reports+edx*4] |
mov ecx, [edx] |
mov [edx], eax |
mov [ecx], eax |
.report_allocated: |
mov ebx, [ebx] |
; ebx points to an already existing report; add new field. |
; 8. Calculate total size of the group and |
; check that the new group would not overflow the report. |
mov eax, [edi+global_items.report_size] |
mul [edi+global_items.report_count] |
mov ecx, [ebx+report.size] |
add ecx, eax |
cmp ecx, MAX_REPORT_BYTES * 8 |
ja .invalid_report |
; 9. If there are no usages for this group, this is padding; |
; add it's size to total report size and stop processing. |
cmp [num_usage_ranges], 0 |
jz .padding |
; 10. Allocate memory for the group: this includes field group structure |
; and additional fields depending on field type. |
; See comments in report_field_group structure. |
push eax |
mov edx, [edi+global_items.report_count] |
lea eax, [report_field_group.common_sizeof+edx*4] |
test byte [field_data], HID_FIELD_VARIABLE |
jnz @f |
lea eax, [eax+edx*4] |
mov edx, [num_usage_ranges] |
lea eax, [eax+edx*sizeof.usage_range+4] |
@@: |
call Kmalloc |
pop edx |
test eax, eax |
jz .memory_error |
; 11. Update report data. |
; Field offset is the current report size; |
; get the current report size and update report size. |
; Also store the pointer to new field in the previous last field |
; and update the last field. |
mov ecx, [ebx+report.last_field] |
xadd [ebx+report.size], edx |
mov [ebx+report.last_field], eax |
mov [ecx], eax |
; 12. Initialize field data: offset was calculated in the previous step, |
; copy other characteristics from global_items data, |
; calculate .mask and .sign_mask. |
mov [eax+report_field_group.offset], edx |
xor edx, edx |
mov [eax+report_field_group.next], edx |
mov [eax+report_field_group.sign_mask], edx |
inc edx |
mov ecx, [edi+global_items.report_size] |
mov [eax+report_field_group.size], ecx |
shl edx, cl |
cmp [edi+global_items.logical_minimum], 0 |
jge .unsigned |
shr edx, 1 |
mov [eax+report_field_group.sign_mask], edx |
.unsigned: |
dec edx |
mov [eax+report_field_group.mask], edx |
mov ecx, [edi+global_items.report_count] |
mov [eax+report_field_group.count], ecx |
mov ecx, [field_data] |
mov [eax+report_field_group.flags], ecx |
irps field, logical_minimum logical_maximum physical_minimum physical_maximum unit_exponent unit |
\{ |
mov ecx, [edi+global_items.\#field] |
mov [eax+report_field_group.\#field], ecx |
\} |
; 13. Update the current collection; nesting collections will be updated by |
; end-of-collection handler. |
movzx edx, [field_type] |
if sizeof.collection_report_set = 16 |
shl edx, 4 |
else |
err Change the code |
end if |
mov ecx, [cur_collection] |
test ecx, ecx |
jz .no_collection |
lea ecx, [ecx+collection.input+edx] |
mov [ecx+collection_report_set.last_report], ebx |
mov [ecx+collection_report_set.last_field], eax |
cmp [ecx+collection_report_set.first_field], 0 |
jnz .no_collection |
mov [ecx+collection_report_set.first_report], ebx |
mov [ecx+collection_report_set.first_field], eax |
.no_collection: |
; 14. Transform usage ranges. The target format depends on field type. |
test byte [eax+report_field_group.flags], HID_FIELD_VARIABLE |
jz .transform_usages_for_array |
; For Variable field groups, expand all ranges to array with .count Usages. |
; If total number of Usages in all ranges is too large, ignore excessive. |
; If total number of Usages in all ranges is too small, duplicate the last |
; Usage up to .count Usages (e.g. group of several indicators can have one usage |
; "Generic Indicator" assigned to all fields). |
mov ecx, [eax+report_field_group.count] |
mov ebx, [usage_list] |
.next_usage_range_for_variable: |
mov edx, [ebx+usage_list_item.first_usage] |
push [ebx+usage_list_item.num_usages] |
.next_usage_for_variable: |
mov [eax+report_field_group.common_sizeof], edx |
dec ecx |
jz @f |
add eax, 4 |
inc edx |
dec dword [esp] |
jnz .next_usage_for_variable |
dec edx |
inc dword [esp] |
cmp [ebx+usage_list_item.next], 0 |
jz .next_usage_for_variable |
pop edx |
mov ebx, [ebx+usage_list_item.next] |
jmp .next_usage_range_for_variable |
@@: |
pop ebx |
jmp .zero_local_items |
.transform_usages_for_array: |
; For Array field groups, leave ranges unexpanded, but recode in the form |
; more convenient to value lookup, see comments in report_field_group structure. |
mov ecx, [num_usage_ranges] |
mov [eax+report_field_group.num_usage_ranges], ecx |
and [eax+report_field_group.num_values_prev], 0 |
mov ecx, [usage_list] |
xor ebx, ebx |
@@: |
mov edx, [ecx+usage_list_item.first_usage] |
mov [eax+report_field_group.usages+usage_range.offset], ebx |
add ebx, [ecx+usage_list_item.num_usages] |
jc .invalid_report |
mov [eax+report_field_group.usages+usage_range.first_usage], edx |
add eax, sizeof.usage_range |
mov ecx, [ecx+usage_list_item.next] |
test ecx, ecx |
jnz @b |
mov [eax+report_field_group.usages], ebx |
; New field is initialized. |
jmp .zero_local_items |
.padding: |
mov [ebx+report.size], ecx |
jmp .zero_local_items |
; Create a new collection, nested in the current one. |
.collection: |
; Actions are quite straightforward: |
; allocate, zero-initialize, update parent, if there is one, |
; make it current. |
movi eax, sizeof.collection |
call Kmalloc |
test eax, eax |
jz .memory_error |
push eax edi |
movi ecx, sizeof.collection / 4 |
xchg edi, eax |
xor eax, eax |
rep stosd |
pop edi eax |
mov edx, [cur_collection] |
mov [eax+collection.parent], edx |
lea ecx, [last_collection] |
test edx, edx |
jz .no_parent |
lea ecx, [edx+collection.last_child] |
.no_parent: |
mov edx, [ecx] |
mov [ecx], eax |
mov [edx], eax |
lea ecx, [eax+collection.first_child] |
; In theory, there must be at least one usage. |
; In practice, some nested collections don't have any. Use zero in this case. |
mov edx, [usage_list] |
test edx, edx |
jz @f |
mov edx, [edx+usage_list_item.first_usage] |
@@: |
mov [eax+collection.last_child], ecx |
mov [eax+collection.type], ebx |
mov [eax+collection.usage], edx |
mov [cur_collection], eax |
jmp .zero_local_items |
; Close the current collection. |
.end_collection: |
; There must be an opened collection. |
mov eax, [cur_collection] |
test eax, eax |
jz .invalid_report |
; Make parent collection the current one. |
mov edx, [eax+collection.parent] |
mov [cur_collection], edx |
; Add field range of the closing collection to field range for nesting collection, |
; if there is one. |
test edx, edx |
jz .zero_local_items |
push 3 ; for each type: input, output, feature |
.update_ranges: |
mov ecx, [eax+collection.input.last_report] |
test ecx, ecx |
jz .no_fields |
mov [edx+collection.input.last_report], ecx |
mov ecx, [eax+collection.input.last_field] |
mov [edx+collection.input.last_field], ecx |
cmp [edx+collection.input.first_report], 0 |
jnz .no_fields |
mov ecx, [eax+collection.input.first_report] |
mov [edx+collection.input.first_report], ecx |
mov ecx, [eax+collection.input.first_field] |
mov [edx+collection.input.first_field], ecx |
.no_fields: |
add eax, sizeof.collection_report_set |
add edx, sizeof.collection_report_set |
dec dword [esp] |
jnz .update_ranges |
pop eax |
jmp .zero_local_items |
; ------------------------------- Global items -------------------------------- |
.parse_global: |
cmp eax, .num_global_items |
jae .item_parsed |
jmp dword [.global_jumps+eax*4] |
; For most global items, just store the value in the current global_items structure. |
; Note 1: Usage Page will be used for upper word of Usage[| Minimum|Maximum], so |
; shift it in advance. |
; Note 2: the HID specification allows both signed and unsigned values for |
; logical and physical minimum/maximum, but does not give a method to distinguish. |
; Thus, hope that minimum comes first, parse the minimum as signed value always, |
; if it is less than zero, assume signed values, otherwise assume unsigned values. |
; This covers both common cases Minimum(0)/Maximum(FF) and Minimum(-7F)/Maximum(7F). |
; Note 3: zero value for Report ID is forbidden by the HID specification. |
; It is quite convenient, we use report_id == 0 for reports without ID. |
.usage_page: |
shl ebx, 16 |
mov [edi+global_items.usage_page], ebx |
jmp .item_parsed |
.logical_minimum: |
mov [edi+global_items.logical_minimum], ecx |
jmp .item_parsed |
.logical_maximum: |
cmp [edi+global_items.logical_minimum], 0 |
jge @f |
mov ebx, ecx |
@@: |
mov [edi+global_items.logical_maximum], ebx |
jmp .item_parsed |
.physical_minimum: |
mov [edi+global_items.physical_minimum], ecx |
jmp .item_parsed |
.physical_maximum: |
cmp [edi+global_items.physical_maximum], 0 |
jge @f |
mov ebx, ecx |
@@: |
mov [edi+global_items.physical_maximum], ebx |
jmp .item_parsed |
.unit_exponent: |
mov [edi+global_items.unit_exponent], ecx |
jmp .item_parsed |
.unit: |
mov [edi+global_items.unit], ebx |
jmp .item_parsed |
.report_size: |
mov [edi+global_items.report_size], ebx |
jmp .item_parsed |
.report_id: |
test ebx, ebx |
jz .invalid_report |
cmp ebx, 0x100 |
jae .invalid_report |
mov [edi+global_items.report_id], ebx |
jmp .item_parsed |
.report_count: |
mov [edi+global_items.report_count], ebx |
jmp .item_parsed |
; Two special global items: Push/Pop. |
.push: |
; For Push, allocate new global_items structure, |
; initialize from the current one and make it current. |
movi eax, sizeof.global_items |
call Kmalloc |
test eax, eax |
jz .memory_error |
push esi eax |
movi ecx, sizeof.global_items / 4 |
mov esi, edi |
xchg eax, edi |
rep movsd |
pop edi esi |
mov [edi+global_items.next], eax |
jmp .item_parsed |
.pop: |
; For Pop, restore the last global_items structure and free the current one. |
mov eax, [edi+global_items.next] |
test eax, eax |
jz .invalid_report |
push eax |
xchg eax, edi |
call Kfree |
pop edi |
jmp .item_parsed |
; -------------------------------- Local items -------------------------------- |
.parse_local: |
cmp eax, .num_local_items |
jae .item_parsed |
jmp dword [.local_jumps+eax*4] |
.usage: |
; Usage tag. |
; If length is 0, 1, 2 bytes, append the global item Usage Page. |
cmp [cur_item_size], 2 |
ja @f |
or ebx, [edi+global_items.usage_page] |
@@: |
; If inside Delimiter(), ignore everything except the first tag. |
cmp [delimiter_depth], 0 |
jz .usage.write |
inc [usage_variant] |
cmp [usage_variant], 1 |
jnz .item_parsed |
.usage.write: |
; Add new range with start = item data and length = 1. |
mov [usage_minimum], ebx |
push 1 |
.new_usage: |
movi eax, sizeof.usage_list_item |
call Kmalloc |
pop edx |
test eax, eax |
jz .memory_error |
inc [num_usage_ranges] |
mov ecx, [usage_minimum] |
and [eax+usage_list_item.next], 0 |
mov [eax+usage_list_item.first_usage], ecx |
mov [eax+usage_list_item.num_usages], edx |
mov ecx, [usage_tail] |
mov [usage_tail], eax |
mov [ecx], eax |
jmp .item_parsed |
.usage_minimum: |
; Usage Minimum tag. Just store in the local var. |
; If length is 0, 1, 2 bytes, append the global item Usage Page. |
cmp [cur_item_size], 2 |
ja @f |
or ebx, [edi+global_items.usage_page] |
@@: |
mov [usage_minimum], ebx |
jmp .item_parsed |
.usage_maximum: |
; Usage Maximum tag. |
; If length is 0, 1, 2 bytes, append the global item Usage Page. |
cmp [cur_item_size], 2 |
ja @f |
or ebx, [edi+global_items.usage_page] |
@@: |
; Meaningless inside Delimiter(). |
cmp [delimiter_depth], 0 |
jnz .invalid_report |
; Add new range with start = saved Usage Minimum and |
; length = Usage Maximum - Usage Minimum + 1. |
sub ebx, [usage_minimum] |
inc ebx |
push ebx |
jmp .new_usage |
.delimiter: |
; Delimiter tag. |
test ebx, ebx |
jz .delimiter.close |
; Delimiter(Opened). |
; Store that we are inside Delimiter(), |
; say a warning that only preferred Usage will be used. |
cmp [delimiter_depth], 0 |
jnz .invalid_report |
inc [delimiter_depth] |
push esi |
mov esi, delimiter_note |
call SysMsgBoardStr |
pop esi |
jmp .item_parsed |
.delimiter.close: |
; Delimiter(Closed). |
; Store that we are not inside Delimiter() anymore. |
dec [delimiter_depth] |
js .invalid_report |
and [usage_variant], 0 |
jmp .item_parsed |
.parse_reserved: |
; Ignore reserved items, except that tag 0xFE means long item |
; with first data byte = length of additional data, |
; second data byte = long item tag. No long items are defined yet, |
; so just skip them. |
cmp eax, 0xF |
jnz .item_parsed |
cmp [cur_item_size], 2 |
jnz .item_parsed |
movzx ecx, bl |
add esi, ecx |
cmp esi, [length] |
ja .invalid_report |
.item_parsed: |
cmp esi, [length] |
jb .fetch_next_item |
.parse_end: |
;-------------------------------- End of parsing ------------------------------ |
; If there are opened collections, it is invalid report. |
cmp [cur_collection], 0 |
jnz .invalid_report |
; There must be at least one input field. |
mov eax, [calldata] |
add eax, hid_data.input.first_report |
cmp [last_reports+0*4], eax |
jz .invalid_report |
; Everything is ok. |
inc [report_ok] |
jmp .end |
.memory_error: |
mov esi, nomemory_msg |
.end_str: |
call SysMsgBoardStr |
.end: |
; Free all global_items structures. |
test edi, edi |
jz @f |
push [edi+global_items.next] |
xchg eax, edi |
call Kfree |
pop edi |
jmp .end |
@@: |
; Free the last Usage list, if any. |
mov eax, [usage_list] |
@@: |
test eax, eax |
jz @f |
push [eax+usage_list_item.next] |
call Kfree |
pop eax |
jmp @b |
@@: |
} |
; Assign drivers to top-level HID collections. |
; The caller should provide ebx = pointer to hid_data and a local variable |
; [has_driver], it will be initialized with 0 if no driver is present. |
macro postprocess_descr |
{ |
postprocess_report_label: |
; Assign drivers to top-level collections. |
; Use mouse driver for Usage(GenericDesktop:Mouse), |
; use keyboard driver for Usage(GenericDesktop:Keyboard) |
; and Usage(GenericDesktop:Keypad) |
; 1. Prepare for the loop: get the pointer to the first collection, |
; store that no drivers were assigned yet. |
mov edi, [ebx+hid_data.first_collection] |
if ~HID_DUMP_UNCLAIMED |
mov [has_driver], 0 |
end if |
.next_collection: |
; 2. Test whether there is a collection to test; if no, break from the loop. |
test edi, edi |
jz .postprocess_done |
; 3. Get pointer to driver callbacks depending on [collection.usage]. |
; If [collection.usage] is unknown, use default driver if HID_DUMP_UNCLAIMED |
; and do not assign a driver otherwise. |
mov esi, mouse_driver |
cmp [edi+collection.usage], USAGE_GD_MOUSE |
jz .has_driver |
mov esi, keyboard_driver |
cmp [edi+collection.usage], USAGE_GD_KEYBOARD |
jz .has_driver |
cmp [edi+collection.usage], USAGE_GD_KEYPAD |
jz .has_driver |
if HID_DUMP_UNCLAIMED |
mov esi, default_driver |
else |
xor esi, esi |
end if |
; 4. If no driver is assigned (possible only if not HID_DUMP_UNCLAIMED), |
; go to 7 with driver data = 0; |
; other code uses this as a sign that driver callbacks should not be called. |
.has_driver: |
xor eax, eax |
if ~HID_DUMP_UNCLAIMED |
test esi, esi |
jz .set_driver |
end if |
; 5. Notify the driver about new device. |
call [esi+hid_driver_callbacks.add_device] |
; 6. If the driver has returned non-zero driver data, |
; store that is an assigned driver. |
; Otherwise, if HID_DUMP_UNCLAIMED, try to assign the default driver. |
if HID_DUMP_UNCLAIMED |
test eax, eax |
jnz .set_driver |
mov esi, default_driver |
call [esi+hid_driver_callbacks.add_device] |
else |
test eax, eax |
jz @f |
mov [has_driver], 1 |
jmp .set_driver |
@@: |
xor esi, esi |
end if |
.set_driver: |
; 7. Store driver data. If a driver is assigned, copy driver callbacks. |
mov [edi+collection.driver_data], eax |
test esi, esi |
jz @f |
push edi |
lodsd ; skip hid_driver_callbacks.add_device |
add edi, collection.callbacks |
repeat sizeof.hid_driver_active_callbacks / 4 |
movsd |
end repeat |
pop edi |
@@: |
; 8. Store pointer to the collection in all input reports belonging to it. |
; Note that the HID spec requires that reports should not cross top-level collections. |
mov eax, [edi+collection.input.first_report] |
test eax, eax |
jz .reports_processed |
.next_report: |
mov [eax+report.top_level_collection], edi |
cmp eax, [edi+collection.input.last_report] |
mov eax, [eax+report.next] |
jnz .next_report |
.reports_processed: |
mov edi, [edi+collection.next] |
jmp .next_collection |
.postprocess_done: |
} |
; Cleanup all resources allocated during parse_descr and postprocess_descr. |
; Called when the corresponding device is disconnected |
; with ebx = pointer to hid_data. |
macro hid_cleanup |
{ |
; 1. Notify all assigned drivers about disconnect. |
; Loop over all top-level collections and call callbacks.disconnect, |
; if a driver is assigned. |
mov esi, [ebx+hid_data.first_collection] |
.notify_drivers: |
test esi, esi |
jz .notify_drivers_done |
mov edi, [esi+collection.driver_data] |
test edi, edi |
jz @f |
call [esi+collection.callbacks.disconnect] |
@@: |
mov esi, [esi+collection.next] |
jmp .notify_drivers |
.notify_drivers_done: |
; 2. Free all collections. |
mov esi, [ebx+hid_data.first_collection] |
.free_collections: |
test esi, esi |
jz .collections_done |
; If a collection has childen, make it forget about them, |
; kill all children; after last child is killed, return to |
; the collection as a parent; this time, it will appear |
; as childless, so it will be killed after children. |
mov eax, [esi+collection.first_child] |
test eax, eax |
jz .no_children |
and [esi+collection.first_child], 0 |
xchg esi, eax |
jmp .free_collections |
.no_children: |
; If a collection has no children (maybe there were no children at all, |
; maybe all children were already killed), kill it and proceed either to |
; next sibling (if any) or to the parent. |
mov eax, [esi+collection.next] |
test eax, eax |
jnz @f |
mov eax, [esi+collection.parent] |
@@: |
xchg eax, esi |
call Kfree |
jmp .free_collections |
.collections_done: |
; 3. Free all three report sets. |
push 3 |
lea esi, [ebx+hid_data.input] |
; For every report set, loop over all reports, |
; for every report free all field groups, then free report itself. |
; When all reports in one set have been freed, free also report list table, |
; if there is one (reports are numbered). |
.report_set_loop: |
mov edi, [esi+report_set.first_report] |
.report_loop: |
test edi, edi |
jz .report_done |
mov eax, [edi+report.first_field] |
.field_loop: |
test eax, eax |
jz .field_done |
push [eax+report_field_group.next] |
call Kfree |
pop eax |
jmp .field_loop |
.field_done: |
mov eax, [edi+report.next] |
xchg eax, edi |
call Kfree |
jmp .report_loop |
.report_done: |
cmp [esi+report_set.numbered], 0 |
jz @f |
mov eax, [esi+report_set.data] |
call Kfree |
@@: |
add esi, sizeof.report_set |
dec dword [esp] |
jnz .report_set_loop |
pop eax |
} |
; Helper for parse_input. Extracts value of one field. |
; in: esi -> report_field_group |
; in: eax = offset in bits from report start |
; in: report -> report data |
; out: edx = value |
; Note: it can read one dword past report data. |
macro extract_field_value report |
{ |
mov ecx, eax |
shr eax, 5 |
shl eax, 2 |
add eax, report |
and ecx, 31 |
mov edx, [eax] |
mov eax, [eax+4] |
shrd edx, eax, cl |
mov ecx, [esi+report_field_group.sign_mask] |
and ecx, edx |
and edx, [esi+report_field_group.mask] |
sub edx, ecx |
} |
; Local variables for parse_input. |
macro parse_input_locals |
{ |
count_inside_group dd ? |
; Number of fields left in the current field. |
field_offset dd ? |
; Offset of the current field from report start, in bits. |
field_range_size dd ? |
; Size of range with valid values, Logical Maximum - Logical Minimum + 1. |
cur_usage dd ? |
; Pointer to current usage for Variable field groups. |
num_values dd ? |
; Number of values in the current instantiation of Array field group. |
values_base dd ? |
; Pointer to memory allocated for array with current values. |
values_prev dd ? |
; Pointer to memory allocated for array with previous values. |
values_cur_ptr dd ? |
; Pointer to the next value in [values_base] array. |
values_end dd ? |
; End of data in array with current values. |
values_prev_ptr dd ? |
; Pointer to the next value in [values_prev_ptr] array. |
values_prev_end dd ? |
; End of data in array with previous values. |
} |
; Parse input report. The caller should provide esi = pointer to report, |
; local variables parse_input_locals and [buffer] = report data. |
macro parse_input |
{ |
; 1. Ignore the report if there is no driver for it. |
mov ebx, [esi+report.top_level_collection] |
mov edi, [ebx+collection.driver_data] |
test edi, edi |
jz .done |
; 2. Notify the driver that a new packet arrived. |
call [ebx+collection.callbacks.begin_packet] |
; Loop over all field groups. |
; Report without fields is meaningless, but theoretically possible: |
; parse_descr does not create reports of zero size, but |
; a report can consist of "padding" fields without usages and have |
; no real fields. |
mov esi, [esi+report.first_field] |
test esi, esi |
jz .packet_processed |
.field_loop: |
; 3. Prepare for group handling: initialize field offset, fields count |
; and size of range for valid values. |
mov eax, [esi+report_field_group.offset] |
mov [field_offset], eax |
mov ecx, [esi+report_field_group.count] |
mov [count_inside_group], ecx |
mov eax, [esi+report_field_group.logical_maximum] |
inc eax |
sub eax, [esi+report_field_group.logical_minimum] |
mov [field_range_size], eax |
; 4. Select handler. Variable and Array groups are handled entirely differently; |
; for Variable groups, advance to 5, for Array groups, go to 6. |
test byte [esi+report_field_group.flags], HID_FIELD_VARIABLE |
jz .array_field |
; 5. Variable groups. They are simple. Loop over all .count fields, |
; for every field extract the value and get the next usage, |
; if the value is within valid range, call the driver. |
lea eax, [esi+report_field_group.common_sizeof] |
mov [cur_usage], eax |
.variable_data_loop: |
mov eax, [field_offset] |
extract_field_value [buffer] ; -> edx |
mov ecx, [cur_usage] |
mov ecx, [ecx] |
call [ebx+collection.callbacks.input_field] |
add [cur_usage], 4 |
mov eax, [esi+report_field_group.size] |
add [field_offset], eax |
dec [count_inside_group] |
jnz .variable_data_loop |
; Variable group is processed; go to 12. |
jmp .field_done |
.array_field: |
; Array groups. They are complicated. |
; 6. Array group: extract all values in one array. |
; memory was allocated during group creation, use it |
; 6a. Prepare: get data pointer, initialize num_values with zero. |
mov eax, [esi+report_field_group.num_usage_ranges] |
lea edx, [esi+report_field_group.usages+eax*sizeof.usage_range+4] |
mov eax, [esi+report_field_group.count] |
mov [values_cur_ptr], edx |
mov [values_base], edx |
lea edx, [edx+ecx*4] |
mov [values_prev], edx |
mov [values_prev_ptr], edx |
mov [num_values], 0 |
; 6b. Start loop for every field. Note that there must be at least one field, |
; parse_descr does not allow .count == 0. |
.array_getval_loop: |
; 6c. Extract the value of the current field. |
mov eax, [field_offset] |
extract_field_value [buffer] ; -> edx |
; 6d. Transform the value to the usage with binary search in array of |
; usage_ranges. started at [esi+report_field_group.usages] |
; having [esi+report_field_group.num_usage_ranges] items. |
; Ignore items outside of valid range. |
sub edx, [esi+report_field_group.logical_minimum] |
cmp edx, [field_range_size] |
jae .array_skip_item |
; If there are too few usages, use last of them. |
mov ecx, [esi+report_field_group.num_usage_ranges] ; upper bound |
xor eax, eax ; lower bound |
cmp edx, [esi+report_field_group.usages+ecx*sizeof.usage_range+usage_range.offset] |
jae .array_last_usage |
; loop invariant: usages[eax].offset <= edx < usages[ecx].offset |
.array_find_usage: |
lea edi, [eax+ecx] |
shr edi, 1 |
cmp edi, eax |
jz .array_found_usage_range |
cmp edx, [esi+report_field_group.usages+edi*sizeof.usage_range+usage_range.offset] |
jae .update_low |
mov ecx, edi |
jmp .array_find_usage |
.update_low: |
mov eax, edi |
jmp .array_find_usage |
.array_last_usage: |
lea eax, [ecx-1] |
mov edx, [esi+report_field_group.usages+ecx*sizeof.usage_range+usage_range.offset] |
dec edx |
.array_found_usage_range: |
sub edx, [esi+report_field_group.usages+eax*sizeof.usage_range+usage_range.offset] |
add edx, [esi+report_field_group.usages+eax*sizeof.usage_range+usage_range.first_usage] |
; 6e. Store the usage, advance data pointer, continue loop started at 6b. |
mov eax, [values_cur_ptr] |
mov [eax], edx |
add [values_cur_ptr], 4 |
inc [num_values] |
.array_skip_item: |
mov eax, [esi+report_field_group.size] |
add [field_offset], eax |
dec [count_inside_group] |
jnz .array_getval_loop |
; 7. Array group: ask driver about array overflow. |
; If driver says that the array is invalid, stop processing this group |
; (in particular, do not update previous values). |
mov ecx, [num_values] |
test ecx, ecx |
jz .duplicates_removed |
mov edx, [values_base] |
mov edi, [ebx+collection.driver_data] |
call [ebx+collection.callbacks.array_overflow?] |
jnc .field_done |
; 8. Array group: sort the array with current values. |
push esi |
mov ecx, [num_values] |
mov edx, [values_base] |
call sort |
pop esi |
; 9. Array group: remove duplicates. |
cmp [num_values], 1 |
jbe .duplicates_removed |
mov eax, [values_base] |
mov edx, [eax] |
add eax, 4 |
mov ecx, eax |
.duplicates_loop: |
cmp edx, [eax] |
jz @f |
mov edx, [eax] |
mov [ecx], edx |
add ecx, 4 |
@@: |
add eax, 4 |
cmp eax, [values_cur_ptr] |
jb .duplicates_loop |
mov [values_cur_ptr], ecx |
sub ecx, [values_base] |
shr ecx, 2 |
mov [num_values], ecx |
.duplicates_removed: |
; 10. Array group: compare current and previous values, |
; call driver for differences. |
mov edi, [ebx+collection.driver_data] |
mov eax, [values_cur_ptr] |
mov [values_end], eax |
mov eax, [values_base] |
mov [values_cur_ptr], eax |
mov eax, [esi+report_field_group.num_values_prev] |
shl eax, 2 |
add eax, [values_prev] |
mov [values_prev_end], eax |
.find_common: |
mov eax, [values_cur_ptr] |
cmp eax, [values_end] |
jae .cur_done |
mov ecx, [eax] |
mov eax, [values_prev_ptr] |
cmp eax, [values_prev_end] |
jae .prev_done |
mov edx, [eax] |
cmp ecx, edx |
jb .advance_cur |
ja .advance_prev |
; common item in both arrays; ignore |
add [values_cur_ptr], 4 |
add [values_prev_ptr], 4 |
jmp .find_common |
.advance_cur: |
; item is present in current array but not in previous; |
; call the driver with value = 1 |
add [values_cur_ptr], 4 |
mov edx, 1 |
call [ebx+collection.callbacks.input_field] |
jmp .find_common |
.advance_prev: |
; item is present in previous array but not in current; |
; call the driver with value = 0 |
add [values_prev_ptr], 4 |
mov ecx, edx |
xor edx, edx |
call [ebx+collection.callbacks.input_field] |
jmp .find_common |
.prev_done: |
; for all items which are left in current array |
; call the driver with value = 1 |
mov eax, [values_cur_ptr] |
@@: |
add [values_cur_ptr], 4 |
mov ecx, [eax] |
mov edx, 1 |
call [ebx+collection.callbacks.input_field] |
mov eax, [values_cur_ptr] |
cmp eax, [values_end] |
jb @b |
jmp .copy_array |
.cur_done: |
; for all items which are left in previous array |
; call the driver with value = 0 |
mov eax, [values_prev_ptr] |
add [values_prev_ptr], 4 |
cmp eax, [values_prev_end] |
jae @f |
mov ecx, [eax] |
xor edx, edx |
call [ebx+collection.callbacks.input_field] |
jmp .cur_done |
@@: |
.copy_array: |
; 11. Array group: copy current values to previous values. |
push esi edi |
mov ecx, [num_values] |
mov [esi+report_field_group.num_values_prev], ecx |
mov esi, [values_base] |
mov edi, [values_prev] |
rep movsd |
pop edi esi |
; 12. Field group is processed. Repeat with the next group, if any. |
.field_done: |
mov esi, [esi+report_field_group.next] |
test esi, esi |
jnz .field_loop |
.packet_processed: |
; 13. Packet is processed, notify the driver. |
call [ebx+collection.callbacks.end_packet] |
} |
/kernel/branches/Kolibri-acpi/drivers/usbhid/sort.inc |
---|
0,0 → 1,60 |
; Sort array of unsigned dwords in non-decreasing order. |
; ecx = array size, edx = array pointer. |
; Destroys eax, ecx, esi, edi. |
sort: |
test ecx, ecx |
jz .done |
mov eax, ecx |
@@: |
push eax |
call .restore |
pop eax |
dec eax |
jnz @b |
@@: |
cmp ecx, 1 |
jz .done |
mov esi, 1 |
mov edi, ecx |
call .exchange |
dec ecx |
mov eax, 1 |
call .restore |
jmp @b |
.done: |
ret |
.exchange: |
push eax ecx |
mov eax, [edx+esi*4-4] |
mov ecx, [edx+edi*4-4] |
mov [edx+esi*4-4], ecx |
mov [edx+edi*4-4], eax |
pop ecx eax |
ret |
.restore: |
lea esi, [eax+eax] |
cmp esi, ecx |
ja .doner |
mov edi, [edx+eax*4-4] |
cmp [edx+esi*4-4], edi |
ja .need_xchg |
cmp esi, ecx |
jae .doner |
mov edi, [edx+eax*4-4] |
cmp [edx+esi*4], edi |
jbe .doner |
.need_xchg: |
cmp esi, ecx |
jz .do_xchg |
mov edi, [edx+esi*4-4] |
cmp [edx+esi*4], edi |
sbb esi, -1 |
.do_xchg: |
mov edi, eax |
call .exchange |
mov eax, esi |
jmp .restore |
.doner: |
ret |
/kernel/branches/Kolibri-acpi/drivers/usbhid/unclaimed.inc |
---|
0,0 → 1,60 |
; HID default driver, part of USBHID driver. |
; Present only if compile-time setting HID_DUMP_UNCLAIMED is on. |
; Active for those devices when we do not have a specialized driver. |
; Just dumps everything to the debug board. |
if HID_DUMP_UNCLAIMED |
; Global constants. |
; They are assembled in a macro to separate code and data; |
; the code is located at the point of "include 'unclaimed.inc'", |
; the data are collected when workers_globals is instantiated. |
macro workers_globals |
{ |
; include global constants from previous workers |
workers_globals |
align 4 |
; Callbacks for HID layer. |
default_driver: |
dd default_driver_add_device |
dd default_driver_disconnect |
dd default_driver_begin_packet |
dd default_driver_array_overflow? |
dd default_driver_input_field |
dd default_driver_end_packet |
} |
; This procedure is called when HID layer detects a new driverless device. |
; in: ebx -> usb_device_data, edi -> collection |
; out: eax = device-specific data or NULL on error |
default_driver_add_device: |
; just return something nonzero, no matter what |
xor eax, eax |
inc eax |
ret |
; This procedure is called when HID layer processes every non-empty array field group. |
; in: edi -> keyboard_device_data (pointer returned from keyboard_driver_add_device) |
; in: ecx = fields count (always nonzero), edx = pointer to fields values |
; in: esi -> report_field_group |
; out: CF set => group is ok, CF cleared => group should be ignored |
default_driver_array_overflow?: |
; parse everything |
stc |
ret |
; This procedure is called from HID layer for every field. |
; in: ecx = field usage, edx = value, esi -> report_field_group |
default_driver_input_field: |
; Do not dump zero values in Variable fields, |
; they are present even if the corresponding control is inactive. |
test edx, edx |
jnz @f |
test byte [esi+report_field_group.flags], HID_FIELD_VARIABLE |
jnz .nodump |
@@: |
DEBUGF 1,'K : unclaimed HID input: usage=%x, value=%x\n',ecx,edx |
.nodump: |
; pass through |
; Three nothing-to-do procedures. |
default_driver_disconnect: |
default_driver_begin_packet: |
default_driver_end_packet: |
ret |
end if |
/kernel/branches/Kolibri-acpi/drivers/usbhid/usbhid.asm |
---|
0,0 → 1,553 |
; standard driver stuff |
format MS COFF |
DEBUG = 1 |
; this is for DEBUGF macro from 'fdo.inc' |
__DEBUG__ = 1 |
__DEBUG_LEVEL__ = 1 |
include '../proc32.inc' |
include '../imports.inc' |
include '../fdo.inc' |
include '../../struct.inc' |
public START |
public version |
; Compile-time settings. |
; If set, the code will dump all descriptors as they are read to the debug board. |
USB_DUMP_DESCRIPTORS = 1 |
; If set, the code will dump any unclaimed input to the debug board. |
HID_DUMP_UNCLAIMED = 1 |
; USB constants |
DEVICE_DESCR_TYPE = 1 |
CONFIG_DESCR_TYPE = 2 |
STRING_DESCR_TYPE = 3 |
INTERFACE_DESCR_TYPE = 4 |
ENDPOINT_DESCR_TYPE = 5 |
DEVICE_QUALIFIER_DESCR_TYPE = 6 |
CONTROL_PIPE = 0 |
ISOCHRONOUS_PIPE = 1 |
BULK_PIPE = 2 |
INTERRUPT_PIPE = 3 |
; USB HID constants |
HID_DESCR_TYPE = 21h |
REPORT_DESCR_TYPE = 22h |
PHYSICAL_DESCR_TYPE = 23h |
; USB structures |
struct config_descr |
bLength db ? |
bDescriptorType db ? |
wTotalLength dw ? |
bNumInterfaces db ? |
bConfigurationValue db ? |
iConfiguration db ? |
bmAttributes db ? |
bMaxPower db ? |
ends |
struct interface_descr |
bLength db ? |
bDescriptorType db ? |
bInterfaceNumber db ? |
bAlternateSetting db ? |
bNumEndpoints db ? |
bInterfaceClass db ? |
bInterfaceSubClass db ? |
bInterfaceProtocol db ? |
iInterface db ? |
ends |
struct endpoint_descr |
bLength db ? |
bDescriptorType db ? |
bEndpointAddress db ? |
bmAttributes db ? |
wMaxPacketSize dw ? |
bInterval db ? |
ends |
; USB HID structures |
struct hid_descr |
bLength db ? |
bDescriptorType db ? |
bcdHID dw ? |
bCountryCode db ? |
bNumDescriptors db ? |
base_sizeof rb 0 |
; now two fields are repeated .bNumDescriptors times: |
subDescriptorType db ? |
subDescriptorLength dw ? |
ends |
; Include macro for parsing report descriptors/data. |
macro workers_globals |
{} |
include 'report.inc' |
; Driver data for all devices |
struct usb_device_data |
hid hid_data ; data of HID layer |
epdescr dd ? ; endpoint descriptor |
hiddescr dd ? ; HID descriptor |
interface_number dd ? ; copy of interface_descr.bInterfaceNumber |
configpipe dd ? ; config pipe handle |
intpipe dd ? ; interrupt pipe handle |
input_transfer_size dd ? ; input transfer size |
input_buffer dd ? ; buffer for input transfers |
control rb 8 ; control packet to device |
ends |
section '.flat' code readable align 16 |
; The start procedure. |
proc START |
virtual at esp |
dd ? ; return address |
.reason dd ? |
end virtual |
; 1. Test whether the procedure is called with the argument DRV_ENTRY. |
; If not, return 0. |
xor eax, eax ; initialize return value |
cmp [.reason], 1 ; compare the argument |
jnz .nothing |
; 2. Register self as a USB driver. |
; The name is my_driver = 'usbhid'; IOCTL interface is not supported; |
; usb_functions is an offset of a structure with callback functions. |
stdcall RegUSBDriver, my_driver, eax, usb_functions |
; 3. Return the returned value of RegUSBDriver. |
.nothing: |
ret 4 |
endp |
; This procedure is called when new HID device is detected. |
; It initializes the device. |
proc AddDevice |
push ebx esi edi ; save used registers to be stdcall |
virtual at esp |
rd 3 ; saved registers |
dd ? ; return address |
.config_pipe dd ? |
.config_descr dd ? |
.interface dd ? |
end virtual |
DEBUGF 1,'K : USB HID device detected\n' |
; 1. Allocate memory for device data. |
movi eax, sizeof.usb_device_data |
call Kmalloc |
test eax, eax |
jnz @f |
mov esi, nomemory_msg |
call SysMsgBoardStr |
jmp .return0 |
@@: |
; zero-initialize it |
mov edi, eax |
xchg eax, ebx |
xor eax, eax |
movi ecx, sizeof.usb_device_data / 4 |
rep stosd |
mov edx, [.interface] |
; HID devices use one IN interrupt endpoint for polling the device |
; and an optional OUT interrupt endpoint. We do not use the later, |
; but must locate the first. Look for the IN interrupt endpoint. |
; Also, look for the HID descriptor; according to HID spec, it must be |
; located before endpoint descriptors. |
; 2. Get the upper bound of all descriptors' data. |
mov eax, [.config_descr] |
movzx ecx, [eax+config_descr.wTotalLength] |
add eax, ecx |
; 3. Loop over all descriptors until |
; either end-of-data reached - this is fail |
; or interface descriptor found - this is fail, all further data |
; correspond to that interface |
; or endpoint descriptor for IN endpoint is found |
; (HID descriptor must be located before the endpoint descriptor). |
; 3a. Loop start: edx points to the interface descriptor. |
.lookep: |
; 3b. Get next descriptor. |
movzx ecx, byte [edx] ; the first byte of all descriptors is length |
test ecx, ecx |
jz .cfgerror |
add edx, ecx |
; 3c. Check that at least two bytes are readable. The opposite is an error. |
inc edx |
cmp edx, eax |
jae .cfgerror |
dec edx |
; 3d. Check that this descriptor is not interface descriptor. The opposite is |
; an error. |
cmp [edx+endpoint_descr.bDescriptorType], INTERFACE_DESCR_TYPE |
jz .cfgerror |
; 3e. For HID descriptor, proceed to 4. |
; For endpoint descriptor, go to 5. |
; For other descriptors, continue the loop. |
; Note: bDescriptorType is in the same place in all descriptors. |
cmp [edx+endpoint_descr.bDescriptorType], ENDPOINT_DESCR_TYPE |
jz .foundep |
cmp [edx+endpoint_descr.bDescriptorType], HID_DESCR_TYPE |
jnz .lookep |
; 4a. Check that the descriptor contains all required data and all data are |
; readable. The opposite is an error. |
movzx ecx, [edx+hid_descr.bLength] |
cmp ecx, hid_descr.base_sizeof + 3 |
jb .cfgerror |
add ecx, edx |
cmp ecx, eax |
ja .cfgerror |
; 4b. Store the pointer in usb_device_data structure for further references. |
mov [ebx+usb_device_data.hiddescr], edx |
; 4c. Continue the loop. |
jmp .lookep |
.foundep: |
; 5a. Check that the descriptor contains all required data and all data are |
; readable. The opposite is an error. |
cmp byte [edx+endpoint_descr.bLength], sizeof.endpoint_descr |
jb .cfgerror |
lea ecx, [edx+sizeof.endpoint_descr] |
cmp ecx, eax |
jbe @f |
; 6. An error occured during processing endpoint descriptor. |
.cfgerror: |
; 6a. Print a message. |
mov esi, invalid_config_descr_msg |
call SysMsgBoardStr |
; 6b. Free memory allocated for device data. |
.free: |
xchg eax, ebx |
call Kfree |
.return0: |
; 6c. Return an error. |
xor eax, eax |
.nothing: |
pop edi esi ebx ; restore used registers to be stdcall |
ret 12 |
@@: |
; 5b. If this is not IN interrupt endpoint, ignore it and continue the loop. |
test [edx+endpoint_descr.bEndpointAddress], 80h |
jz .lookep |
mov cl, [edx+endpoint_descr.bmAttributes] |
and cl, 3 |
cmp cl, INTERRUPT_PIPE |
jnz .lookep |
; 5c. Store the pointer in usb_device_data structure for futher references. |
mov [ebx+usb_device_data.epdescr], edx |
; 5d. Check that HID descriptor was found. If not, go to 6. |
cmp [ebx+usb_device_data.hiddescr], 0 |
jz .cfgerror |
.descriptors_found: |
; 6. Configuration descriptor seems to be ok. |
; Send SET_IDLE command disabling auto-repeat feature (it is quite useless) |
; and continue configuring in SET_IDLE callback. |
lea edx, [ebx+usb_device_data.control] |
mov eax, [.interface] |
mov dword [edx], 21h + \ ; Class-specific request to Interface |
(0Ah shl 8) + \ ; SET_IDLE |
(0 shl 16) + \ ; apply to all input reports |
(0 shl 24) ; disable auto-repeat |
movzx eax, [eax+interface_descr.bInterfaceNumber] |
mov [ebx+usb_device_data.interface_number], eax |
mov [edx+4], eax ; set interface number, zero length |
mov eax, [.config_pipe] |
mov [ebx+usb_device_data.configpipe], eax |
xor ecx, ecx |
stdcall USBControlTransferAsync, eax, edx, ecx, ecx, idle_set, ebx, ecx |
; 7. Return pointer to usb_device_data. |
xchg eax, ebx |
jmp .nothing |
endp |
; This procedure is called by USB stack when SET_IDLE request initiated by |
; AddDevice is completed, either successfully or unsuccessfully. |
proc idle_set |
push ebx esi ; save used registers to be stdcall |
virtual at esp |
rd 2 ; saved registers |
dd ? ; return address |
.pipe dd ? |
.status dd ? |
.buffer dd ? |
.length dd ? |
.calldata dd ? |
end virtual |
; Ignore status. Support for SET_IDLE is optional, so the device is free to |
; STALL the request; config pipe should remain functional without explicit cleanup. |
mov ebx, [.calldata] |
; 1. HID descriptor contains length of Report descriptor. Parse it. |
mov esi, [ebx+usb_device_data.hiddescr] |
movzx ecx, [esi+hid_descr.bNumDescriptors] |
lea eax, [hid_descr.base_sizeof+ecx*3] |
cmp eax, 100h |
jae .cfgerror |
cmp al, [esi+hid_descr.bLength] |
jb .cfgerror |
.look_report: |
dec ecx |
js .cfgerror |
cmp [esi+hid_descr.subDescriptorType], REPORT_DESCR_TYPE |
jz .found_report |
add esi, 3 |
jmp .look_report |
.cfgerror: |
mov esi, invalid_config_descr_msg |
.abort_with_msg: |
call SysMsgBoardStr |
jmp .nothing |
.found_report: |
; 2. Send request for the Report descriptor. |
; 2a. Allocate memory. |
movzx eax, [esi+hid_descr.subDescriptorLength] |
test eax, eax |
jz .cfgerror |
push eax |
call Kmalloc |
pop ecx |
; If failed, say a message and stop initialization. |
mov esi, nomemory_msg |
test eax, eax |
jz .abort_with_msg |
; 2b. Submit the request. |
xchg eax, esi |
lea edx, [ebx+usb_device_data.control] |
mov eax, [ebx+usb_device_data.interface_number] |
mov dword [edx], 81h + \ ; Standard request to Interface |
(6 shl 8) + \ ; GET_DESCRIPTOR |
(0 shl 16) + \ ; descriptor index: there is only one report descriptor |
(REPORT_DESCR_TYPE shl 24); descriptor type |
mov [edx+4], ax ; Interface number |
mov [edx+6], cx ; descriptor length |
stdcall USBControlTransferAsync, [ebx+usb_device_data.configpipe], \ |
edx, esi, ecx, got_report, ebx, 0 |
; 2c. If failed, free the buffer and stop initialization. |
test eax, eax |
jnz .nothing |
xchg eax, esi |
call Kfree |
.nothing: |
pop esi ebx ; restore used registers to be stdcall |
ret 20 |
endp |
; This procedure is called by USB stack when the report descriptor queried |
; by idle_set is completed, either successfully or unsuccessfully. |
proc got_report stdcall uses ebx esi edi, pipe, status, buffer, length, calldata |
locals |
parse_descr_locals |
if ~HID_DUMP_UNCLAIMED |
has_driver db ? |
rb 3 |
end if |
endl |
; 1. Check the status; if the request has failed, say something to the debug board |
; and stop initialization. |
cmp [status], 0 |
jnz .generic_fail |
; 2. Subtract size of setup packet from the total length; |
; the rest is length of the descriptor, and it must be nonzero. |
sub [length], 8 |
ja .has_something |
.generic_fail: |
push esi |
mov esi, reportfail |
call SysMsgBoardStr |
pop esi |
jmp .exit |
.has_something: |
; 3. Process descriptor. |
; 3a. Dump it to the debug board, if enabled in compile-time setting. |
if USB_DUMP_DESCRIPTORS |
mov eax, [buffer] |
mov ecx, [length] |
DEBUGF 1,'K : report descriptor:' |
@@: |
DEBUGF 1,' %x',[eax]:2 |
inc eax |
dec ecx |
jnz @b |
DEBUGF 1,'\n' |
end if |
; 3b. Call the HID layer. |
parse_descr |
cmp [report_ok], 0 |
jz got_report.exit |
mov ebx, [calldata] |
postprocess_descr |
; 4. Stop initialization if no driver is assigned. |
if ~HID_DUMP_UNCLAIMED |
cmp [has_driver], 0 |
jz got_report.exit |
end if |
; 5. Open interrupt IN pipe. If failed, stop initialization. |
mov edx, [ebx+usb_device_data.epdescr] |
movzx ecx, [edx+endpoint_descr.bEndpointAddress] |
movzx eax, [edx+endpoint_descr.bInterval] |
movzx edx, [edx+endpoint_descr.wMaxPacketSize] |
stdcall USBOpenPipe, [ebx+usb_device_data.configpipe], ecx, edx, INTERRUPT_PIPE, eax |
test eax, eax |
jz got_report.exit |
mov [ebx+usb_device_data.intpipe], eax |
; 6. Initialize buffer for input packet. |
; 6a. Find the length of input packet. |
; This is the maximal length of all input reports. |
mov edx, [ebx+usb_device_data.hid.input.first_report] |
xor eax, eax |
.find_input_size: |
test edx, edx |
jz .found_input_size |
cmp eax, [edx+report.size] |
jae @f |
mov eax, [edx+report.size] |
@@: |
mov edx, [edx+report.next] |
jmp .find_input_size |
.found_input_size: |
; report.size is in bits, transform it to bytes |
add eax, 7 |
shr eax, 3 |
; if reports are numbered, the first byte is report ID, include it |
cmp [ebx+usb_device_data.hid.input.numbered], 0 |
jz @f |
inc eax |
@@: |
mov [ebx+usb_device_data.input_transfer_size], eax |
; 6b. Allocate memory for input packet: dword-align and add additional dword |
; for extract_field_value. |
add eax, 4+3 |
and eax, not 3 |
call Kmalloc |
test eax, eax |
jnz @f |
mov esi, nomemory_msg |
call SysMsgBoardStr |
jmp got_report.exit |
@@: |
mov [ebx+usb_device_data.input_buffer], eax |
; 7. Submit a request for input packet and wait for input. |
call ask_for_input |
got_report.exit: |
mov eax, [buffer] |
call Kfree |
ret |
endp |
; Helper procedure for got_report and got_input. |
; Submits a request for the next input packet. |
proc ask_for_input |
; just call USBNormalTransferAsync with correct parameters, |
; allow short packets |
stdcall USBNormalTransferAsync, \ |
[ebx+usb_device_data.intpipe], \ |
[ebx+usb_device_data.input_buffer], \ |
[ebx+usb_device_data.input_transfer_size], \ |
got_input, ebx, \ |
1 |
ret |
endp |
; This procedure is called by USB stack when a HID device responds with input |
; data packet. |
proc got_input stdcall uses ebx esi edi, pipe, status, buffer, length, calldata |
locals |
parse_input_locals |
endl |
; 1. Validate parameters: fail on error, ignore zero-length transfers. |
mov ebx, [calldata] |
cmp [status], 0 |
jnz .fail |
cmp [length], 0 |
jz .done |
; 2. Get pointer to report in esi. |
; 2a. If there are no report IDs, use hid.input.data. |
mov eax, [buffer] |
mov esi, [ebx+usb_device_data.hid.input.data] |
cmp [ebx+usb_device_data.hid.input.numbered], 0 |
jz .report_found |
; 2b. Otherwise, the first byte of report is report ID; |
; locate the report by its ID, advance buffer+length to one byte. |
movzx eax, byte [eax] |
mov esi, [esi+eax*4] |
inc [buffer] |
dec [length] |
.report_found: |
; 3. Validate: ignore transfers with unregistered report IDs |
; and transfers which are too short for the corresponding report. |
test esi, esi |
jz .done |
mov eax, [esi+report.size] |
add eax, 7 |
shr eax, 3 |
cmp eax, [length] |
ja .done |
; 4. Pass everything to HID layer. |
parse_input |
.done: |
; 5. Query the next input. |
mov ebx, [calldata] |
call ask_for_input |
.nothing: |
ret |
.fail: |
mov esi, transfer_error_msg |
call SysMsgBoardStr |
jmp .nothing |
endp |
; This function is called by the USB subsystem when a device is disconnected. |
proc DeviceDisconnected |
push ebx esi edi ; save used registers to be stdcall |
virtual at esp |
rd 3 ; saved registers |
dd ? ; return address |
.device_data dd ? |
end virtual |
; 1. Say a message. |
mov ebx, [.device_data] |
mov esi, disconnectmsg |
stdcall SysMsgBoardStr |
; 2. Ask HID layer to release all HID-related resources. |
hid_cleanup |
; 3. Free the device data. |
xchg eax, ebx |
call Kfree |
; 4. Return. |
.nothing: |
pop edi esi ebx ; restore used registers to be stdcall |
ret 4 ; purge one dword argument to be stdcall |
endp |
include 'sort.inc' |
include 'unclaimed.inc' |
include 'mouse.inc' |
include 'keyboard.inc' |
; strings |
my_driver db 'usbhid',0 |
nomemory_msg db 'K : no memory',13,10,0 |
invalid_config_descr_msg db 'K : invalid config descriptor',13,10,0 |
reportfail db 'K : failed to read report descriptor',13,10,0 |
transfer_error_msg db 'K : USB transfer error, disabling HID device',13,10,0 |
disconnectmsg db 'K : USB HID device disconnected',13,10,0 |
invalid_report_msg db 'K : report descriptor is invalid',13,10,0 |
delimiter_note db 'K : note: alternate usage ignored',13,10,0 |
; Exported variable: kernel API version. |
align 4 |
version dd 50005h |
; Structure with callback functions. |
usb_functions: |
dd 12 |
dd AddDevice |
dd DeviceDisconnected |
; for DEBUGF macro |
include_debug_strings |
; Workers data |
workers_globals |
; for uninitialized data |
;section '.data' data readable writable align 16 |
/kernel/branches/Kolibri-acpi/drivers/usbhid |
---|
Property changes: |
Added: tsvn:logminsize |
+5 |
\ No newline at end of property |
/kernel/branches/Kolibri-acpi/drivers/vidrdc.asm |
---|
0,0 → 1,438 |
; Stub of videodriver for RDC Semiconductor Co. M2010/M2012 videocards (controller names: R3306/R3308). |
; It is used in SoC produced by DMP Electronics Inc.: |
; Vortex86MX (contains RDC M2010 graphics card, appears in eBox-3300MX) |
; Vortex86MX+ (contains RDC M2012 graphics card, appears in eBox-3310MX) |
; Link to manufacturers websites - |
; RDC Semiconductor Co.: http://www.rdc.com.tw |
; DM&P Electronics Inc.: http://www.dmp.com.tw and http://www.compactpc.com.tw |
; Code stolen from vidintel.asm driver (c) by CleverMouse and adapted for RDC. |
; When the start procedure gets control, |
; it tries to detect preferred resolution, |
; sets the detected resolution assuming 32-bpp VESA mode and exits |
; (without registering a service). |
; Detection can be overloaded with compile-time settings |
; use_predefined_mode/predefined_width/predefined_height. |
; set predefined resolution here |
use_predefined_mode = 0;1 |
predefined_width = 0;1366 |
predefined_height = 0;768 |
; standard driver stuff |
format MS COFF |
DEBUG = 1 |
include 'proc32.inc' |
include 'imports.inc' |
public START |
public version |
section '.flat' code readable align 16 |
; the start procedure (see the description above) |
START: |
; 1. Detect device. Abort if not found. |
push esi |
call DetectDevice |
test esi, esi |
jz .return0 |
;{START}yogev_ezra: temporary exit after detection |
pusha |
mov esi, exitmsg |
call SysMsgBoardStr |
popa |
jmp .return0 |
;{END}yogev_ezra: temporary exit after detection |
; 2. Detect optimal mode unless the mode is given explicitly. Abort if failed. |
if use_predefined_mode = 0 |
call DetectMode |
end if |
cmp [width], 0 |
jz .return0_cleanup |
; 3. Set the detected mode. |
call SetMode |
; 4. Cleanup and return. |
.return0_cleanup: |
stdcall FreeKernelSpace, esi |
.return0: |
pop esi |
xor eax, eax |
ret 4 |
; check that there is RDC videocard |
; if so, map MMIO registers and set internal variables |
; esi points to MMIO block; NULL means no device |
DetectDevice: |
; 1. Sanity check: check that we are dealing with RDC videocard. |
; Integrated video device for RDC is always at PCI:0:13:0 (bus:dev:fn=0:0d:0) |
xor esi, esi ; initialize return value to NULL |
; 1a. Get PCI VendorID and DeviceID. |
push esi ; in: reg=0 (register) -> register 00 means return DeviceID (bits 16-31) + VendorID (bits 0-15) |
push 68h ; in: devfn=13:0 | device:5bit (0Dh = 1101) + func:3bit (0 = 000) -> total:1byte (1101000b = 68h) |
push esi ; in: bus=0 |
call PciRead32 |
; 1b. loword(eax) = ax = VendorID, hiword(eax) = DeviceID. |
; Test whether we have RDC Semiconductor Co. chipset. |
cmp ax, 17F3h ;VendorID 0x17F3, 'RDC Semiconductor Co.' |
jnz .return |
; 1c. Say hi including DeviceID. |
shr eax, 10h ; now, ax = HIWORD(eax) = PCI DeviceID |
push edi |
pusha |
mov edi, pciid_text ; edi='0000' |
call WriteWord |
mov esi, hellomsg |
call SysMsgBoardStr |
popa |
; 1d. Test whether we know this DeviceID. |
; If this is the case, remember the position of the device in line of RDC cards; |
; this knowledge will be useful later. |
; Tested on devices with id: 17F3:2010, 17F3:2012. |
mov ecx, pciids_num |
mov edi, pciids |
repnz scasw |
pop edi |
jnz .return_unknown_pciid |
sub ecx, pciids_num - 1 |
neg ecx |
mov [deviceType], ecx |
; 1e. Continue saying hi with positive intonation. |
pusha |
mov esi, knownmsg |
call SysMsgBoardStr |
popa |
; 2. Prepare MMIO region to control the card. |
; 2a. Read MMIO physical address from PCI config space. |
; According to RDC M2010/M2012 registers manual, their memory-mapped I/O space is located at Base address #1 |
push 14h ; in: reg=14h (register) -> register 14h means Base address #1 (BAR1) in PCI configuration space |
push 68h ; in: devfn=13:0 | device:5bit (0Dh = 1101) + func:3bit (0 = 000) -> total:1byte (1101000b = 68h) |
push esi ; in: bus=0 |
call PciRead32 |
; 2b. Mask out PCI region type, lower 4 bits. |
and al, not 0xF |
; 2c. Create virtual mapping of the physical memory. |
push 1Bh |
push 100000h |
push eax |
call MapIoMem |
; 3. Return. |
xchg esi, eax |
.return: |
ret |
; 1f. If we do not know DeviceID, continue saying hi with negative intonation. |
.return_unknown_pciid: |
pusha |
mov esi, unknownmsg |
call SysMsgBoardStr |
popa |
ret |
; Convert word in ax to hexadecimal text in edi, advance edi. |
WriteWord: |
; 1. Convert high byte. |
push eax |
mov al, ah |
call WriteByte |
pop eax |
; 2. Convert low byte. |
; Fall through to WriteByte; ret from WriteByte is ret from WriteWord too. |
; Convert byte in al to hexadecimal text in edi, advance edi. |
WriteByte: |
; 1. Convert high nibble. |
push eax |
shr al, 4 |
call WriteNibble |
pop eax |
; 2. Convert low nibble. |
and al, 0xF |
; Fall through to WriteNibble; ret from WriteNibble is ret from WriteByte too. |
; Convert nibble in al to hexadecimal text in edi, advance edi. |
WriteNibble: |
; Obvious, isn't it? |
cmp al, 10 |
sbb al, 69h |
das |
stosb ; This instruction uses EDI implicitly |
ret |
if use_predefined_mode = 0 |
; detect resolution of the flat panel |
DetectMode: |
push esi edi |
; 1. Get the location of block of GMBUS* registers. |
; Starting with Ironlake, GMBUS* registers were moved. |
add esi, 5100h |
cmp [deviceType], pciids_num ;ironlake_start |
jb @f |
add esi, 0xC0000 |
@@: |
; 2. Initialize GMBUS engine. |
mov edi, edid |
mov ecx, 0x10000 |
@@: |
test byte [esi+8+1], 80h |
loopnz @b |
jnz .fail |
mov dword [esi], 3 |
test byte [esi+8+1], 4 |
jz .noreset |
call ResetGMBus |
jnz .fail |
.noreset: |
; 3. Send read command. |
and dword [esi+20h], 0 |
mov dword [esi+4], 4E8000A1h |
; 4. Wait for data, writing to the buffer as data arrive. |
.getdata: |
mov ecx, 0x10000 |
@@: |
test byte [esi+8+1], 8 |
loopz @b |
test byte [esi+8+1], 4 |
jz .dataok |
call ResetGMBus |
jmp .fail |
.dataok: |
mov eax, [esi+0Ch] |
stosd |
cmp edi, edid+80h |
jb .getdata |
; 5. Wait for bus idle. |
mov ecx, 0x10000 |
@@: |
test byte [esi+8+1], 2 |
loopnz @b |
; 6. We got EDID; dump it if DEBUG. |
if DEBUG |
pusha |
xor ecx, ecx |
mov esi, edid |
mov edi, edid_text |
.dumploop: |
lodsb |
call WriteByte |
mov al, ' ' |
stosb |
inc cl |
test cl, 15 |
jnz @f |
mov byte [edi-1], 13 |
mov al, 10 |
stosb |
@@: |
test cl, cl |
jns .dumploop |
mov esi, edidmsg |
call SysMsgBoardStr |
popa |
end if |
; 7. Test whether EDID is good. |
; 7a. Signature: 00 FF FF FF FF FF FF 00. |
mov esi, edid |
cmp dword [esi], 0xFFFFFF00 |
jnz .fail |
cmp dword [esi+4], 0x00FFFFFF |
jnz .fail |
; 7b. Checksum must be zero. |
xor edx, edx |
mov ecx, 80h |
@@: |
lodsb |
add dl, al |
loop @b |
jnz .fail |
; 8. Get width and height from EDID. |
xor eax, eax |
mov ah, [esi-80h+3Ah] |
shr ah, 4 |
mov al, [esi-80h+38h] |
mov [width], eax |
mov ah, [esi-80h+3Dh] |
shr ah, 4 |
mov al, [esi-80h+3Bh] |
mov [height], eax |
; 9. Return. |
.fail: |
pop edi esi |
ret |
; reset bus, clear all errors |
ResetGMBus: |
; look into the PRM |
mov dword [esi+4], 80000000h |
mov dword [esi+4], 0 |
mov ecx, 0x10000 |
@@: |
test byte [esi+8+1], 2 |
loopnz @b |
ret |
end if |
; set resolution [width]*[height] |
SetMode: |
; 1. Program the registers of videocard. |
; look into the PRM |
cli |
; or byte [esi+7000Ah], 0Ch ; PIPEACONF: disable Display+Cursor Planes |
; or byte [esi+7100Ah], 0Ch ; PIPEBCONF: disable Display+Cursor Planes |
xor eax, eax |
xor edx, edx |
cmp [deviceType], pciids_num ;i965_start |
jb @f |
mov dl, 9Ch - 84h |
@@: |
; or byte [esi+71403h], 80h ; VGACNTRL: VGA Display Disable |
and byte [esi+70080h], not 27h ; CURACNTR: disable cursor A |
mov dword [esi+70084h], eax ; CURABASE: force write to CURA* regs |
and byte [esi+700C0h], not 27h ; CURBCNTR: disable cursor B |
mov dword [esi+700C4h], eax ; CURBBASE: force write to CURB* regs |
and byte [esi+70183h], not 80h ; DSPACNTR: disable Primary A Plane |
mov dword [esi+edx+70184h], eax ; DSPALINOFF/DSPASURF: force write to DSPA* regs |
and byte [esi+71183h], not 80h ; DSPBCNTR: disable Primary B Plane |
mov dword [esi+edx+71184h], eax ; DSPBLINOFF/DSPBSURF: force write to DSPB* regs |
if 1 |
cmp [deviceType], pciids_num ;ironlake_start |
jae .disable_pipes |
mov edx, 10000h |
or byte [esi+70024h], 2 ; PIPEASTAT: clear VBLANK status |
or byte [esi+71024h], 2 ; PIPEBSTAT: clear VBLANK status |
.wait_vblank_preironlake1: |
mov ecx, 1000h |
loop $ |
test byte [esi+7000Bh], 80h ; PIPEACONF: pipe A active? |
jz @f |
test byte [esi+70024h], 2 ; PIPEASTAT: got VBLANK? |
jz .wait_vblank_preironlake2 |
@@: |
test byte [esi+7100Bh], 80h ; PIPEBCONF: pipe B active? |
jz .disable_pipes |
test byte [esi+71024h], 2 ; PIPEBSTAT: got VBLANK? |
jnz .disable_pipes |
.wait_vblank_preironlake2: |
dec edx |
jnz .wait_vblank_preironlake1 |
jmp .not_disabled |
.disable_pipes: |
end if |
and byte [esi+7000Bh], not 80h ; PIPEACONF: disable pipe |
and byte [esi+7100Bh], not 80h ; PIPEBCONF: disable pipe |
cmp [deviceType], pciids_num ;gen4_start |
jb .wait_watching_scanline |
; g45 and later: use special flag from PIPE*CONF |
mov edx, 10000h |
@@: |
mov ecx, 1000h |
loop $ |
test byte [esi+7000Bh], 40h ; PIPEACONF: wait until pipe disabled |
jz @f |
dec edx |
jnz @b |
jmp .not_disabled |
@@: |
test byte [esi+7100Bh], 40h ; PIPEBCONF: wait until pipe disabled |
jz .disabled |
mov ecx, 1000h |
loop $ |
dec edx |
jnz @b |
jmp .not_disabled |
; pineview and before: wait while scanline still changes |
.wait_watching_scanline: |
mov edx, 1000h |
.dis1: |
push dword [esi+71000h] |
push dword [esi+70000h] |
mov ecx, 10000h |
loop $ |
pop eax |
xor eax, [esi+70000h] |
and eax, 1FFFh |
pop eax |
jnz .notdis1 |
xor eax, [esi+71000h] |
and eax, 1FFFh |
jz .disabled |
.notdis1: |
dec edx |
jnz .dis1 |
.not_disabled: |
sti |
jmp .return |
.disabled: |
lea eax, [esi+61183h] |
cmp [deviceType], pciids_num ;ironlake_start |
jb @f |
add eax, 0xE0000 - 0x60000 |
@@: |
lea edx, [esi+60000h] |
test byte [eax], 40h |
jz @f |
add edx, 1000h |
@@: |
mov eax, [width] |
dec eax |
shl eax, 16 |
mov ax, word [height] |
dec eax |
mov dword [edx+1Ch], eax ; PIPEASRC: set source image size |
ror eax, 16 |
mov dword [edx+10190h], eax ; for old cards |
mov ecx, [width] |
add ecx, 15 |
and ecx, not 15 |
shl ecx, 2 |
mov dword [edx+10188h], ecx ; DSPASTRIDE: set scanline length |
mov dword [edx+10184h], 0 ; DSPALINOFF: force write to DSPA* registers |
and byte [esi+61233h], not 80h ; PFIT_CONTROL: disable panel fitting |
or byte [edx+1000Bh], 80h ; PIPEACONF: enable pipe |
; and byte [edx+1000Ah], not 0Ch ; PIPEACONF: enable Display+Cursor Planes |
or byte [edx+10183h], 80h ; DSPACNTR: enable Display Plane A |
sti |
; 2. Notify the kernel that resolution has changed. |
call GetDisplay |
mov edx, [width] |
mov dword [eax+8], edx |
mov edx, [height] |
mov dword [eax+0Ch], edx |
mov [eax+18h], ecx |
mov eax, [width] |
dec eax |
dec edx |
call SetScreen |
.return: |
ret |
align 4 |
hellomsg db 'RDC videocard detected, PciId=17F3:' ;VendorID 0x17F3, 'RDC Semiconductor Co.' |
pciid_text db '0000' |
db ', which is ', 0 |
knownmsg db 'known',13,10,0 |
unknownmsg db 'unknown',13,10,0 |
exitmsg db 'Card detected successfully, exiting driver...',13,10,0 |
if DEBUG |
edidmsg db 'EDID successfully read:',13,10 |
edid_text rb 8*(16*3+1) |
db 0 |
end if |
version: |
dd 0x50005 |
width dd predefined_width |
height dd predefined_height |
pciids: |
dw 0x2010 ; M2010 - appears in eBox-3300MX (Vortex86MX SoC) |
dw 0x2012 ; M2012 - appears in eBox-3310MX (Vortex86MX+ SoC) |
pciids_num = ($ - pciids) / 2 |
align 4 |
deviceType dd ? |
edid rb 0x80 |
/kernel/branches/Kolibri-acpi/drivers/imports.inc |
---|
0,0 → 1,112 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
macro kernel_export [name]{ |
forward |
if used name |
if DEBUG |
display 'uses: ',`name,#13,#10 |
end if |
extrn name |
end if |
} |
; all exported kernel functions and data |
kernel_export \ |
RegService,\ |
GetService,\ |
ServiceHandler,\ |
AttachIntHandler,\ |
GetIntHandler,\ |
FpuSave,\ |
FpuRestore,\ |
ReservePortArea,\ |
Boot_Log,\ |
\ |
MutexInit,\ |
MutexLock,\ |
MutexUnlock,\ |
\ |
PciApi,\ |
PciRead32,\ |
PciRead16,\ |
PciRead8,\ |
PciWrite8,\ |
PciWrite16,\ |
PciWrite32,\ |
\ |
AllocPage,\ |
AllocPages,\ |
FreePage,\ |
MapPage,\ |
MapSpace,\ |
MapIoMem,\ |
GetPgAddr,\ |
CommitPages,\ |
ReleasePages,\ |
\ |
AllocKernelSpace,\ |
FreeKernelSpace,\ |
KernelAlloc,\ |
KernelFree,\ |
UserAlloc,\ |
UserFree,\ |
Kmalloc,\ |
Kfree,\ |
CreateRingBuffer,\ |
\ |
GetPid,\ |
CreateThread,\ |
CreateObject,\ |
DestroyObject,\ |
CreateEvent,\ |
RaiseEvent,\ |
WaitEvent,\ |
DestroyEvent,\ |
ClearEvent,\ |
\ |
LoadCursor,\ |
SelectHwCursor,\ |
SetHwCursor,\ |
HwCursorRestore,\ |
HwCursorCreate,\ |
\ |
SysMsgBoardStr,\ |
SysMsgBoard,\ |
GetCurrentTask,\ |
LoadFile,\ |
SendEvent,\ |
SetMouseData,\ |
SetKeyboardData,\ |
RegKeyboard,\ |
DelKeyboard,\ |
Sleep,\ |
GetTimerTicks,\ |
\ |
strncat,\ |
strncpy,\ |
strncmp,\ |
strnlen,\ |
strchr,\ |
strrchr,\ |
\ |
LFBAddress,\ |
GetDisplay,\ |
SetScreen,\ |
\ |
RegUSBDriver,\ |
USBOpenPipe,\ |
USBNormalTransferAsync,\ |
USBControlTransferAsync,\ |
USBGetParam,\ |
\ |
DiskAdd,\ |
DiskMediaChanged,\ |
DiskDel,\ |
\ |
TimerHS,\ |
CancelTimerHS |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
/kernel/branches/Kolibri-acpi/drivers/sound.asm |
---|
0,0 → 1,423 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
format MS COFF |
DEBUG = 1 |
include 'proc32.inc' |
include 'imports.inc' |
include '../struct.inc' |
VID_INTEL = 0x8086 |
VID_NVIDIA = 0x10DE |
VID_VIA = 0x1106 |
VID_SIS = 0x1039 |
VID_FM801 = 0x1319 |
VID_CREATIVE = 0x1102 |
VID_ATI = 0x1002 |
VID_AMD = 0x1022 |
VID_ULI = 0x10B9 |
VID_TERA = 0x6549 |
VID_RDC = 0x17F3 |
VID_VMWARE = 0x15AD |
CTRL_ICH = 0x2415 |
CTRL_ICH0 = 0x2425 |
CTRL_ICH2 = 0x2435 |
CTRL_ICH3 = 0x2445 |
CTRL_ICH4 = 0x24C5 |
CTRL_ICH5 = 0x24D5 |
CTRL_ICH6 = 0x266E |
CTRL_ICH7 = 0x27DE |
CTRL_NFORCE = 0x01B1 |
CTRL_NFORCE2 = 0x006A |
CTRL_NFORCE3 = 0x00DA |
CTRL_MCP04 = 0x003A |
CTRL_CK804 = 0x0059 |
CTRL_CK8 = 0x008A |
CTRL_CK8S = 0x00EA |
CTRL_MCP51 = 0x026B |
CTRL_VT82C686 = 0x3058 |
CTRL_VT8233_5 = 0x3059 |
CTRL_SIS = 0x7012 |
CTRL_FM801 = 0x0801 |
CTRL_CT0200 = 0x0006 ; Dell OEM version (EMU10K1X) |
CTRL_INTEL_SCH2 = 0x080a |
CTRL_INTEL_HPT = 0x0c0c |
CTRL_INTEL_CPT = 0x1c20 |
CTRL_INTEL_PGB = 0x1d20 |
CTRL_INTEL_PPT1 = 0x1e20 |
CTRL_INTEL_82801F = 0x2668 |
CTRL_INTEL_63XXESB = 0x269a |
CTRL_INTEL_82801G = 0x27d8 |
CTRL_INTEL_82801H = 0x284b |
CTRL_INTEL_82801_UNK1 = 0x2911 |
CTRL_INTEL_82801I = 0x293e |
CTRL_INTEL_82801_UNK2 = 0x293f |
CTRL_INTEL_82801JI = 0x3a3e |
CTRL_INTEL_82801JD = 0x3a6e |
CTRL_INTEL_PCH = 0x3b56 |
CTRL_INTEL_PCH2 = 0x3b57 |
CTRL_INTEL_SCH = 0x811b |
CTRL_INTEL_LPT = 0x8c20 |
CTRL_NVIDIA_MCP51 = 0x026c |
CTRL_NVIDIA_MCP55 = 0x0371 |
CTRL_NVIDIA_MCP61_1 = 0x03e4 |
CTRL_NVIDIA_MCP61_2 = 0x03f0 |
CTRL_NVIDIA_MCP65_1 = 0x044a |
CTRL_NVIDIA_MCP65_2 = 0x044b |
CTRL_NVIDIA_MCP67_1 = 0x055c |
CTRL_NVIDIA_MCP67_2 = 0x055d |
CTRL_NVIDIA_MCP78_1 = 0x0774 |
CTRL_NVIDIA_MCP78_2 = 0x0775 |
CTRL_NVIDIA_MCP78_3 = 0x0776 |
CTRL_NVIDIA_MCP78_4 = 0x0777 |
CTRL_NVIDIA_MCP73_1 = 0x07fc |
CTRL_NVIDIA_MCP73_2 = 0x07fd |
CTRL_NVIDIA_MCP79_1 = 0x0ac0 |
CTRL_NVIDIA_MCP79_2 = 0x0ac1 |
CTRL_NVIDIA_MCP79_3 = 0x0ac2 |
CTRL_NVIDIA_MCP79_4 = 0x0ac3 |
CTRL_NVIDIA_0BE2 = 0x0be2 |
CTRL_NVIDIA_0BE3 = 0x0be3 |
CTRL_NVIDIA_0BE4 = 0x0be4 |
CTRL_NVIDIA_GT100 = 0x0be5 |
CTRL_NVIDIA_GT106 = 0x0be9 |
CTRL_NVIDIA_GT108 = 0x0bea |
CTRL_NVIDIA_GT104 = 0x0beb |
CTRL_NVIDIA_GT116 = 0x0bee |
CTRL_NVIDIA_MCP89_1 = 0x0d94 |
CTRL_NVIDIA_MCP89_2 = 0x0d95 |
CTRL_NVIDIA_MCP89_3 = 0x0d96 |
CTRL_NVIDIA_MCP89_4 = 0x0d97 |
CTRL_NVIDIA_GF119 = 0x0e08 |
CTRL_NVIDIA_GF110_1 = 0x0e09 |
CTRL_NVIDIA_GF110_2 = 0x0e0c |
CTRL_ATI_SB450 = 0x437b |
CTRL_ATI_SB600 = 0x4383 |
CTRL_ATI_RS600 = 0x793b |
CTRL_ATI_RS690 = 0x7919 |
CTRL_ATI_RS780 = 0x960f |
CTRL_ATI_RS_UNK1 = 0x970f |
CTRL_ATI_R600 = 0xaa00 |
CTRL_ATI_RV630 = 0xaa08 |
CTRL_ATI_RV610 = 0xaa10 |
CTRL_ATI_RV670 = 0xaa18 |
CTRL_ATI_RV635 = 0xaa20 |
CTRL_ATI_RV620 = 0xaa28 |
CTRL_ATI_RV770 = 0xaa30 |
CTRL_ATI_RV730 = 0xaa38 |
CTRL_ATI_RV710 = 0xaa40 |
CTRL_ATI_RV740 = 0xaa48 |
CTRL_AMD_HUDSON = 0x780d |
CTRL_VIA_VT82XX = 0x3288 |
CTRL_VIA_VT61XX = 0x9140 |
CTRL_VIA_VT71XX = 0x9170 |
CTRL_SIS_966 = 0x7502 |
CTRL_ULI_M5461 = 0x5461 |
CTRL_CREATIVE_CA0110_IBG = 0x0009 |
CTRL_CREATIVE_SOUND_CORE3D_1 = 0x0010 |
CTRL_CREATIVE_SOUND_CORE3D_2 = 0x0012 |
CTRL_TERA_UNK1 = 0x1200 |
CTRL_RDC_R3010 = 0x3010 |
CTRL_VMWARE_UNK1 = 0x1977 |
API_VERSION = 0x01000100 |
public START |
public service_proc |
public version |
struct SRV |
srv_name rb 16 ;ASCIIZ string |
magic dd ? ;+0x10 ;'SRV ' |
size dd ? ;+0x14 ;size of structure SRV |
fd dd ? ;+0x18 ;next SRV descriptor |
bk dd ? ;+0x1C ;prev SRV descriptor |
base dd ? ;+0x20 ;service base address |
entry dd ? ;+0x24 ;service START function |
srv_proc dd ? ;+0x28 ;user mode service handler |
srv_proc_ex dd ? ;+0x2C ;kernel mode service handler |
ends |
section '.flat' code readable align 16 |
proc START stdcall, state:dword |
mov eax, [srv_entry] |
cmp [state], 1 |
jne .stop |
if DEBUG |
mov esi, msgInit |
call SysMsgBoardStr |
end if |
test eax, eax |
jnz .done |
call detect_controller |
ret |
.stop: |
test eax, eax |
jz .done |
leave |
jmp eax |
.done: |
xor eax, eax |
ret |
endp |
align 4 |
proc service_proc stdcall, ioctl:dword |
or eax, -1 |
ret |
endp |
align 4 |
proc detect_controller |
locals |
last_bus dd ? |
bus dd ? |
devfn dd ? |
endl |
xor eax, eax |
mov [bus], eax |
inc eax |
call PciApi |
cmp eax, -1 |
je .err |
mov [last_bus], eax |
.next_bus: |
and [devfn], 0 |
.next_dev: |
stdcall PciRead32, [bus], [devfn], dword 0 |
test eax, eax |
jz .next |
cmp eax, -1 |
je .next |
mov edi, devices |
@@: |
mov ebx, [edi] |
test ebx, ebx |
jz .next |
cmp eax, ebx |
je .found |
add edi, 8 |
jmp @B |
.next: |
inc [devfn] |
cmp [devfn], 256 |
jb .next_dev |
mov eax, [bus] |
inc eax |
mov [bus], eax |
cmp eax, [last_bus] |
jna .next_bus |
xor eax, eax |
ret |
.found: |
if DEBUG |
mov esi, msgLoading |
call SysMsgBoardStr |
mov esi, dword[edi+4] |
call SysMsgBoardStr |
mov esi, msgNewline |
call SysMsgBoardStr |
end if |
stdcall GetService, dword[edi+4] |
test eax, eax |
jz .err |
mov edx, [eax+SRV.entry] |
mov [srv_entry], edx |
ret |
.err: |
if DEBUG |
mov esi, msgFail |
call SysMsgBoardStr |
end if |
xor eax, eax |
ret |
endp |
align 4 |
devices dd (CTRL_ICH shl 16)+VID_INTEL, intelac97 |
dd (CTRL_ICH0 shl 16)+VID_INTEL, intelac97 |
dd (CTRL_ICH2 shl 16)+VID_INTEL, intelac97 |
dd (CTRL_ICH3 shl 16)+VID_INTEL, intelac97 |
dd (CTRL_ICH4 shl 16)+VID_INTEL, intelac97 |
dd (CTRL_ICH5 shl 16)+VID_INTEL, intelac97 |
dd (CTRL_ICH6 shl 16)+VID_INTEL, intelac97 |
dd (CTRL_ICH7 shl 16)+VID_INTEL, intelac97 |
dd (CTRL_NFORCE shl 16)+VID_NVIDIA, intelac97 |
dd (CTRL_NFORCE2 shl 16)+VID_NVIDIA, intelac97 |
dd (CTRL_NFORCE3 shl 16)+VID_NVIDIA, intelac97 |
dd (CTRL_MCP04 shl 16)+VID_NVIDIA, intelac97 |
dd (CTRL_CK804 shl 16)+VID_NVIDIA, intelac97 |
dd (CTRL_CK8 shl 16)+VID_NVIDIA, intelac97 |
dd (CTRL_CK8S shl 16)+VID_NVIDIA, intelac97 |
dd (CTRL_MCP51 shl 16)+VID_NVIDIA, intelac97 |
dd (CTRL_VT82C686 shl 16)+VID_VIA, vt823x |
dd (CTRL_VT8233_5 shl 16)+VID_VIA, vt823x |
dd (CTRL_SIS shl 16)+VID_SIS, sis |
dd (CTRL_FM801 shl 16)+VID_FM801, fm801 |
dd (0x5000 shl 16)+0x1274, ensoniq |
dd (0x5880 shl 16)+0x1274, ensoniq |
dd (CTRL_CT0200 shl 16)+VID_CREATIVE, emu10k1x |
; Intel |
dd (CTRL_INTEL_SCH2 shl 16)+VID_INTEL, intelhda |
dd (CTRL_INTEL_HPT shl 16)+VID_INTEL, intelhda |
dd (CTRL_INTEL_CPT shl 16)+VID_INTEL, intelhda |
dd (CTRL_INTEL_PGB shl 16)+VID_INTEL, intelhda |
dd (CTRL_INTEL_PPT1 shl 16)+VID_INTEL, intelhda |
dd (CTRL_INTEL_82801F shl 16)+VID_INTEL, intelhda |
dd (CTRL_INTEL_63XXESB shl 16)+VID_INTEL, intelhda |
dd (CTRL_INTEL_82801G shl 16)+VID_INTEL, intelhda |
dd (CTRL_INTEL_82801H shl 16)+VID_INTEL, intelhda |
dd (CTRL_INTEL_82801_UNK1 shl 16)+VID_INTEL, intelhda |
dd (CTRL_INTEL_82801I shl 16)+VID_INTEL, intelhda |
dd (CTRL_INTEL_82801_UNK2 shl 16)+VID_INTEL, intelhda |
dd (CTRL_INTEL_82801JI shl 16)+VID_INTEL, intelhda |
dd (CTRL_INTEL_82801JD shl 16)+VID_INTEL, intelhda |
dd (CTRL_INTEL_PCH shl 16)+VID_INTEL, intelhda |
dd (CTRL_INTEL_PCH2 shl 16)+VID_INTEL, intelhda |
dd (CTRL_INTEL_SCH shl 16)+VID_INTEL, intelhda |
dd (CTRL_INTEL_LPT shl 16)+VID_INTEL, intelhda |
; Nvidia |
dd (CTRL_NVIDIA_MCP51 shl 16)+VID_NVIDIA, intelhda |
dd (CTRL_NVIDIA_MCP55 shl 16)+VID_NVIDIA, intelhda |
dd (CTRL_NVIDIA_MCP61_1 shl 16)+VID_NVIDIA, intelhda |
dd (CTRL_NVIDIA_MCP61_2 shl 16)+VID_NVIDIA, intelhda |
dd (CTRL_NVIDIA_MCP65_1 shl 16)+VID_NVIDIA, intelhda |
dd (CTRL_NVIDIA_MCP65_2 shl 16)+VID_NVIDIA, intelhda |
dd (CTRL_NVIDIA_MCP67_1 shl 16)+VID_NVIDIA, intelhda |
dd (CTRL_NVIDIA_MCP67_2 shl 16)+VID_NVIDIA, intelhda |
dd (CTRL_NVIDIA_MCP73_1 shl 16)+VID_NVIDIA, intelhda |
dd (CTRL_NVIDIA_MCP73_2 shl 16)+VID_NVIDIA, intelhda |
dd (CTRL_NVIDIA_MCP78_1 shl 16)+VID_NVIDIA, intelhda |
dd (CTRL_NVIDIA_MCP78_2 shl 16)+VID_NVIDIA, intelhda |
dd (CTRL_NVIDIA_MCP78_3 shl 16)+VID_NVIDIA, intelhda |
dd (CTRL_NVIDIA_MCP78_4 shl 16)+VID_NVIDIA, intelhda |
dd (CTRL_NVIDIA_MCP79_1 shl 16)+VID_NVIDIA, intelhda |
dd (CTRL_NVIDIA_MCP79_2 shl 16)+VID_NVIDIA, intelhda |
dd (CTRL_NVIDIA_MCP79_3 shl 16)+VID_NVIDIA, intelhda |
dd (CTRL_NVIDIA_MCP79_4 shl 16)+VID_NVIDIA, intelhda |
dd (CTRL_NVIDIA_0BE2 shl 16)+VID_NVIDIA, intelhda |
dd (CTRL_NVIDIA_0BE3 shl 16)+VID_NVIDIA, intelhda |
dd (CTRL_NVIDIA_0BE4 shl 16)+VID_NVIDIA, intelhda |
dd (CTRL_NVIDIA_GT100 shl 16)+VID_NVIDIA, intelhda |
dd (CTRL_NVIDIA_GT106 shl 16)+VID_NVIDIA, intelhda |
dd (CTRL_NVIDIA_GT108 shl 16)+VID_NVIDIA, intelhda |
dd (CTRL_NVIDIA_GT104 shl 16)+VID_NVIDIA, intelhda |
dd (CTRL_NVIDIA_GT116 shl 16)+VID_NVIDIA, intelhda |
dd (CTRL_NVIDIA_MCP89_1 shl 16)+VID_NVIDIA, intelhda |
dd (CTRL_NVIDIA_MCP89_2 shl 16)+VID_NVIDIA, intelhda |
dd (CTRL_NVIDIA_MCP89_3 shl 16)+VID_NVIDIA, intelhda |
dd (CTRL_NVIDIA_MCP89_4 shl 16)+VID_NVIDIA, intelhda |
dd (CTRL_NVIDIA_GF119 shl 16)+VID_NVIDIA, intelhda |
dd (CTRL_NVIDIA_GF110_1 shl 16)+VID_NVIDIA, intelhda |
dd (CTRL_NVIDIA_GF110_2 shl 16)+VID_NVIDIA, intelhda |
; ATI |
dd (CTRL_ATI_SB450 shl 16)+VID_ATI, intelhda |
dd (CTRL_ATI_SB600 shl 16)+VID_ATI, intelhda |
dd (CTRL_ATI_RS600 shl 16)+VID_ATI, intelhda |
dd (CTRL_ATI_RS690 shl 16)+VID_ATI, intelhda |
dd (CTRL_ATI_RS780 shl 16)+VID_ATI, intelhda |
dd (CTRL_ATI_RS_UNK1 shl 16)+VID_ATI, intelhda |
dd (CTRL_ATI_R600 shl 16)+VID_ATI, intelhda |
dd (CTRL_ATI_RV610 shl 16)+VID_ATI, intelhda |
dd (CTRL_ATI_RV620 shl 16)+VID_ATI, intelhda |
dd (CTRL_ATI_RV630 shl 16)+VID_ATI, intelhda |
dd (CTRL_ATI_RV635 shl 16)+VID_ATI, intelhda |
dd (CTRL_ATI_RV670 shl 16)+VID_ATI, intelhda |
dd (CTRL_ATI_RV710 shl 16)+VID_ATI, intelhda |
dd (CTRL_ATI_RV730 shl 16)+VID_ATI, intelhda |
dd (CTRL_ATI_RV740 shl 16)+VID_ATI, intelhda |
dd (CTRL_ATI_RV770 shl 16)+VID_ATI, intelhda |
; AMD |
dd (CTRL_AMD_HUDSON shl 16)+VID_AMD, intelhda |
; VIA |
dd (CTRL_VIA_VT82XX shl 16)+VID_VIA, intelhda |
dd (CTRL_VIA_VT61XX shl 16)+VID_VIA, intelhda |
dd (CTRL_VIA_VT71XX shl 16)+VID_VIA, intelhda |
; SiS |
dd (CTRL_SIS_966 shl 16)+VID_SIS, intelhda |
; ULI |
dd (CTRL_ULI_M5461 shl 16)+VID_ULI, intelhda |
; Teradici |
dd (CTRL_TERA_UNK1 shl 16)+VID_ULI, intelhda |
; Creative |
dd (CTRL_CREATIVE_CA0110_IBG shl 16)+VID_CREATIVE, intelhda |
dd (CTRL_CREATIVE_SOUND_CORE3D_1 shl 16)+VID_CREATIVE, intelhda |
dd (CTRL_CREATIVE_SOUND_CORE3D_2 shl 16)+VID_CREATIVE, intelhda |
; RDC Semiconductor |
dd (CTRL_RDC_R3010 shl 16)+VID_RDC, intelhda |
; VMware |
dd (CTRL_VMWARE_UNK1 shl 16)+VID_VMWARE, intelhda |
dd 0 ;terminator |
version dd (5 shl 16) or (API_VERSION and 0xFFFF) |
srv_entry dd 0 |
intelac97 db 'INTELAC97', 0 |
vt823x db 'VT823X', 0 |
sis db 'SIS', 0 |
fm801 db 'FM801', 0 |
ensoniq db 'ENSONIQ', 0 |
emu10k1x db 'EMU10K1X', 0 |
intelhda db 'INTEL_HDA', 0 |
msgInit db 'Detecting hardware...',13,10,0 |
msgFail db 'No compatible soundcard found!',13,10,0 |
msgLoading db 'Loading ',0 |
msgNewline db 13,10,0 |
section '.data' data readable writable align 16 |
/kernel/branches/Kolibri-acpi/drivers/vidintel.asm |
---|
0,0 → 1,465 |
; Stub of videodriver for Intel videocards. |
; (c) CleverMouse |
; When the start procedure gots control, |
; it tries to detect preferred resolution, |
; sets the detected resolution assuming 32-bpp VESA mode and exits |
; (without registering a service). |
; Detection can be overloaded with compile-time settings |
; use_predefined_mode/predefined_width/predefined_height. |
; set predefined resolution here |
use_predefined_mode = 0;1 |
predefined_width = 0;1366 |
predefined_height = 0;768 |
; standard driver stuff |
format MS COFF |
DEBUG = 1 |
include 'proc32.inc' |
include 'imports.inc' |
public START |
public version |
section '.flat' code readable align 16 |
; the start procedure (see the description above) |
START: |
; 1. Detect device. Abort if not found. |
push esi |
call DetectDevice |
test esi, esi |
jz .return0 |
; 2. Detect optimal mode unless the mode is given explicitly. Abort if failed. |
if use_predefined_mode = 0 |
call DetectMode |
end if |
cmp [width], 0 |
jz .return0_cleanup |
; 3. Set the detected mode. |
call SetMode |
; 4. Cleanup and return. |
.return0_cleanup: |
stdcall FreeKernelSpace, esi |
.return0: |
pop esi |
xor eax, eax |
ret 4 |
; check that there is Intel videocard |
; if so, map MMIO registers and set internal variables |
; esi points to MMIO block; NULL means no device |
DetectDevice: |
; 1. Sanity check: check that we are dealing with Intel videocard. |
; Integrated video device for Intel is always at PCI:0:2:0. |
xor esi, esi ; initialize return value to NULL |
; 1a. Get PCI VendorID and DeviceID. |
push esi |
push 10h |
push esi |
call PciRead32 |
; 1b. loword(eax) = ax = VendorID, hiword(eax) = DeviceID. |
; Test whether we have Intel chipset. |
cmp ax, 8086h |
jnz .return |
; 1c. Say hi including DeviceID. |
shr eax, 10h |
push edi |
pusha |
mov edi, pciid_text |
call WriteWord |
mov esi, hellomsg |
call SysMsgBoardStr |
popa |
; 1d. Test whether we know this DeviceID. |
; If this is the case, remember the position of the device in line of Intel cards; |
; this knowledge will be useful later. |
; Tested on devices with id: 8086:0046, partially 8086:2A02. |
mov ecx, pciids_num |
mov edi, pciids |
repnz scasw |
pop edi |
jnz .return_unknown_pciid |
sub ecx, pciids_num - 1 |
neg ecx |
mov [deviceType], ecx |
; 1e. Continue saying hi with positive intonation. |
pusha |
mov esi, knownmsg |
call SysMsgBoardStr |
popa |
; 2. Prepare MMIO region to control the card. |
; 2a. Read MMIO physical address from PCI config space. |
push 10h |
cmp ecx, i9xx_start |
jae @f |
mov byte [esp], 14h |
@@: |
push 10h |
push esi |
call PciRead32 |
; 2b. Mask out PCI region type, lower 4 bits. |
and al, not 0xF |
; 2c. Create virtual mapping of the physical memory. |
push 1Bh |
push 100000h |
push eax |
call MapIoMem |
; 3. Return. |
xchg esi, eax |
.return: |
ret |
; 1f. If we do not know DeviceID, continue saying hi with negative intonation. |
.return_unknown_pciid: |
pusha |
mov esi, unknownmsg |
call SysMsgBoardStr |
popa |
ret |
; Convert word in ax to hexadecimal text in edi, advance edi. |
WriteWord: |
; 1. Convert high byte. |
push eax |
mov al, ah |
call WriteByte |
pop eax |
; 2. Convert low byte. |
; Fall through to WriteByte; ret from WriteByte is ret from WriteWord too. |
; Convert byte in al to hexadecimal text in edi, advance edi. |
WriteByte: |
; 1. Convert high nibble. |
push eax |
shr al, 4 |
call WriteNibble |
pop eax |
; 2. Convert low nibble. |
and al, 0xF |
; Fall through to WriteNibble; ret from WriteNibble is ret from WriteByte too. |
; Convert nibble in al to hexadecimal text in edi, advance edi. |
WriteNibble: |
; Obvious, isn't it? |
cmp al, 10 |
sbb al, 69h |
das |
stosb |
ret |
if use_predefined_mode = 0 |
; detect resolution of the flat panel |
DetectMode: |
push esi edi |
; 1. Get the location of block of GMBUS* registers. |
; Starting with Ironlake, GMBUS* registers were moved. |
add esi, 5100h |
cmp [deviceType], ironlake_start |
jb @f |
add esi, 0xC0000 |
@@: |
; 2. Initialize GMBUS engine. |
mov edi, edid |
mov ecx, 0x10000 |
@@: |
test byte [esi+8+1], 80h |
loopnz @b |
jnz .fail |
mov dword [esi], 3 |
test byte [esi+8+1], 4 |
jz .noreset |
call ResetGMBus |
jnz .fail |
.noreset: |
; 3. Send read command. |
and dword [esi+20h], 0 |
mov dword [esi+4], 4E8000A1h |
; 4. Wait for data, writing to the buffer as data arrive. |
.getdata: |
mov ecx, 0x10000 |
@@: |
test byte [esi+8+1], 8 |
loopz @b |
test byte [esi+8+1], 4 |
jz .dataok |
call ResetGMBus |
jmp .fail |
.dataok: |
mov eax, [esi+0Ch] |
stosd |
cmp edi, edid+80h |
jb .getdata |
; 5. Wait for bus idle. |
mov ecx, 0x10000 |
@@: |
test byte [esi+8+1], 2 |
loopnz @b |
; 6. We got EDID; dump it if DEBUG. |
if DEBUG |
pusha |
xor ecx, ecx |
mov esi, edid |
mov edi, edid_text |
.dumploop: |
lodsb |
call WriteByte |
mov al, ' ' |
stosb |
inc cl |
test cl, 15 |
jnz @f |
mov byte [edi-1], 13 |
mov al, 10 |
stosb |
@@: |
test cl, cl |
jns .dumploop |
mov esi, edidmsg |
call SysMsgBoardStr |
popa |
end if |
; 7. Test whether EDID is good. |
; 7a. Signature: 00 FF FF FF FF FF FF 00. |
mov esi, edid |
cmp dword [esi], 0xFFFFFF00 |
jnz .fail |
cmp dword [esi+4], 0x00FFFFFF |
jnz .fail |
; 7b. Checksum must be zero. |
xor edx, edx |
mov ecx, 80h |
@@: |
lodsb |
add dl, al |
loop @b |
jnz .fail |
; 8. Get width and height from EDID. |
xor eax, eax |
mov ah, [esi-80h+3Ah] |
shr ah, 4 |
mov al, [esi-80h+38h] |
mov [width], eax |
mov ah, [esi-80h+3Dh] |
shr ah, 4 |
mov al, [esi-80h+3Bh] |
mov [height], eax |
; 9. Return. |
.fail: |
pop edi esi |
ret |
; reset bus, clear all errors |
ResetGMBus: |
; look into the PRM |
mov dword [esi+4], 80000000h |
mov dword [esi+4], 0 |
mov ecx, 0x10000 |
@@: |
test byte [esi+8+1], 2 |
loopnz @b |
ret |
end if |
; set resolution [width]*[height] |
SetMode: |
; 1. Program the registers of videocard. |
; look into the PRM |
cli |
; or byte [esi+7000Ah], 0Ch ; PIPEACONF: disable Display+Cursor Planes |
; or byte [esi+7100Ah], 0Ch ; PIPEBCONF: disable Display+Cursor Planes |
xor eax, eax |
xor edx, edx |
cmp [deviceType], i965_start |
jb @f |
mov dl, 9Ch - 84h |
@@: |
; or byte [esi+71403h], 80h ; VGACNTRL: VGA Display Disable |
and byte [esi+70080h], not 27h ; CURACNTR: disable cursor A |
mov dword [esi+70084h], eax ; CURABASE: force write to CURA* regs |
and byte [esi+700C0h], not 27h ; CURBCNTR: disable cursor B |
mov dword [esi+700C4h], eax ; CURBBASE: force write to CURB* regs |
and byte [esi+70183h], not 80h ; DSPACNTR: disable Primary A Plane |
mov dword [esi+edx+70184h], eax ; DSPALINOFF/DSPASURF: force write to DSPA* regs |
and byte [esi+71183h], not 80h ; DSPBCNTR: disable Primary B Plane |
mov dword [esi+edx+71184h], eax ; DSPBLINOFF/DSPBSURF: force write to DSPB* regs |
if 1 |
cmp [deviceType], ironlake_start |
jae .disable_pipes |
mov edx, 10000h |
or byte [esi+70024h], 2 ; PIPEASTAT: clear VBLANK status |
or byte [esi+71024h], 2 ; PIPEBSTAT: clear VBLANK status |
.wait_vblank_preironlake1: |
mov ecx, 1000h |
loop $ |
test byte [esi+7000Bh], 80h ; PIPEACONF: pipe A active? |
jz @f |
test byte [esi+70024h], 2 ; PIPEASTAT: got VBLANK? |
jz .wait_vblank_preironlake2 |
@@: |
test byte [esi+7100Bh], 80h ; PIPEBCONF: pipe B active? |
jz .disable_pipes |
test byte [esi+71024h], 2 ; PIPEBSTAT: got VBLANK? |
jnz .disable_pipes |
.wait_vblank_preironlake2: |
dec edx |
jnz .wait_vblank_preironlake1 |
jmp .not_disabled |
.disable_pipes: |
end if |
and byte [esi+7000Bh], not 80h ; PIPEACONF: disable pipe |
and byte [esi+7100Bh], not 80h ; PIPEBCONF: disable pipe |
cmp [deviceType], gen4_start |
jb .wait_watching_scanline |
; g45 and later: use special flag from PIPE*CONF |
mov edx, 10000h |
@@: |
mov ecx, 1000h |
loop $ |
test byte [esi+7000Bh], 40h ; PIPEACONF: wait until pipe disabled |
jz @f |
dec edx |
jnz @b |
jmp .not_disabled |
@@: |
test byte [esi+7100Bh], 40h ; PIPEBCONF: wait until pipe disabled |
jz .disabled |
mov ecx, 1000h |
loop $ |
dec edx |
jnz @b |
jmp .not_disabled |
; pineview and before: wait while scanline still changes |
.wait_watching_scanline: |
mov edx, 1000h |
.dis1: |
push dword [esi+71000h] |
push dword [esi+70000h] |
mov ecx, 10000h |
loop $ |
pop eax |
xor eax, [esi+70000h] |
and eax, 1FFFh |
pop eax |
jnz .notdis1 |
xor eax, [esi+71000h] |
and eax, 1FFFh |
jz .disabled |
.notdis1: |
dec edx |
jnz .dis1 |
.not_disabled: |
sti |
jmp .return |
.disabled: |
lea eax, [esi+61183h] |
cmp [deviceType], ironlake_start |
jb @f |
add eax, 0xE0000 - 0x60000 |
@@: |
lea edx, [esi+60000h] |
test byte [eax], 40h |
jz @f |
add edx, 1000h |
@@: |
mov eax, [width] |
dec eax |
shl eax, 16 |
mov ax, word [height] |
dec eax |
mov dword [edx+1Ch], eax ; PIPEASRC: set source image size |
ror eax, 16 |
mov dword [edx+10190h], eax ; for old cards |
mov ecx, [width] |
add ecx, 15 |
and ecx, not 15 |
shl ecx, 2 |
mov dword [edx+10188h], ecx ; DSPASTRIDE: set scanline length |
mov dword [edx+10184h], 0 ; DSPALINOFF: force write to DSPA* registers |
and byte [esi+61233h], not 80h ; PFIT_CONTROL: disable panel fitting |
or byte [edx+1000Bh], 80h ; PIPEACONF: enable pipe |
; and byte [edx+1000Ah], not 0Ch ; PIPEACONF: enable Display+Cursor Planes |
or byte [edx+10183h], 80h ; DSPACNTR: enable Display Plane A |
sti |
; 2. Notify the kernel that resolution has changed. |
call GetDisplay |
mov edx, [width] |
mov dword [eax+8], edx |
mov edx, [height] |
mov dword [eax+0Ch], edx |
mov [eax+18h], ecx |
mov eax, [width] |
dec eax |
dec edx |
call SetScreen |
.return: |
ret |
align 4 |
hellomsg db 'Intel videocard detected, PciId=8086:' |
pciid_text db '0000' |
db ', which is ', 0 |
knownmsg db 'known',13,10,0 |
unknownmsg db 'unknown',13,10,0 |
if DEBUG |
edidmsg db 'EDID successfully read:',13,10 |
edid_text rb 8*(16*3+1) |
db 0 |
end if |
version: |
dd 0x50005 |
width dd predefined_width |
height dd predefined_height |
pciids: |
dw 0x3577 ; i830m |
dw 0x2562 ; 845g |
dw 0x3582 ; i855gm |
i865_start = ($ - pciids) / 2 |
dw 0x2572 ; i865g |
i9xx_start = ($ - pciids) / 2 |
dw 0x2582 ; i915g |
dw 0x258a ; e7221g (i915g) |
dw 0x2592 ; i915gm |
dw 0x2772 ; i945g |
dw 0x27a2 ; i945gm |
dw 0x27ae ; i945gme |
i965_start = ($ - pciids) / 2 |
dw 0x2972 ; i946qz (i965g) |
dw 0x2982 ; g35g (i965g) |
dw 0x2992 ; i965q (i965g) |
dw 0x29a2 ; i965g |
dw 0x29b2 ; q35g |
dw 0x29c2 ; g33g |
dw 0x29d2 ; q33g |
dw 0xa001 ; pineview |
dw 0xa011 ; pineview |
gen4_start = ($ - pciids) / 2 |
dw 0x2a02 ; i965gm |
dw 0x2a12 ; i965gm |
dw 0x2a42 ; gm45 |
dw 0x2e02 ; g45 |
dw 0x2e12 ; g45 |
dw 0x2e22 ; g45 |
dw 0x2e32 ; g45 |
dw 0x2e42 ; g45 |
dw 0x2e92 ; g45 |
ironlake_start = ($ - pciids) / 2 |
dw 0x0042 ; ironlake_d |
dw 0x0046 ; ironlake_m |
dw 0x0102 ; sandybridge_d |
dw 0x0112 ; sandybridge_d |
dw 0x0122 ; sandybridge_d |
dw 0x0106 ; sandybridge_m |
dw 0x0116 ; sandybridge_m |
dw 0x0126 ; sandybridge_m |
dw 0x010A ; sandybridge_d |
pciids_num = ($ - pciids) / 2 |
align 4 |
deviceType dd ? |
edid rb 0x80 |
/kernel/branches/Kolibri-acpi/drivers/com_mouse.asm |
---|
0,0 → 1,382 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; Includes source code by Kulakov Vladimir Gennadievich. ;; |
;; Modified by Mario79 and Rus. ;; |
;; 02.12.2009 <Lrz> ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;driver sceletone |
format MS COFF |
DEBUG equ 0 |
include 'proc32.inc' |
include 'imports.inc' |
API_VERSION equ 5 ;debug |
struc IOCTL |
{ .handle dd ? |
.io_code dd ? |
.input dd ? |
.inp_size dd ? |
.output dd ? |
.out_size dd ? |
} |
virtual at 0 |
IOCTL IOCTL |
end virtual |
public START |
public version |
DRV_ENTRY equ 1 |
DRV_EXIT equ -1 |
STRIDE equ 4 ;size of row in devices table |
SRV_GETVERSION equ 0 |
section '.flat' code readable align 16 |
proc START stdcall, state:dword |
cmp [state], 1 |
jne .exit |
.entry: |
;Detect_COM_Mouse: |
if DEBUG |
mov esi, msgInit |
call Boot_Log |
end if |
mov bx, 0x3f8 |
call MSMouseSearch |
cmp AL, 'M' |
jne @f |
;mov [com1_mouse_detected],1 |
;mov [irq_owner+4*4], 1 ; IRQ4 owner is System |
mov dx, bx |
inc dx ; 0x3f8 + 1 |
mov al, 1 |
out dx, al |
stdcall AttachIntHandler, 4, irq4_handler, dword 0 |
if DEBUG |
test eax, eax |
jne .label1 |
mov esi, msg_error_attach_int_handler |
call Boot_Log |
end if |
.label1: |
; mov eax, 0 |
; mov ebx, 0x3F8 |
; mov ecx, 0x3FF |
xor ebx, ebx |
mov ecx, 0x3F8 |
mov edx, 0x3FF |
call ReservePortArea |
if DEBUG |
cmp eax, 1 |
jne .go |
mov esi, msg_error_reserve_ports |
call Boot_Log |
.go: |
mov esi, boot_setmouse_type |
call Boot_Log |
end if |
@@: |
mov bx, 0x2f8 |
call MSMouseSearch |
cmp AL, 'M' |
jne .resume |
;mov [com2_mouse_detected],1 |
;mov [irq_owner+3*4], 1 ; IRQ3 owner is System |
stdcall AttachIntHandler, 3, irq3_handler, dword 0 |
; mov eax, 0 |
; mov ebx, 0x2F8 |
; mov ecx, 0x3F8 |
xor ebx, ebx |
mov ecx, 0x2F8 |
mov edx, 0x3F8 |
call ReservePortArea |
if DEBUG |
cmp eax, 1 |
jne @f |
mov esi, msg_error_reserve_ports |
call Boot_Log |
@@: |
mov esi, boot_setmouse_type + 22 |
call Boot_Log |
end if |
.resume: |
stdcall RegService, my_service, service_proc |
if DEBUG |
test eax, eax |
jne @f |
mov esi, msg_exit |
call Boot_Log |
end if |
@@: |
ret |
.fail: |
.exit: |
if DEBUG |
mov esi, msg_exit |
call Boot_Log |
end if |
xor eax, eax |
ret |
endp |
handle equ IOCTL.handle |
io_code equ IOCTL.io_code |
input equ IOCTL.input |
inp_size equ IOCTL.inp_size |
output equ IOCTL.output |
out_size equ IOCTL.out_size |
align 4 |
proc service_proc stdcall, ioctl:dword |
mov ebx, [ioctl] |
mov eax, [ebx+io_code] |
cmp eax, SRV_GETVERSION |
jne @F |
mov eax, [ebx+output] |
cmp [ebx+out_size], 4 |
jne .fail |
mov [eax], dword API_VERSION |
xor eax, eax |
ret |
@@: |
.fail: |
or eax, -1 |
ret |
endp |
align 4 |
MSMouseSearch: |
; ПОИСК МЫШИ ЧЕРЕЗ COM-ПОРТЫ |
MouseSearch: |
; Устанавливаем скорость |
; приема/передачи 1200 бод |
; in bx COM Port Base Address |
mov DX, bx |
add DX, 3 |
in AL, DX |
or AL, 80h ;установить бит DLAB |
out DX, AL |
mov DX, bx |
mov AL, 60h ;1200 бод |
out DX, AL |
inc DX |
mov AL, 0 |
out DX, AL |
; Установить длину слова 7 бит, 1 стоповый бит, |
; четность не контролировать |
mov DX, bx |
add DX, 3 |
mov AL, 00000010b |
out DX, AL |
; Запретить все прерывани |
mov dx, bx |
inc dx |
mov AL, 0 |
out DX, AL |
; Проверить, что устройство подключено и являетс |
; мышью типа MSMouse |
; Отключить питание мыши и прерывани |
mov DX, bx |
add EDX, 4 ;регистр управления модемом |
mov AL, 0 ;сбросить DTR, RTS и OUT2 |
out DX, AL |
; Ожидать 5 "тиков" (0,2 с) |
mov ecx, 0xFFFF |
loop $ |
; Включить питание мыши |
mov al, 1 |
out dx, al |
mov ecx, 0xFFFF |
loop $ |
; Очистить регистр данных |
mov dx, bx |
in AL, DX |
add edx, 4 |
mov AL, 1011b ;установить DTR и RTS и OUT2 |
out DX, AL |
mov ecx, 0x1FFFF |
; Цикл опроса порта |
WaitData: |
; Ожидать еще 10 "тиков" |
dec ecx |
; cmp ecx,0 |
jz NoMouse |
; Проверить наличие идентификационного байта |
mov DX, bx |
add DX, 5 |
in AL, DX |
test AL, 1 ;Данные готовы? |
jz WaitData |
; Ввести данные |
mov DX, bx |
in AL, DX |
NoMouse: |
ret |
align 4 |
irq3_handler: |
mov dx, 0x2f8 |
mov esi, com2_mouse |
jmp irq_handler |
align 4 |
irq4_handler: |
mov dx, 0x3f8 |
mov esi, com1_mouse |
irq_handler: |
; in: esi -> COM_MOUSE_DATA struc, dx = base port (xF8h) |
add edx, 5 ; xFDh |
in al, dx |
test al, 1 ; Данные готовы? |
jz .Error |
; Ввести данные |
sub edx, 5 |
in al, dx |
; Сбросить старший незначащий бит |
and al, 01111111b |
; Определить порядковый номер принимаемого байта |
cmp [esi+COM_MOUSE_DATA.MouseByteNumber], 2 |
ja .Error |
jz .ThirdByte |
jp .SecondByte |
; Сохранить первый байт данных |
.FirstByte: |
test al, 1000000b ; Первый байт посылки? |
jz .Error |
mov [esi+COM_MOUSE_DATA.FirstByte], al |
inc [esi+COM_MOUSE_DATA.MouseByteNumber] |
jmp .EndMouseInterrupt |
; Сохранить второй байт данных |
.SecondByte: |
test al, 1000000b |
jnz .Error |
mov [esi+COM_MOUSE_DATA.SecondByte], al |
inc [esi+COM_MOUSE_DATA.MouseByteNumber] |
jmp .EndMouseInterrupt |
; Сохранить третий байт данных |
.ThirdByte: |
test al, 1000000b |
jnz .Error |
mov [esi+COM_MOUSE_DATA.ThirdByte], al |
mov [esi+COM_MOUSE_DATA.MouseByteNumber], 0 |
; (Пакет данных от мыши принят полностью). |
; Записать новое значение состояния кнопок мыши |
mov al, [esi+COM_MOUSE_DATA.FirstByte] |
mov ah, al |
shr al, 3 |
and al, 2 |
shr ah, 5 |
and ah, 1 |
add al, ah |
movzx eax, al |
mov [BTN_DOWN], eax |
; Прибавить перемещение по X к координате X |
mov al, [esi+COM_MOUSE_DATA.FirstByte] |
shl al, 6 |
or al, [esi+COM_MOUSE_DATA.SecondByte] |
cbw |
movzx eax, ax |
mov [MOUSE_X], eax |
; Прибавить перемещение по Y к координате Y |
mov al, [esi+COM_MOUSE_DATA.FirstByte] |
and al, 00001100b |
shl al, 4 |
or al, [esi+COM_MOUSE_DATA.ThirdByte] |
cbw |
movzx eax, ax |
neg eax |
mov [MOUSE_Y], eax |
stdcall SetMouseData, [BTN_DOWN], [MOUSE_X], [MOUSE_Y], 0, 0 |
jmp .EndMouseInterrupt |
.Error: |
; Произошел сбой в порядке передачи информации от |
; мыши, обнулить счетчик байтов пакета данных |
mov [esi+COM_MOUSE_DATA.MouseByteNumber], 0 |
.EndMouseInterrupt: |
mov al, 1 |
ret |
;all initialized data place here |
align 4 |
struc COM_MOUSE_DATA { |
; Номер принимаемого от мыши байта |
.MouseByteNumber db ? |
; Трехбайтовая структура данных, передаваемая мышью |
.FirstByte db ? |
.SecondByte db ? |
.ThirdByte db ? |
;.timer_ticks_com dd ? |
} |
virtual at 0 |
COM_MOUSE_DATA COM_MOUSE_DATA |
end virtual |
com1_mouse COM_MOUSE_DATA |
com2_mouse COM_MOUSE_DATA |
MOUSE_X dd 0 |
MOUSE_Y dd 0 |
BTN_DOWN dd 0 |
COMPortBaseAddr dw 3F8h |
version dd (5 shl 16) or (API_VERSION and 0xFFFF) |
my_service db 'COM_Mouse',0 ;max 16 chars include zero |
if DEBUG |
msgInit db 'Preved bugoga!',13,10,0 |
boot_setmouse_type db 'Detected - COM1 mouse',13,10,0 |
db 'Detected - COM2 mouse',13,10,0 |
msg_error_reserve_ports db 'Error reserving ports!',13,10,0 |
msg_error_attach_int_handler db 'Error attach interrupt handler!',13,10,0 |
msg_exit db 'Exit!',13,10,0 |
end if |
section '.data' data readable writable align 16 |
;all uninitialized data place here |
/kernel/branches/Kolibri-acpi/drivers/emu10k1x.asm |
---|
0,0 → 1,1166 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
format MS COFF |
DEBUG equ 1 |
include 'proc32.inc' |
include 'imports.inc' |
API_VERSION equ 0x01000100 |
USE_COM_IRQ equ 0 ;make irq 3 and irq 4 available for PCI devices |
IRQ_REMAP equ 0 |
IRQ_LINE equ 0 |
;irq 0,1,2,8,12,13 недоступны |
; FEDCBA9876543210 |
VALID_IRQ equ 1100111011111000b |
ATTCH_IRQ equ 0000111010100000b |
if USE_COM_IRQ |
ATTCH_IRQ equ 0000111010111000b |
end if |
CPU_FREQ equ 2600d |
BIT0 EQU 0x00000001 |
BIT1 EQU 0x00000002 |
BIT5 EQU 0x00000020 |
BIT10 EQU 0x00000400 |
VID_Creative equ 0x1102 |
CTRL_CT0200 equ 0x0006 ; Dell OEM version (EMU10K1X) |
CODEC_MASTER_VOL_REG equ 0x02 |
CODEC_AUX_VOL equ 0x04 ; |
CODEC_PCM_OUT_REG equ 0x18 ; PCM output volume |
CODEC_EXT_AUDIO_REG equ 0x28 ; extended audio |
CODEC_EXT_AUDIO_CTRL_REG equ 0x2a ; extended audio control |
CODEC_PCM_FRONT_DACRATE_REG equ 0x2c ; PCM out sample rate |
CODEC_PCM_SURND_DACRATE_REG equ 0x2e ; surround sound sample rate |
CODEC_PCM_LFE_DACRATE_REG equ 0x30 ; LFE sample rate |
;EMU10K1(X) host controller registers set |
;; common offsets |
;; some definitions were borrowed from emu10k1 driver as they seem to be the same |
;;**********************************************************************************************;; |
;; PCI function 0 registers, address = <val> + PCIBASE0 ;; |
;;**********************************************************************************************;; |
PTR equ 0x00 ;; Indexed register set pointer register ;; |
;; NOTE: The CHANNELNUM and ADDRESS words can ;; |
;; be modified independently of each other. ;; |
DATA equ 0x04 ;; Indexed register set data register ;; |
IPR equ 0x08 ;; Global interrupt pending register ;; |
;; Clear pending interrupts by writing a 1 to ;; |
;; the relevant bits and zero to the other bits ;; |
IPR_MIDITRANSBUFEMPTY equ 0x00000001 ;; MIDI UART transmit buffer empty ;; |
IPR_MIDIRECVBUFEMPTY equ 0x00000002 ;; MIDI UART receive buffer empty ;; |
IPR_CH_0_LOOP equ 0x00000800 ;; Channel 0 loop ;; |
IPR_CH_0_HALF_LOOP equ 0x00000100 ;; Channel 0 half loop ;; |
IPR_CAP_0_LOOP equ 0x00080000 ;; Channel capture loop ;; |
IPR_CAP_0_HALF_LOOP equ 0x00010000 ;; Channel capture half loop ;; |
INTE equ 0x0c ;; Interrupt enable register ;; |
INTE_MIDITXENABLE equ 0x00000001 ;; Enable MIDI transmit-buffer-empty interrupts ;; |
INTE_MIDIRXENABLE equ 0x00000002 ;; Enable MIDI receive-buffer-empty interrupts ;; |
INTE_CH_0_LOOP equ 0x00000800 ;; Channel 0 loop ;; |
INTE_CH_0_HALF_LOOP equ 0x00000100 ;; Channel 0 half loop ;; |
INTE_CAP_0_LOOP equ 0x00080000 ;; Channel capture loop ;; |
INTE_CAP_0_HALF_LOOP equ 0x00010000 ;; Channel capture half loop ;; |
HCFG equ 0x14 ;; Hardware config register ;; |
HCFG_LOCKSOUNDCACHE equ 0x00000008 ;; 1 = Cancel bustmaster accesses to soundcache ;; |
;; NOTE: This should generally never be used. ;; |
HCFG_AUDIOENABLE equ 0x00000001 ;; 0 = CODECs transmit zero-valued samples ;; |
;; Should be set to 1 when the EMU10K1 is ;; |
;; completely initialized. ;; |
GPIO equ 0x18 ;; Defaults: 00001080-Analog, 00001000-SPDIF. ;; |
AC97DATA equ 0x1c ;; AC97 register set data register (16 bit) ;; |
AC97ADDRESS equ 0x1e ;; AC97 register set address register (8 bit) ;; |
;;******************************************************************************************************;; |
;; Emu10k1x pointer-offset register set, accessed through the PTR and DATA registers ;; |
;;******************************************************************************************************;; |
PLAYBACK_LIST_ADDR equ 0x00 ;; Base DMA address of a list of pointers to each period/size ;; |
;; One list entry: 4 bytes for DMA address, |
;; 4 bytes for period_size << 16. |
;; One list entry is 8 bytes long. |
;; One list entry for each period in the buffer. |
;; |
PLAYBACK_LIST_SIZE equ 0x01 ;; Size of list in bytes << 19. E.g. 8 periods -> 0x00380000 ;; |
PLAYBACK_LIST_PTR equ 0x02 ;; Pointer to the current period being played ;; |
PLAYBACK_DMA_ADDR equ 0x04 ;; Playback DMA addresss ;; |
PLAYBACK_PERIOD_SIZE equ 0x05 ;; Playback period size ;; |
PLAYBACK_POINTER equ 0x06 ;; Playback period pointer. Sample currently in DAC ;; |
PLAYBACK_UNKNOWN1 equ 0x07 |
PLAYBACK_UNKNOWN2 equ 0x08 |
;; Only one capture channel supported ;; |
CAPTURE_DMA_ADDR equ 0x10 ;; Capture DMA address ;; |
CAPTURE_BUFFER_SIZE equ 0x11 ;; Capture buffer size ;; |
CAPTURE_POINTER equ 0x12 ;; Capture buffer pointer. Sample currently in ADC ;; |
CAPTURE_UNKNOWN equ 0x13 |
;; From 0x20 - 0x3f, last samples played on each channel ;; |
TRIGGER_CHANNEL equ 0x40 ;; Trigger channel playback ;; |
TRIGGER_CHANNEL_0 equ 0x00000001 ;; Trigger channel 0 ;; |
TRIGGER_CHANNEL_1 equ 0x00000002 ;; Trigger channel 1 ;; |
TRIGGER_CHANNEL_2 equ 0x00000004 ;; Trigger channel 2 ;; |
TRIGGER_CAPTURE equ 0x00000100 ;; Trigger capture channel ;; |
ROUTING equ 0x41 ;; Setup sound routing ? ;; |
ROUTING_FRONT_LEFT equ 0x00000001 |
ROUTING_FRONT_RIGHT equ 0x00000002 |
ROUTING_REAR_LEFT equ 0x00000004 |
ROUTING_REAR_RIGHT equ 0x00000008 |
ROUTING_CENTER_LFE equ 0x00010000 |
SPCS0 equ 0x42 ;; SPDIF output Channel Status 0 register ;; |
SPCS1 equ 0x43 ;; SPDIF output Channel Status 1 register ;; |
SPCS2 equ 0x44 ;; SPDIF output Channel Status 2 register ;; |
SPCS_CLKACCYMASK equ 0x30000000 ;; Clock accuracy ;; |
SPCS_CLKACCY_1000PPM equ 0x00000000 ;; 1000 parts per million ;; |
SPCS_CLKACCY_50PPM equ 0x10000000 ;; 50 parts per million ;; |
SPCS_CLKACCY_VARIABLE equ 0x20000000 ;; Variable accuracy ;; |
SPCS_SAMPLERATEMASK equ 0x0f000000 ;; Sample rate ;; |
SPCS_SAMPLERATE_44 equ 0x00000000 ;; 44.1kHz sample rate ;; |
SPCS_SAMPLERATE_48 equ 0x02000000 ;; 48kHz sample rate ;; |
SPCS_SAMPLERATE_32 equ 0x03000000 ;; 32kHz sample rate ;; |
SPCS_CHANNELNUMMASK equ 0x00f00000 ;; Channel number ;; |
SPCS_CHANNELNUM_UNSPEC equ 0x00000000 ;; Unspecified channel number ;; |
SPCS_CHANNELNUM_LEFT equ 0x00100000 ;; Left channel ;; |
SPCS_CHANNELNUM_RIGHT equ 0x00200000 ;; Right channel ;; |
SPCS_SOURCENUMMASK equ 0x000f0000 ;; Source number ;; |
SPCS_SOURCENUM_UNSPEC equ 0x00000000 ;; Unspecified source number ;; |
SPCS_GENERATIONSTATUS equ 0x00008000 ;; Originality flag (see IEC-958 spec) ;; |
SPCS_CATEGORYCODEMASK equ 0x00007f00 ;; Category code (see IEC-958 spec) ;; |
SPCS_MODEMASK equ 0x000000c0 ;; Mode (see IEC-958 spec) ;; |
SPCS_EMPHASISMASK equ 0x00000038 ;; Emphasis ;; |
SPCS_EMPHASIS_NONE equ 0x00000000 ;; No emphasis ;; |
SPCS_EMPHASIS_50_15 equ 0x00000008 ;; 50/15 usec 2 channel ;; |
SPCS_COPYRIGHT equ 0x00000004 ;; Copyright asserted flag -- do not modify ;; |
SPCS_NOTAUDIODATA equ 0x00000002 ;; 0 = Digital audio, 1 = not audio ;; |
SPCS_PROFESSIONAL equ 0x00000001 ;; 0 = Consumer (IEC-958), 1 = pro (AES3-1992) ;; |
SPDIF_SELECT equ 0x45 ;; Enables SPDIF or Analogue outputs 0-Analogue, 0x700-SPDIF ;; |
;; This is the MPU port on the card ;; |
MUDATA equ 0x47 |
MUCMD equ 0x48 |
MUSTAT equ MUCMD |
;; From 0x50 - 0x5f, last samples captured ;; |
SRV_GETVERSION equ 0 |
DEV_PLAY equ 1 |
DEV_STOP equ 2 |
DEV_CALLBACK equ 3 |
DEV_SET_BUFF equ 4 |
DEV_NOTIFY equ 5 |
DEV_SET_MASTERVOL equ 6 |
DEV_GET_MASTERVOL equ 7 |
DEV_GET_INFO equ 8 |
struc AC_CNTRL ;AC controller base class |
{ .bus dd ? |
.devfn dd ? |
.vendor dd ? |
.dev_id dd ? |
.pci_cmd dd ? |
.pci_stat dd ? |
.codec_io_base dd ? |
.codec_mem_base dd ? |
.ctrl_io_base dd ? |
.ctrl_mem_base dd ? |
.cfg_reg dd ? |
.int_line dd ? |
.vendor_ids dd ? ;vendor id string |
.ctrl_ids dd ? ;hub id string |
.buffer dd ? |
.notify_pos dd ? |
.notify_task dd ? |
.lvi_reg dd ? |
.ctrl_setup dd ? |
.user_callback dd ? |
.codec_read16 dd ? |
.codec_write16 dd ? |
.ctrl_read8 dd ? |
.ctrl_read16 dd ? |
.ctrl_read32 dd ? |
.ctrl_write8 dd ? |
.ctrl_write16 dd ? |
.ctrl_write32 dd ? |
} |
struc CODEC ;Audio Chip base class |
{ |
.chip_id dd ? |
.flags dd ? |
.status dd ? |
.ac_vendor_ids dd ? ;ac vendor id string |
.chip_ids dd ? ;chip model string |
.shadow_flag dd ? |
dd ? |
.regs dw ? ; codec registers |
.reg_master_vol dw ? ;0x02 |
.reg_aux_out_vol dw ? ;0x04 |
.reg_mone_vol dw ? ;0x06 |
.reg_master_tone dw ? ;0x08 |
.reg_beep_vol dw ? ;0x0A |
.reg_phone_vol dw ? ;0x0C |
.reg_mic_vol dw ? ;0x0E |
.reg_line_in_vol dw ? ;0x10 |
.reg_cd_vol dw ? ;0x12 |
.reg_video_vol dw ? ;0x14 |
.reg_aux_in_vol dw ? ;0x16 |
.reg_pcm_out_vol dw ? ;0x18 |
.reg_rec_select dw ? ;0x1A |
.reg_rec_gain dw ? ;0x1C |
.reg_rec_gain_mic dw ? ;0x1E |
.reg_gen dw ? ;0x20 |
.reg_3d_ctrl dw ? ;0X22 |
.reg_page dw ? ;0X24 |
.reg_powerdown dw ? ;0x26 |
.reg_ext_audio dw ? ;0x28 |
.reg_ext_st dw ? ;0x2a |
.reg_pcm_front_rate dw ? ;0x2c |
.reg_pcm_surr_rate dw ? ;0x2e |
.reg_lfe_rate dw ? ;0x30 |
.reg_pcm_in_rate dw ? ;0x32 |
dw ? ;0x34 |
.reg_cent_lfe_vol dw ? ;0x36 |
.reg_surr_vol dw ? ;0x38 |
.reg_spdif_ctrl dw ? ;0x3A |
dw ? ;0x3C |
dw ? ;0x3E |
dw ? ;0x40 |
dw ? ;0x42 |
dw ? ;0x44 |
dw ? ;0x46 |
dw ? ;0x48 |
dw ? ;0x4A |
dw ? ;0x4C |
dw ? ;0x4E |
dw ? ;0x50 |
dw ? ;0x52 |
dw ? ;0x54 |
dw ? ;0x56 |
dw ? ;0x58 |
dw ? ;0x5A |
dw ? ;0x5C |
dw ? ;0x5E |
.reg_page_0 dw ? ;0x60 |
.reg_page_1 dw ? ;0x62 |
.reg_page_2 dw ? ;0x64 |
.reg_page_3 dw ? ;0x66 |
.reg_page_4 dw ? ;0x68 |
.reg_page_5 dw ? ;0x6A |
.reg_page_6 dw ? ;0x6C |
.reg_page_7 dw ? ;0x6E |
dw ? ;0x70 |
dw ? ;0x72 |
dw ? ;0x74 |
dw ? ;0x76 |
dw ? ;0x78 |
dw ? ;0x7A |
.reg_vendor_id_1 dw ? ;0x7C |
.reg_vendor_id_2 dw ? ;0x7E |
.reset dd ? ;virual |
.set_master_vol dd ? |
} |
struc CTRL_INFO |
{ .pci_cmd dd ? |
.irq dd ? |
.glob_cntrl dd ? |
.glob_sta dd ? |
.codec_io_base dd ? |
.ctrl_io_base dd ? |
.codec_mem_base dd ? |
.ctrl_mem_base dd ? |
.codec_id dd ? |
} |
struc IOCTL |
{ .handle dd ? |
.io_code dd ? |
.input dd ? |
.inp_size dd ? |
.output dd ? |
.out_size dd ? |
} |
virtual at 0 |
IOCTL IOCTL |
end virtual |
EVENT_NOTIFY equ 0x00000200 |
public START |
public service_proc |
public version |
section '.flat' code readable align 16 |
proc START stdcall, state:dword |
cmp [state], 1 |
jne .stop |
if DEBUG |
mov esi, msgInit |
call SysMsgBoardStr |
end if |
call detect_controller |
test eax, eax |
jz .fail |
if DEBUG |
mov esi, [ctrl.vendor_ids] |
call SysMsgBoardStr |
mov esi, [ctrl.ctrl_ids] |
call SysMsgBoardStr |
end if |
call init_controller |
test eax, eax |
jz .fail |
call init_codec |
test eax, eax |
jz .fail |
call setup_codec |
mov esi, msgPrimBuff |
call SysMsgBoardStr |
call create_primary_buff |
mov esi, msgDone |
call SysMsgBoardStr |
if IRQ_REMAP |
pushf |
cli |
mov ebx, [ctrl.int_line] |
in al, 0xA1 |
mov ah, al |
in al, 0x21 |
test ebx, ebx |
jz .skip |
bts ax, bx ;mask old line |
.skip: |
bts ax, IRQ_LINE ;mask new ine |
out 0x21, al |
mov al, ah |
out 0xA1, al |
stdcall PciWrite8, 0, 0xF8, 0x61, IRQ_LINE ;remap IRQ |
mov dx, 0x4d0 ;8259 ELCR1 |
in al, dx |
bts ax, IRQ_LINE |
out dx, al ;set level-triggered mode |
mov [ctrl.int_line], IRQ_LINE |
popf |
mov esi, msgRemap |
call SysMsgBoardStr |
end if |
mov eax, VALID_IRQ |
mov ebx, [ctrl.int_line] |
mov esi, msgInvIRQ |
bt eax, ebx |
jnc .fail_msg |
mov eax, ATTCH_IRQ |
mov esi, msgAttchIRQ |
bt eax, ebx |
jnc .fail_msg |
stdcall AttachIntHandler, ebx, ac97_irq, dword 0 |
stdcall create |
.reg: |
stdcall RegService, sz_sound_srv, service_proc |
ret |
.fail: |
if DEBUG |
mov esi, msgFail |
call SysMsgBoardStr |
end if |
xor eax, eax |
ret |
.fail_msg: |
call SysMsgBoardStr |
xor eax, eax |
ret |
.stop: |
call stop |
xor eax, eax |
ret |
endp |
handle equ IOCTL.handle |
io_code equ IOCTL.io_code |
input equ IOCTL.input |
inp_size equ IOCTL.inp_size |
output equ IOCTL.output |
out_size equ IOCTL.out_size |
align 4 |
proc service_proc stdcall, ioctl:dword |
mov edi, [ioctl] |
mov eax, [edi+io_code] |
cmp eax, SRV_GETVERSION |
jne @F |
mov eax, [edi+output] |
cmp [edi+out_size], 4 |
jne .fail |
mov [eax], dword API_VERSION |
xor eax, eax |
ret |
@@: |
cmp eax, DEV_PLAY |
jne @F |
if DEBUG |
mov esi, msgPlay |
call SysMsgBoardStr |
end if |
call play |
ret |
@@: |
cmp eax, DEV_STOP |
jne @F |
if DEBUG |
mov esi, msgStop |
call SysMsgBoardStr |
end if |
call stop |
ret |
@@: |
cmp eax, DEV_CALLBACK |
jne @F |
mov ebx, [edi+input] |
stdcall set_callback, [ebx] |
ret |
@@: |
cmp eax, DEV_SET_MASTERVOL |
jne @F |
mov eax, [edi+input] |
mov eax, [eax] |
call set_master_vol ;eax= vol |
ret |
@@: |
cmp eax, DEV_GET_MASTERVOL |
jne @F |
mov ebx, [edi+output] |
stdcall get_master_vol, ebx |
ret |
@@: |
cmp eax, DEV_GET_INFO |
jne @F |
mov ebx, [edi+output] |
stdcall get_dev_info, ebx |
ret |
@@: |
.fail: |
or eax, -1 |
ret |
endp |
restore handle |
restore io_code |
restore input |
restore inp_size |
restore output |
restore out_size |
align 4 |
proc ac97_irq |
locals |
status dd 0 |
endl |
; status = inl(chip->port + IPR); |
mov edx, IPR |
call [ctrl.ctrl_read32] |
test eax, eax |
jz @f |
mov dword [status], eax |
mov ebx, dword [buff_list] |
cmp [ctrl.user_callback], 0 |
je @f |
stdcall [ctrl.user_callback], ebx |
@@: |
mov eax, dword [status] ;; ack ;; |
mov edx, IPR |
call [ctrl.ctrl_write32] |
ret |
endp |
align 4 |
proc create_primary_buff |
stdcall KernelAlloc, 0x10000 |
mov [ctrl.buffer], eax |
mov edi, eax |
mov ecx, 0x10000/4 |
xor eax, eax |
cld |
rep stosd |
mov eax, [ctrl.buffer] |
call GetPgAddr |
mov edi, pcmout_bdl |
stosd |
mov eax, 0x4000000 |
stosd |
mov edi, buff_list |
mov eax, [ctrl.buffer] |
stosd ;1.] |
mov eax, [ctrl.buffer] |
call GetPgAddr |
stdcall ptr_write, PLAYBACK_POINTER, 0, 0 |
stdcall ptr_write, PLAYBACK_UNKNOWN1, 0, 0 |
stdcall ptr_write, PLAYBACK_UNKNOWN2, 0, 0 |
stdcall ptr_write, PLAYBACK_DMA_ADDR, 0, eax |
mov eax, pcmout_bdl |
mov ebx, eax |
call GetPgAddr |
and ebx, 0xFFF |
add eax, ebx |
stdcall ptr_write, PLAYBACK_LIST_ADDR, 0, eax |
stdcall ptr_write, PLAYBACK_LIST_SIZE, 0, 0 |
stdcall ptr_write, PLAYBACK_LIST_PTR, 0, 0 |
;mov eax, 0x00004000 |
;shl eax, 16 |
stdcall ptr_write, PLAYBACK_PERIOD_SIZE, 0, 0x40000000 ;eax |
ret |
endp |
align 4 |
proc detect_controller |
locals |
last_bus dd ? |
bus dd ? |
devfn dd ? |
endl |
xor eax, eax |
mov [bus], eax |
inc eax |
call PciApi |
cmp eax, -1 |
je .err |
mov [last_bus], eax |
.next_bus: |
and [devfn], 0 |
.next_dev: |
stdcall PciRead32, [bus], [devfn], dword 0 |
test eax, eax |
jz .next |
cmp eax, -1 |
je .next |
mov edi, devices |
@@: |
mov ebx, [edi] |
test ebx, ebx |
jz .next |
cmp eax, ebx |
je .found |
add edi, 12 |
jmp @B |
.next: |
inc [devfn] |
cmp [devfn], 256 |
jb .next_dev |
mov eax, [bus] |
inc eax |
mov [bus], eax |
cmp eax, [last_bus] |
jna .next_bus |
xor eax, eax |
ret |
.found: |
mov ebx, [bus] |
mov [ctrl.bus], ebx |
mov ecx, [devfn] |
mov [ctrl.devfn], ecx |
mov edx, eax |
and edx, 0xFFFF |
mov [ctrl.vendor], edx |
shr eax, 16 |
mov [ctrl.dev_id], eax |
mov ebx, [edi+4] |
mov [ctrl.ctrl_ids], ebx |
mov esi, [edi+8] |
mov [ctrl.ctrl_setup], esi |
cmp edx, VID_Creative |
jne @F |
mov [ctrl.vendor_ids], msg_Creative |
ret |
@@: |
.err: |
xor eax, eax |
mov [ctrl.vendor_ids], eax ;something wrong ? |
ret |
endp |
align 4 |
proc init_controller |
stdcall PciRead32, [ctrl.bus], [ctrl.devfn], dword 0x2C |
mov esi, msgPciSubsys |
call SysMsgBoardStr |
call dword2str |
call SysMsgBoardStr |
stdcall PciRead32, [ctrl.bus], [ctrl.devfn], dword 4 |
mov ebx, eax |
and eax, 0xFFFF |
mov [ctrl.pci_cmd], eax |
shr ebx, 16 |
mov [ctrl.pci_stat], ebx |
mov esi, msgPciCmd |
call SysMsgBoardStr |
call dword2str |
call SysMsgBoardStr |
mov esi, msgPciStat |
call SysMsgBoardStr |
mov eax, [ctrl.pci_stat] |
call dword2str |
call SysMsgBoardStr |
mov esi, msgCtrlIsaIo |
call SysMsgBoardStr |
stdcall PciRead32, [ctrl.bus], [ctrl.devfn], dword 0x10 |
call dword2str |
call SysMsgBoardStr |
and eax, 0xFFC0 |
mov [ctrl.ctrl_io_base], eax |
.default: |
stdcall PciRead32, [ctrl.bus], [ctrl.devfn], dword 0x3C |
and eax, 0xFF |
@@: |
mov [ctrl.int_line], eax |
call [ctrl.ctrl_setup] |
xor eax, eax |
inc eax |
ret |
endp |
align 4 |
proc set_Creative |
mov [ctrl.codec_read16], codec_io_r16 ;virtual |
mov [ctrl.codec_write16], codec_io_w16 ;virtual |
mov [ctrl.ctrl_read8 ], ctrl_io_r8 ;virtual |
mov [ctrl.ctrl_read16], ctrl_io_r16 ;virtual |
mov [ctrl.ctrl_read32], ctrl_io_r32 ;virtual |
mov [ctrl.ctrl_write8 ], ctrl_io_w8 ;virtual |
mov [ctrl.ctrl_write16], ctrl_io_w16 ;virtual |
mov [ctrl.ctrl_write32], ctrl_io_w32 ;virtual |
ret |
endp |
align 4 |
proc init_codec |
call reset_codec |
test eax, eax |
jz .err |
call detect_codec |
xor eax, eax |
inc eax |
ret |
.err: |
xor eax, eax |
ret |
endp |
align 4 |
proc reset_codec |
locals |
counter dd ? |
endl |
if DEBUG |
mov esi, msgCold |
call SysMsgBoardStr |
end if |
mov eax, 100000 ; wait 100 ms ;400000 ; wait 400 ms |
call StallExec |
stdcall ptr_read, TRIGGER_CHANNEL, 0 |
mov [counter], 16 ; total 20*100 ms = 2s |
.wait: |
stdcall codec_read, dword 0x26 |
test eax, 1 |
jnz .ok |
mov eax, 100000 ; wait 100 ms |
call StallExec |
dec [counter] |
jnz .wait |
if DEBUG |
mov esi, msgCRFail |
call SysMsgBoardStr |
end if |
.fail: |
stc |
ret |
.ok: |
xor eax, eax |
inc eax |
ret |
endp |
align 4 |
play: |
mov eax, INTE_CH_0_LOOP |
stdcall intr_enable, eax |
stdcall ptr_read, TRIGGER_CHANNEL, 0 |
mov ebx, TRIGGER_CHANNEL_0 |
or eax, ebx |
stdcall ptr_write, TRIGGER_CHANNEL, 0, eax |
xor eax, eax |
ret |
align 4 |
stop: |
mov eax, INTE_CH_0_LOOP or INTE_CH_0_HALF_LOOP |
stdcall intr_disable, eax |
stdcall ptr_read, TRIGGER_CHANNEL, 0 |
mov ebx, TRIGGER_CHANNEL_0 |
xor ebx, -1 |
or eax, ebx |
stdcall ptr_write, TRIGGER_CHANNEL, 0, eax |
xor eax, eax |
ret |
align 4 |
proc get_dev_info stdcall, p_info:dword |
virtual at esi |
CTRL_INFO CTRL_INFO |
end virtual |
mov esi, [p_info] |
mov eax, [ctrl.int_line] |
mov ecx, [ctrl.ctrl_io_base] |
mov [CTRL_INFO.irq], eax |
mov [CTRL_INFO.ctrl_io_base], ecx |
mov eax, [codec.chip_id] |
mov [CTRL_INFO.codec_id], eax |
mov ebx, [ctrl.pci_cmd] |
mov [CTRL_INFO.pci_cmd], ebx |
xor eax, eax |
mov [CTRL_INFO.codec_io_base], eax |
mov [CTRL_INFO.codec_mem_base], eax |
mov [CTRL_INFO.ctrl_mem_base], eax |
mov [CTRL_INFO.glob_cntrl], eax |
mov [CTRL_INFO.glob_sta], eax |
ret |
endp |
align 4 |
proc set_callback stdcall, handler:dword |
mov eax, [handler] |
mov [ctrl.user_callback], eax |
ret |
endp |
align 4 |
proc create stdcall |
stdcall PciRead16, [ctrl.bus], [ctrl.devfn], dword 4 |
test eax, 4 ; test master bit |
jnz @f |
or eax, 4 |
stdcall PciWrite16, [ctrl.bus], [ctrl.devfn], dword 4, eax ; set master bit |
@@: |
xor eax, eax |
mov edx, INTE |
call [ctrl.ctrl_write32] |
stdcall ptr_write, SPCS0, 0, \ |
SPCS_CLKACCY_1000PPM or SPCS_SAMPLERATE_48 or \ |
SPCS_CHANNELNUM_LEFT or SPCS_SOURCENUM_UNSPEC or \ |
SPCS_GENERATIONSTATUS or 0x00001200 or \ |
0x00000000 or SPCS_EMPHASIS_NONE or SPCS_COPYRIGHT |
stdcall ptr_write, SPCS1, 0, \ |
SPCS_CLKACCY_1000PPM or SPCS_SAMPLERATE_48 or \ |
SPCS_CHANNELNUM_LEFT or SPCS_SOURCENUM_UNSPEC or \ |
SPCS_GENERATIONSTATUS or 0x00001200 or \ |
0x00000000 or SPCS_EMPHASIS_NONE or SPCS_COPYRIGHT |
stdcall ptr_write, SPCS2, 0, \ |
SPCS_CLKACCY_1000PPM or SPCS_SAMPLERATE_48 or \ |
SPCS_CHANNELNUM_LEFT or SPCS_SOURCENUM_UNSPEC or \ |
SPCS_GENERATIONSTATUS or 0x00001200 or \ |
0x00000000 or SPCS_EMPHASIS_NONE or SPCS_COPYRIGHT |
stdcall ptr_write, SPDIF_SELECT, 0, 0x700 ; disable SPDIF |
stdcall ptr_write, ROUTING, 0, 0x1003F ; routing |
stdcall gpio_write, 0x1080 ; analog mode |
mov eax, dword HCFG_LOCKSOUNDCACHE or HCFG_AUDIOENABLE |
mov edx, HCFG |
call [ctrl.ctrl_write32] |
ret |
endp |
align 4 |
proc codec_read stdcall, reg:dword |
stdcall ac97_read, dword [reg] |
ret |
endp |
align 4 |
proc codec_write stdcall, reg:dword |
stdcall ac97_write, dword [reg], eax |
ret |
endp |
align 4 |
proc ac97_read stdcall, reg:dword |
push edx |
mov eax, dword [reg] |
mov edx, AC97ADDRESS |
call [ctrl.ctrl_write8] |
mov edx, AC97DATA |
call [ctrl.ctrl_read16] |
and eax, 0xFFFF |
pop edx |
ret |
endp |
align 4 |
proc ac97_write stdcall, reg:dword, val:dword |
push eax edx |
mov eax, dword [reg] |
mov edx, AC97ADDRESS |
call [ctrl.ctrl_write8] |
mov eax, dword [val] |
mov edx, AC97DATA |
call [ctrl.ctrl_write16] |
pop edx eax |
ret |
endp |
align 4 |
proc ptr_read stdcall, reg:dword, chn:dword |
push edx |
mov eax, dword [reg] |
shl eax, 16 |
or eax, dword [chn] |
mov edx, PTR |
call [ctrl.ctrl_write32] |
mov edx, DATA |
call [ctrl.ctrl_read32] |
pop edx |
ret |
endp |
align 4 |
proc ptr_write stdcall, reg:dword, chn:dword, data:dword |
push eax edx |
mov eax, dword [reg] |
shl eax, 16 |
or eax, dword [chn] |
mov edx, PTR |
call [ctrl.ctrl_write32] |
mov eax, dword [data] |
mov edx, DATA |
call [ctrl.ctrl_write32] |
pop edx eax |
ret |
endp |
align 4 |
proc intr_enable stdcall, intrenb:dword |
push edx |
mov edx, INTE |
call [ctrl.ctrl_read32] |
or eax, dword [intrenb] |
mov edx, INTE |
call [ctrl.ctrl_write32] |
pop edx |
ret |
endp |
align 4 |
proc intr_disable stdcall, intrenb:dword |
push eax ebx edx |
mov edx, INTE |
call [ctrl.ctrl_read32] |
mov ebx, dword [intrenb] |
xor ebx, -1 |
and eax, ebx |
mov edx, INTE |
call [ctrl.ctrl_write32] |
pop edx ebx eax |
ret |
endp |
align 4 |
proc gpio_write stdcall, value:dword |
push eax edx |
mov eax, dword [value] |
mov edx, GPIO |
call [ctrl.ctrl_write32] |
pop edx eax |
ret |
endp |
align 4 |
proc StallExec |
push ecx |
push edx |
push ebx |
push eax |
mov ecx, CPU_FREQ |
mul ecx |
mov ebx, eax ;low |
mov ecx, edx ;high |
rdtsc |
add ebx, eax |
adc ecx, edx |
@@: |
rdtsc |
sub eax, ebx |
sbb edx, ecx |
js @B |
pop eax |
pop ebx |
pop edx |
pop ecx |
ret |
endp |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
; CONTROLLER IO functions |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
proc codec_io_r16 ;Not used. |
;mov edx, [ctrl.ctrl_io_base] |
;in eax, dx |
ret |
endp |
align 4 |
proc codec_io_w16 ;Not used. |
;mov edx, [ctrl.ctrl_io_base] |
;out dx, eax |
ret |
endp |
align 4 |
proc ctrl_io_r8 |
add edx, [ctrl.ctrl_io_base] |
in al, dx |
ret |
endp |
align 4 |
proc ctrl_io_r16 |
add edx, [ctrl.ctrl_io_base] |
in ax, dx |
ret |
endp |
align 4 |
proc ctrl_io_r32 |
add edx, [ctrl.ctrl_io_base] |
in eax, dx |
ret |
endp |
align 4 |
proc ctrl_io_w8 |
add edx, [ctrl.ctrl_io_base] |
out dx, al |
ret |
endp |
align 4 |
proc ctrl_io_w16 |
add edx, [ctrl.ctrl_io_base] |
out dx, ax |
ret |
endp |
align 4 |
proc ctrl_io_w32 |
add edx, [ctrl.ctrl_io_base] |
out dx, eax |
ret |
endp |
align 4 |
dword2str: |
push eax ebx ecx |
mov esi, hex_buff |
mov ecx, -8 |
@@: |
rol eax, 4 |
mov ebx, eax |
and ebx, 0x0F |
mov bl, [ebx+hexletters] |
mov [8+esi+ecx], bl |
inc ecx |
jnz @B |
pop ecx ebx eax |
ret |
hexletters db '0123456789ABCDEF' |
hex_buff db 8 dup(0),13,10,0 |
include "codec.inc" |
align 4 |
devices dd (CTRL_CT0200 shl 16)+VID_Creative,msg_CT_EMU10K1X,set_Creative |
dd 0 ;terminator |
version dd (5 shl 16) or (API_VERSION and 0xFFFF) |
msg_CT_EMU10K1X db 'SB Live! Dell OEM', 13,10, 0 |
msg_Creative db 'Creative ', 0 |
szKernel db 'KERNEL', 0 |
sz_sound_srv db 'SOUND',0 |
msgInit db 'detect hardware...',13,10,0 |
msgFail db 'device not found',13,10,0 |
msgAttchIRQ db 'IRQ line not supported', 13,10, 0 |
msgInvIRQ db 'IRQ line not assigned or invalid', 13,10, 0 |
msgPlay db 'start play', 13,10,0 |
msgStop db 'stop play', 13,10,0 |
msgIRQ db 'AC97 IRQ', 13,10,0 |
;msgInitCtrl db 'init controller',13,10,0 |
;msgInitCodec db 'init codec',13,10,0 |
msgPrimBuff db 'create primary buffer ...',0 |
msgDone db 'done',13,10,0 |
msgRemap db 'Remap IRQ',13,10,0 |
;msgReg db 'set service handler',13,10,0 |
;msgOk db 'service installed',13,10,0 |
msgCold db 'cold reset',13,10,0 |
;msgWarm db 'warm reset',13,10,0 |
;msgWRFail db 'warm reset failed',13,10,0 |
msgCRFail db 'cold reset failed',13,10,0 |
;msgCFail db 'codec not ready',13,10,0 |
;msgCInvalid db 'codec is not valid',13,10,0 ;Asper |
;msgResetOk db 'reset complete',13,10,0 |
;msgStatus db 'global status ',0 |
;msgControl db 'global control ',0 |
msgPciCmd db 'PCI command ',0 |
msgPciStat db 'PCI status ',0 |
msgPciSubsys db 'PCI subsystem ',0 |
msgCtrlIsaIo db 'controller io base ',0 |
;msgMixIsaIo db 'codec io base ',0 |
;msgCtrlMMIo db 'controller mmio base ',0 |
;msgMixMMIo db 'codec mmio base ',0 |
;msgIrqMap db 'AC97 irq map as ',0 |
section '.data' data readable writable align 16 |
pcmout_bdl rq 32 |
buff_list rd 32 |
codec CODEC |
ctrl AC_CNTRL |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |
/kernel/branches/Kolibri-acpi/drivers/ensoniq.asm |
---|
0,0 → 1,1177 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;alpha version |
format MS COFF |
DEBUG equ 1 |
include 'proc32.inc' |
include 'imports.inc' |
REMAP_IRQ equ 0 |
;irq 0,1,2,8,12,13 недоступны |
; FEDCBA9876543210 |
VALID_IRQ equ 1100111011111000b |
ATTCH_IRQ equ 0000111010101000b |
IRQ_LINE equ 0 |
CPU_FREQ equ 2600d |
BIT0 EQU 0x00000001 |
BIT1 EQU 0x00000002 |
BIT2 EQU 0x00000004 |
BIT3 EQU 0x00000008 |
BIT4 EQU 0x00000010 |
BIT5 EQU 0x00000020 |
BIT6 EQU 0x00000040 |
BIT7 EQU 0x00000080 |
BIT8 EQU 0x00000100 |
BIT9 EQU 0x00000200 |
BIT10 EQU 0x00000400 |
BIT11 EQU 0x00000800 |
BIT12 EQU 0x00001000 |
BIT13 EQU 0x00002000 |
BIT14 EQU 0x00004000 |
BIT15 EQU 0x00008000 |
BIT16 EQU 0x00010000 |
BIT17 EQU 0x00020000 |
BIT18 EQU 0x00040000 |
BIT19 EQU 0x00080000 |
BIT20 EQU 0x00100000 |
BIT21 EQU 0x00200000 |
BIT22 EQU 0x00400000 |
BIT23 EQU 0x00800000 |
BIT24 EQU 0x00100000 |
BIT25 EQU 0x02000000 |
BIT26 EQU 0x04000000 |
BIT27 EQU 0x08000000 |
BIT28 EQU 0x10000000 |
BIT29 EQU 0x20000000 |
BIT30 EQU 0x40000000 |
BIT31 EQU 0x80000000 |
PCM_OUT_BDL equ 0x10 ; PCM out buffer descriptors list |
PCM_OUT_CR_REG equ 0x1b ; PCM out Control Register |
PCM_OUT_LVI_REG equ 0x15 ; PCM last valid index |
PCM_OUT_SR_REG equ 0x16 ; PCM out Status register |
PCM_OUT_PIV_REG equ 0x1a |
PCM_OUT_CIV_REG equ 0x14 ; PCM out current index |
PCM_IN_CR_REG equ 0x0b ; PCM in Control Register |
MC_IN_CR_REG equ 0x2b ; MIC in Control Register |
RR equ BIT1 ; reset registers. Nukes all regs |
CODEC_MASTER_VOL_REG equ 0x02 |
CODEC_AUX_VOL equ 0x04 ; |
CODEC_PCM_OUT_REG equ 18h ; PCM output volume |
CODEC_EXT_AUDIO_REG equ 28h ; extended audio |
CODEC_EXT_AUDIO_CTRL_REG equ 2ah ; extended audio control |
CODEC_PCM_FRONT_DACRATE_REG equ 2ch ; PCM out sample rate |
CODEC_PCM_SURND_DACRATE_REG equ 2eh ; surround sound sample rate |
CODEC_PCM_LFE_DACRATE_REG equ 30h ; LFE sample rate |
GLOB_CTRL equ 0x2C ; Global Control |
CTRL_STAT equ 0x30 ; Global Status |
CTRL_CAS equ 0x34 ; Codec Access Semiphore |
CAS_FLAG equ 0x01 ; Codec Access Semiphore Bit |
CTRL_ST_CREADY equ BIT8+BIT9+BIT28 ; Primary Codec Ready |
CTRL_ST_RCS equ 0x00008000 ; Read Completion Status |
CTRL_CNT_CRIE equ BIT4+BIT5+BIT6 ; Codecs Resume Interrupt Enable |
CTRL_CNT_AC_OFF equ 0x00000008 ; ACLINK Off |
CTRL_CNT_WARM equ 0x00000004 ; AC97 Warm Reset |
CTRL_CNT_COLD equ 0x00000002 ; AC97 Cold Reset |
CTRL_CNT_GIE equ 0x00000001 ; GPI Interrupt Enable |
CODEC_REG_POWERDOWN equ 0x26 |
CODEC_REG_ST equ 0x26 |
DEV_PLAY equ 1 |
DEV_STOP equ 2 |
DEV_CALLBACK equ 3 |
DEV_SET_BUFF equ 4 |
DEV_NOTIFY equ 5 |
DEV_SET_MASTERVOL equ 6 |
DEV_GET_MASTERVOL equ 7 |
DEV_GET_INFO equ 8 |
struc AC_CNTRL ;AC controller base class |
{ .bus dd ? |
.devfn dd ? |
.vendor dd ? |
.dev_id dd ? |
.pci_cmd dd ? |
.pci_stat dd ? |
.codec_io_base dd ? |
.codec_mem_base dd ? |
.ctrl_io_base dd ? |
.ctrl_mem_base dd ? |
.cfg_reg dd ? |
.int_line dd ? |
.vendor_ids dd ? ;vendor id string |
.ctrl_ids dd ? ;hub id string |
.buffer dd ? |
.notify_pos dd ? |
.notify_task dd ? |
.lvi_reg dd ? |
.ctrl_setup dd ? |
.user_callback dd ? |
.codec_read16 dd ? |
.codec_write16 dd ? |
.ctrl_read8 dd ? |
.ctrl_read16 dd ? |
.ctrl_read32 dd ? |
.ctrl_write8 dd ? |
.ctrl_write16 dd ? |
.ctrl_write32 dd ? |
} |
struc CODEC ;Audio Chip base class |
{ |
.chip_id dd ? |
.flags dd ? |
.status dd ? |
.ac_vendor_ids dd ? ;ac vendor id string |
.chip_ids dd ? ;chip model string |
.shadow_flag dd ? |
dd ? |
.regs dw ? ; codec registers |
.reg_master_vol dw ? ;0x02 |
.reg_aux_out_vol dw ? ;0x04 |
.reg_mone_vol dw ? ;0x06 |
.reg_master_tone dw ? ;0x08 |
.reg_beep_vol dw ? ;0x0A |
.reg_phone_vol dw ? ;0x0C |
.reg_mic_vol dw ? ;0x0E |
.reg_line_in_vol dw ? ;0x10 |
.reg_cd_vol dw ? ;0x12 |
.reg_video_vol dw ? ;0x14 |
.reg_aux_in_vol dw ? ;0x16 |
.reg_pcm_out_vol dw ? ;0x18 |
.reg_rec_select dw ? ;0x1A |
.reg_rec_gain dw ? ;0x1C |
.reg_rec_gain_mic dw ? ;0x1E |
.reg_gen dw ? ;0x20 |
.reg_3d_ctrl dw ? ;0X22 |
.reg_page dw ? ;0X24 |
.reg_powerdown dw ? ;0x26 |
.reg_ext_audio dw ? ;0x28 |
.reg_ext_st dw ? ;0x2a |
.reg_pcm_front_rate dw ? ;0x2c |
.reg_pcm_surr_rate dw ? ;0x2e |
.reg_lfe_rate dw ? ;0x30 |
.reg_pcm_in_rate dw ? ;0x32 |
dw ? ;0x34 |
.reg_cent_lfe_vol dw ? ;0x36 |
.reg_surr_vol dw ? ;0x38 |
.reg_spdif_ctrl dw ? ;0x3A |
dw ? ;0x3C |
dw ? ;0x3E |
dw ? ;0x40 |
dw ? ;0x42 |
dw ? ;0x44 |
dw ? ;0x46 |
dw ? ;0x48 |
dw ? ;0x4A |
dw ? ;0x4C |
dw ? ;0x4E |
dw ? ;0x50 |
dw ? ;0x52 |
dw ? ;0x54 |
dw ? ;0x56 |
dw ? ;0x58 |
dw ? ;0x5A |
dw ? ;0x5C |
dw ? ;0x5E |
.reg_page_0 dw ? ;0x60 |
.reg_page_1 dw ? ;0x62 |
.reg_page_2 dw ? ;0x64 |
.reg_page_3 dw ? ;0x66 |
.reg_page_4 dw ? ;0x68 |
.reg_page_5 dw ? ;0x6A |
.reg_page_6 dw ? ;0x6C |
.reg_page_7 dw ? ;0x6E |
dw ? ;0x70 |
dw ? ;0x72 |
dw ? ;0x74 |
dw ? ;0x76 |
dw ? ;0x78 |
dw ? ;0x7A |
.reg_vendor_id_1 dw ? ;0x7C |
.reg_vendor_id_2 dw ? ;0x7E |
.reset dd ? ;virual |
.set_master_vol dd ? |
} |
struc CTRL_INFO |
{ .pci_cmd dd ? |
.irq dd ? |
.glob_cntrl dd ? |
.glob_sta dd ? |
.codec_io_base dd ? |
.ctrl_io_base dd ? |
.codec_mem_base dd ? |
.ctrl_mem_base dd ? |
.codec_id dd ? |
} |
struc IOCTL |
{ .handle dd ? |
.io_code dd ? |
.input dd ? |
.inp_size dd ? |
.output dd ? |
.out_size dd ? |
} |
virtual at 0 |
IOCTL IOCTL |
end virtual |
EVENT_NOTIFY equ 0x00000200 |
OS_BASE equ 0x80000000 |
SLOT_BASE equ OS_BASE+0x0080000 |
new_app_base equ 0 |
public START |
public service_proc |
public version |
section '.flat' code readable align 16 |
proc START stdcall, state:dword |
cmp [state], 1 |
jne .stop |
if DEBUG |
mov esi, msgDetect |
call SysMsgBoardStr |
end if |
call detect_controller |
test eax, eax |
jz .fail |
if DEBUG |
mov esi, [ctrl.vendor_ids] |
call SysMsgBoardStr |
mov esi, [ctrl.ctrl_ids] |
call SysMsgBoardStr |
end if |
call init_controller |
test eax, eax |
jz .fail |
jmp .fail ;force fail |
if DEBUG |
mov esi, msgInitCodec |
call SysMsgBoardStr |
end if |
call init_codec |
test eax, eax |
jz .fail |
if DEBUG |
mov esi, [codec.ac_vendor_ids] |
call SysMsgBoardStr |
mov esi, [codec.chip_ids] |
call SysMsgBoardStr |
end if |
call reset_controller |
call setup_codec |
mov esi, msgPrimBuff |
call SysMsgBoardStr |
call create_primary_buff |
mov eax, VALID_IRQ |
mov ebx, [ctrl.int_line] |
mov esi, msgInvIRQ |
bt eax, ebx |
jnc .fail |
mov eax, ATTCH_IRQ |
mov esi, msgAttchIRQ |
bt eax, ebx |
jnc .fail |
stdcall AttachIntHandler, ebx, ac97_irq, dword 0 |
stdcall RegService, sz_sound_srv, service_proc |
ret |
.fail: |
if DEBUG |
mov esi, msgFail |
call SysMsgBoardStr |
end if |
xor eax, eax |
ret |
.stop: |
call stop |
xor eax, eax |
ret |
endp |
handle equ IOCTL.handle |
io_code equ IOCTL.io_code |
input equ IOCTL.input |
inp_size equ IOCTL.inp_size |
output equ IOCTL.output |
out_size equ IOCTL.out_size |
align 4 |
proc service_proc stdcall, ioctl:dword |
mov edi, [ioctl] |
mov eax, [edi+io_code] |
cmp eax, DEV_PLAY |
jne @F |
if DEBUG |
mov esi, msgPlay |
call SysMsgBoardStr |
end if |
call play |
ret |
@@: |
cmp eax, DEV_STOP |
jne @F |
if DEBUG |
mov esi, msgStop |
call SysMsgBoardStr |
end if |
call stop |
ret |
@@: |
cmp eax, DEV_CALLBACK |
jne @F |
mov ebx, [edi+input] |
stdcall set_callback, [ebx] |
ret |
@@: |
cmp eax, DEV_SET_MASTERVOL |
jne @F |
mov eax, [edi+input] |
mov eax, [eax] |
call set_master_vol ;eax= vol |
ret |
@@: |
cmp eax, DEV_GET_MASTERVOL |
jne @F |
mov ebx, [edi+output] |
stdcall get_master_vol, ebx |
ret |
;@@: |
; cmp eax, DEV_GET_INFO |
; jne @F |
; mov ebx, [edi+output] |
; stdcall get_dev_info, ebx |
; ret |
@@: |
.fail: |
or eax, -1 |
ret |
endp |
restore handle |
restore io_code |
restore input |
restore inp_size |
restore output |
restore out_size |
align 4 |
proc ac97_irq |
; if DEBUG |
; mov esi, msgIRQ |
; call SysMsgBoardStr |
; end if |
cmp [ctrl.user_callback], 0 |
je @f |
stdcall [ctrl.user_callback], ebx |
@@: |
ret |
.skip: |
mov edx, PCM_OUT_CR_REG |
mov ax, 0x11 ;0x1D |
call [ctrl.ctrl_write8] |
ret |
endp |
align 4 |
proc create_primary_buff |
stdcall KernelAlloc, 0x10000 |
mov [ctrl.buffer], eax |
mov edi, eax |
mov ecx, 0x10000/4 |
xor eax, eax |
cld |
rep stosd |
mov eax, [ctrl.buffer] |
call GetPgAddr |
mov ebx, 0xC0002000 |
mov ecx, 4 |
mov edi, pcmout_bdl |
@@: |
mov [edi], eax |
mov [edi+4], ebx |
mov [edi+32], eax |
mov [edi+4+32], ebx |
mov [edi+64], eax |
mov [edi+4+64], ebx |
mov [edi+96], eax |
mov [edi+4+96], ebx |
mov [edi+128], eax |
mov [edi+4+128], ebx |
mov [edi+160], eax |
mov [edi+4+160], ebx |
mov [edi+192], eax |
mov [edi+4+192], ebx |
mov [edi+224], eax |
mov [edi+4+224], ebx |
add eax, 0x4000 |
add edi, 8 |
loop @B |
mov edi, buff_list |
mov eax, [ctrl.buffer] |
mov ecx, 4 |
@@: |
mov [edi], eax |
mov [edi+16], eax |
mov [edi+32], eax |
mov [edi+48], eax |
mov [edi+64], eax |
mov [edi+80], eax |
mov [edi+96], eax |
mov [edi+112], eax |
add eax, 0x4000 |
add edi, 4 |
loop @B |
mov eax, pcmout_bdl |
mov ebx, eax |
call GetPgAddr ;eax |
and ebx, 0xFFF |
add eax, ebx |
mov edx, PCM_OUT_BDL |
call [ctrl.ctrl_write32] |
mov eax, 16 |
mov [ctrl.lvi_reg], eax |
mov edx, PCM_OUT_LVI_REG |
call [ctrl.ctrl_write8] |
ret |
endp |
align 4 |
proc detect_controller |
locals |
last_bus dd ? |
bus dd ? |
devfn dd ? |
endl |
xor eax, eax |
mov [bus], eax |
inc eax |
call PciApi |
cmp eax, -1 |
je .err |
mov [last_bus], eax |
.next_bus: |
and [devfn], 0 |
.next_dev: |
stdcall PciRead32, [bus], [devfn], dword 0 |
test eax, eax |
jz .next |
cmp eax, -1 |
je .next |
mov edi, devices |
@@: |
mov ebx, [edi] |
test ebx, ebx |
jz .next |
cmp eax, ebx |
je .found |
add edi, 12 |
jmp @B |
.next: |
inc [devfn] |
cmp [devfn], 256 |
jb .next_dev |
mov eax, [bus] |
inc eax |
mov [bus], eax |
cmp eax, [last_bus] |
jna .next_bus |
xor eax, eax |
ret |
.found: |
mov ebx, [bus] |
mov [ctrl.bus], ebx |
mov ecx, [devfn] |
mov [ctrl.devfn], ecx |
mov edx, eax |
and edx, 0xFFFF |
mov [ctrl.vendor], edx |
shr eax, 16 |
mov [ctrl.dev_id], eax |
mov ebx, [edi+4] |
mov [ctrl.ctrl_ids], ebx |
mov esi, [edi+8] |
mov [ctrl.ctrl_setup], esi |
cmp ebx, 0x1274 |
jne @F |
mov [ctrl.vendor_ids], msgEnsoniq |
ret |
@@: |
mov [ctrl.vendor_ids], 0 ;something wrong ? |
ret |
.err: |
xor eax, eax |
ret |
endp |
align 4 |
proc init_controller |
mov esi, msgPCIcmd |
call SysMsgBoardStr |
stdcall PciRead32, [ctrl.bus], [ctrl.devfn], dword 4 |
mov ebx, eax |
and eax, 0xFFFF |
mov [ctrl.pci_cmd], eax |
shr ebx, 16 |
mov [ctrl.pci_stat], ebx |
call dword2str |
call SysMsgBoardStr |
mov esi, msgIObase |
call SysMsgBoardStr |
stdcall PciRead32, [ctrl.bus], [ctrl.devfn], dword 0x10 |
; and eax, -16 |
mov [ctrl.ctrl_io_base], eax |
call dword2str |
call SysMsgBoardStr |
mov esi, msgIRQline |
call SysMsgBoardStr |
stdcall PciRead32, [ctrl.bus], [ctrl.devfn], dword 0x3C |
and eax, 0xFF |
mov [ctrl.int_line], eax |
call dword2str |
call SysMsgBoardStr |
call [ctrl.ctrl_setup] |
xor eax, eax |
inc eax |
ret |
endp |
align 4 |
proc set_ICH |
mov [ctrl.codec_read16], codec_io_r16 ;virtual |
mov [ctrl.codec_write16], codec_io_w16 ;virtual |
mov [ctrl.ctrl_read8 ], ctrl_io_r8 ;virtual |
mov [ctrl.ctrl_read16], ctrl_io_r16 ;virtual |
mov [ctrl.ctrl_read32], ctrl_io_r32 ;virtual |
mov [ctrl.ctrl_write8 ], ctrl_io_w8 ;virtual |
mov [ctrl.ctrl_write16], ctrl_io_w16 ;virtual |
mov [ctrl.ctrl_write32], ctrl_io_w32 ;virtual |
ret |
endp |
align 4 |
proc reset_controller |
xor eax, eax |
mov edx, PCM_IN_CR_REG |
call [ctrl.ctrl_write8] |
mov edx, PCM_OUT_CR_REG |
call [ctrl.ctrl_write8] |
mov edx, MC_IN_CR_REG |
call [ctrl.ctrl_write8] |
mov eax, RR |
mov edx, PCM_IN_CR_REG |
call [ctrl.ctrl_write8] |
mov edx, PCM_OUT_CR_REG |
call [ctrl.ctrl_write8] |
mov edx, MC_IN_CR_REG |
call [ctrl.ctrl_write8] |
ret |
endp |
align 4 |
proc init_codec |
locals |
counter dd ? |
endl |
mov esi, msgControl |
call SysMsgBoardStr |
mov edx, GLOB_CTRL |
call [ctrl.ctrl_read32] |
call dword2str |
call SysMsgBoardStr |
mov esi, msgStatus |
call SysMsgBoardStr |
mov edx, CTRL_STAT |
call [ctrl.ctrl_read32] |
call dword2str |
call SysMsgBoardStr |
test eax, CTRL_ST_CREADY |
jnz .ready |
call reset_codec |
and eax, eax |
jz .err |
xor edx, edx ;ac_reg_0 |
call [ctrl.codec_write16] |
xor eax, eax |
mov edx, CODEC_REG_POWERDOWN |
call [ctrl.codec_write16] |
mov [counter], 200 ; total 200*5 ms = 1s |
.wait: |
mov edx, CODEC_REG_POWERDOWN |
call [ctrl.codec_read16] |
and eax, 0x0F |
cmp eax, 0x0F |
jz .ready |
mov eax, 5000 ; wait 5 ms |
call StallExec |
sub [counter] , 1 |
jnz .wait |
.err: |
xor eax, eax ; timeout error |
ret |
.ready: |
call detect_codec |
xor eax, eax |
inc eax |
ret |
endp |
align 4 |
proc reset_codec |
mov edx, GLOB_CTRL |
call [ctrl.ctrl_read32] |
test eax, 0x02 |
jz .cold |
call warm_reset |
jnc .ok |
.cold: |
call cold_reset |
jnc .ok |
if DEBUG |
mov esi, msgCFail |
call SysMsgBoardStr |
end if |
xor eax, eax ; timeout error |
ret |
.ok: |
if DEBUG |
mov esi, msgResetOk |
call SysMsgBoardStr |
end if |
xor eax, eax |
inc eax |
ret |
endp |
align 4 |
proc warm_reset |
locals |
counter dd ? |
endl |
mov eax, 0x06 |
mov edx, GLOB_CTRL |
call [ctrl.ctrl_write32] |
if DEBUG |
mov esi, msgWarm |
call SysMsgBoardStr |
end if |
mov [counter], 10 ; total 10*100 ms = 1s |
.wait: |
mov eax, 100000 ; wait 100 ms |
call StallExec |
mov edx, GLOB_CTRL |
call [ctrl.ctrl_read32] |
test eax, 4 |
jz .ok |
sub [counter], 1 |
jnz .wait |
if DEBUG |
mov esi, msgWRFail |
call SysMsgBoardStr |
end if |
stc |
ret |
.ok: |
mov edx, CTRL_STAT |
call [ctrl.ctrl_read32] |
and eax, CTRL_ST_CREADY |
jz .fail |
clc |
ret |
.fail: |
stc |
ret |
endp |
align 4 |
proc cold_reset |
locals |
counter dd ? |
endl |
xor eax, eax |
mov edx, GLOB_CTRL |
call [ctrl.ctrl_write32] |
if DEBUG |
mov esi, msgCold |
call SysMsgBoardStr |
end if |
mov eax, 1000000 ; wait 1 s |
call StallExec |
mov eax, 2 |
mov edx, GLOB_CTRL |
call [ctrl.ctrl_write32] |
mov [counter], 10 ; total 10*100 ms = 1s |
.wait: |
mov eax, 100000 ; wait 100 ms |
call StallExec |
mov edx, GLOB_CTRL |
call [ctrl.ctrl_read32] |
test eax, 4 |
jz .ok |
sub [counter], 1 |
jnz .wait |
if DEBUG |
mov esi, msgCRFail |
call SysMsgBoardStr |
end if |
stc |
ret |
.ok: |
mov edx, CTRL_STAT |
call [ctrl.ctrl_read32] |
and eax, CTRL_ST_CREADY |
jz .fail |
clc |
ret |
.fail: |
stc |
ret |
endp |
align 4 |
play: |
mov eax, 16 |
mov [ctrl.lvi_reg], eax |
mov edx, PCM_OUT_LVI_REG |
call [ctrl.ctrl_write8] |
mov edx, PCM_OUT_CR_REG |
mov ax, 0x1D |
call [ctrl.ctrl_write8] |
xor eax, eax |
ret |
align 4 |
stop: |
mov edx, PCM_OUT_CR_REG |
mov ax, 0x0 |
call [ctrl.ctrl_write8] |
mov ax, 0x1c |
mov edx, PCM_OUT_SR_REG |
call [ctrl.ctrl_write16] |
xor eax, eax |
ret |
align 4 |
proc get_dev_info stdcall, p_info:dword |
virtual at esi |
CTRL_INFO CTRL_INFO |
end virtual |
mov esi, [p_info] |
mov eax, [ctrl.int_line] |
mov ebx, [ctrl.codec_io_base] |
mov ecx, [ctrl.ctrl_io_base] |
mov edx, [ctrl.codec_mem_base] |
mov edi, [ctrl.ctrl_mem_base] |
mov [CTRL_INFO.irq], eax |
mov [CTRL_INFO.codec_io_base], ebx |
mov [CTRL_INFO.ctrl_io_base], ecx |
mov [CTRL_INFO.codec_mem_base], edx |
mov [CTRL_INFO.ctrl_mem_base], edi |
mov eax, [codec.chip_id] |
mov [CTRL_INFO.codec_id], eax |
mov edx, GLOB_CTRL |
call [ctrl.ctrl_read32] |
mov [CTRL_INFO.glob_cntrl], eax |
mov edx, CTRL_STAT |
call [ctrl.ctrl_read32] |
mov [CTRL_INFO.glob_sta], eax |
mov ebx, [ctrl.pci_cmd] |
mov [CTRL_INFO.pci_cmd], ebx |
ret |
endp |
align 4 |
proc set_callback stdcall, handler:dword |
mov eax, [handler] |
mov [ctrl.user_callback], eax |
ret |
endp |
align 4 |
proc codec_read stdcall, ac_reg:dword ; reg = edx, reval = eax |
mov edx, [ac_reg] |
mov ebx, edx |
shr ebx, 1 |
bt [codec.shadow_flag], ebx |
jc .use_shadow |
call [ctrl.codec_read16] ;change edx !!! |
mov ecx, eax |
mov edx, CTRL_STAT |
call [ctrl.ctrl_read32] |
test eax, CTRL_ST_RCS |
jz .read_ok |
mov edx, CTRL_STAT |
call [ctrl.ctrl_write32] |
xor eax, eax |
not eax ;timeout |
ret |
.read_ok: |
mov edx, [ac_reg] |
mov [codec.regs+edx], cx |
bts [codec.shadow_flag], ebx |
mov eax, ecx |
ret |
.use_shadow: |
movzx eax, word [codec.regs+edx] |
ret |
endp |
align 4 |
proc codec_write stdcall, ac_reg:dword |
push eax |
call check_semafore |
and eax, eax |
jz .err |
pop eax |
mov esi, [ac_reg] |
mov edx, esi |
call [ctrl.codec_write16] |
mov [codec.regs+esi], ax |
shr esi, 1 |
bts [codec.shadow_flag], esi |
ret |
.err: |
pop eax |
ret |
endp |
align 4 |
proc codec_check_ready |
mov edx, CTRL_ST |
call [ctrl.ctrl_read32] |
and eax, CTRL_ST_CREADY |
jz .not_ready |
xor eax, wax |
inc eax |
ret |
.not_ready: |
xor eax, eax |
ret |
endp |
align 4 |
proc check_semafore |
local counter:DWORD |
mov [counter], 100 |
.l1: |
mov edx, CTRL_CAS |
call [ctrl.ctrl_read8] |
and eax, CAS_FLAG |
jz .ok |
mov eax, 1 |
call StallExec |
sub [counter], 1 |
jnz .l1 |
xor eax, eax |
ret |
align 4 |
.ok: |
xor eax, eax |
inc eax |
ret |
endp |
align 4 |
proc StallExec |
push ecx |
push edx |
push ebx |
push eax |
mov ecx, CPU_FREQ |
mul ecx |
mov ebx, eax ;low |
mov ecx, edx ;high |
rdtsc |
add ebx, eax |
adc ecx, edx |
@@: |
rdtsc |
sub eax, ebx |
sbb edx, ecx |
js @B |
pop eax |
pop ebx |
pop edx |
pop ecx |
ret |
endp |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
; CONTROLLER IO functions |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
codec_io_r16: |
add edx, [ctrl.codec_io_base] |
in ax, dx |
ret |
align 4 |
codec_io_w16: |
add edx, [ctrl.codec_io_base] |
out dx, ax |
ret |
align 4 |
ctrl_io_r8: |
add edx, [ctrl.ctrl_io_base] |
in al, dx |
ret |
align 4 |
ctrl_io_r16: |
add edx, [ctrl.ctrl_io_base] |
in ax, dx |
ret |
align 4 |
ctrl_io_r32: |
add edx, [ctrl.ctrl_io_base] |
in eax, dx |
ret |
align 4 |
ctrl_io_w8: |
add edx, [ctrl.ctrl_io_base] |
out dx, al |
ret |
align 4 |
ctrl_io_w16: |
add edx, [ctrl.ctrl_io_base] |
out dx, ax |
ret |
align 4 |
ctrl_io_w32: |
add edx, [ctrl.ctrl_io_base] |
out dx, eax |
ret |
align 4 |
dword2str: |
mov esi, hex_buff |
mov ecx, -8 |
@@: |
rol eax, 4 |
mov ebx, eax |
and ebx, 0x0F |
mov bl, [ebx+hexletters] |
mov [8+esi+ecx], bl |
inc ecx |
jnz @B |
ret |
hexletters db '0123456789ABCDEF' |
hex_buff db 8 dup(0),13,10,0 |
include "codec.inc" |
align 4 |
devices dd (0x5000 shl 16)+0x1274,msgEnsoniq,set_ICH |
dd (0x5880 shl 16)+0x1274,msgVibra128,set_ICH |
dd 0 ;terminator |
version dd 0x00040004 |
msgEnsoniq db 'Ensonic 1371',13,10,0 |
msgVibra128 db 'Sound Blaster AudioPCI Vibra 128',13,10,0 |
sz_sound_srv db 'SOUND',0 |
msgDetect db 'detect hardware...',13,10,0 |
msgFail db 'device not found',13,10,0 |
msgAttchIRQ db 'IRQ line not supported', 13,10, 0 |
msgInvIRQ db 'IRQ line not assigned or invalid', 13,10, 0 |
msgPlay db 'start play', 13,10,0 |
msgStop db 'stop play', 13,10,0 |
msgNotify db 'call notify',13,10,0 |
msgIRQ db 'AC97 IRQ', 13,10,0 |
msgInitCtrl db 'init controller',13,10,0 |
msgInitCodec db 'init codec',13,10,0 |
msgPrimBuff db 'create primary buffer',13,10,0 |
msgReg db 'set service handler',13,10,0 |
msgOk db 'service installed',13,10,0 |
msgCold db 'cold reset',13,10,0 |
msgWarm db 'warm reset',13,10,0 |
msgWRFail db 'warm reset failed',13,10,0 |
msgCRFail db 'cold reset failed',13,10,0 |
msgCFail db 'codec not ready',13,10,0 |
msgResetOk db 'reset complete',13,10,0 |
msgStatus db 'global status ',0 |
msgControl db 'global control ',0 |
msgPCIcmd db 'PCI command ',0 |
msgIObase db 'IO base ',0 |
msgIRQline db 'IRQ line ',0 |
section '.data' data readable writable align 16 |
pcmout_bdl rq 32 |
buff_list rd 32 |
codec CODEC |
ctrl AC_CNTRL |
lpc_bus rd 1 |
civ_val rd 1 |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
/kernel/branches/Kolibri-acpi/drivers/fm801.asm |
---|
0,0 → 1,1062 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
format MS COFF |
DEBUG equ 1 |
DEBUG_IRQ equ 0 |
include 'proc32.inc' |
include 'imports.inc' |
API_VERSION equ 0x01000100 |
USE_COM_IRQ equ 0 ;make irq 3 and irq 4 available for PCI devices |
;irq 0,1,2,8,12,13 недоступны |
; FEDCBA9876543210 |
VALID_IRQ equ 1100111011111000b |
ATTCH_IRQ equ 0000111010100000b |
if USE_COM_IRQ |
ATTCH_IRQ equ 0000111010111000b |
end if |
CPU_FREQ equ 2000d |
BIT0 EQU 0x00000001 |
BIT1 EQU 0x00000002 |
BIT2 EQU 0x00000004 |
BIT3 EQU 0x00000008 |
BIT4 EQU 0x00000010 |
BIT5 EQU 0x00000020 |
BIT6 EQU 0x00000040 |
BIT7 EQU 0x00000080 |
BIT8 EQU 0x00000100 |
BIT9 EQU 0x00000200 |
BIT10 EQU 0x00000400 |
BIT11 EQU 0x00000800 |
BIT12 EQU 0x00001000 |
BIT13 EQU 0x00002000 |
BIT14 EQU 0x00004000 |
BIT15 EQU 0x00008000 |
BIT16 EQU 0x00010000 |
BIT17 EQU 0x00020000 |
BIT18 EQU 0x00040000 |
BIT19 EQU 0x00080000 |
BIT20 EQU 0x00100000 |
BIT21 EQU 0x00200000 |
BIT22 EQU 0x00400000 |
BIT23 EQU 0x00800000 |
BIT24 EQU 0x00100000 |
BIT25 EQU 0x02000000 |
BIT26 EQU 0x04000000 |
BIT27 EQU 0x08000000 |
BIT28 EQU 0x10000000 |
BIT29 EQU 0x20000000 |
BIT30 EQU 0x40000000 |
BIT31 EQU 0x80000000 |
VID_FM801 equ 0x1319 |
CTRL_FM801 equ 0x0801 |
FM_PCM_VOLUME equ 0x00 |
FM_FM_VOLUME equ 0x02 |
FM_I2S_VOLUME equ 0x04 |
FM_RECORD_SOURCE equ 0x06 |
FM_PLAY_CTL equ 0x08 |
FM_PLAY_RATE_MASK equ 0x0f00 |
FM_PLAY_BUF1_LAST equ 0x0001 |
FM_PLAY_BUF2_LAST equ 0x0002 |
FM_PLAY_START equ 0x0020 |
FM_PLAY_PAUSE equ 0x0040 |
FM_PLAY_STOPNOW equ 0x0080 |
FM_PLAY_16BIT equ 0x4000 |
FM_PLAY_STEREO equ 0x8000 |
FM_PLAY_DMALEN equ 0x0a |
FM_PLAY_DMABUF1 equ 0x0c |
FM_PLAY_DMABUF2 equ 0x10 |
FM_REC_CTL equ 0x14 |
FM_REC_RATE_MASK equ 0x0f00 |
FM_REC_BUF1_LAST equ 0x0001 |
FM_REC_BUF2_LAST equ 0x0002 |
FM_REC_START equ 0x0020 |
FM_REC_PAUSE equ 0x0040 |
FM_REC_STOPNOW equ 0x0080 |
FM_REC_16BIT equ 0x4000 |
FM_REC_STEREO equ 0x8000 |
FM_REC_DMALEN equ 0x16 |
FM_REC_DMABUF1 equ 0x18 |
FM_REC_DMABUF2 equ 0x1c |
FM_CODEC_CTL equ 0x22 |
FM_VOLUME equ 0x26 |
FM_VOLUME_MUTE equ 0x8000 |
FM_CODEC_CMD equ 0x2a |
FM_CODEC_CMD_READ equ 0x0080 |
FM_CODEC_CMD_VALID equ 0x0100 |
FM_CODEC_CMD_BUSY equ 0x0200 |
FM_CODEC_DATA equ 0x2c |
FM_IO_CTL equ 0x52 |
FM_CARD_CTL equ 0x54 |
FM_INTMASK equ 0x56 |
FM_INTMASK_PLAY equ 0x0001 |
FM_INTMASK_REC equ 0x0002 |
FM_INTMASK_VOL equ 0x0040 |
FM_INTMASK_MPU equ 0x0080 |
FM_INTSTATUS equ 0x5a |
FM_INTSTATUS_PLAY equ 0x0100 |
FM_INTSTATUS_REC equ 0x0200 |
FM_INTSTATUS_VOL equ 0x4000 |
FM_INTSTATUS_MPU equ 0x8000 |
CODEC_MASTER_VOL_REG equ 0x02 ; |
CODEC_AUX_VOL equ 0x04 ; |
CODEC_PCM_OUT_REG equ 0x18 ; PCM output volume |
CODEC_EXT_AUDIO_REG equ 0x28 ; extended audio |
CODEC_EXT_AUDIO_CTRL_REG equ 0x2a ; extended audio control |
CODEC_PCM_FRONT_DACRATE_REG equ 0x2c ; PCM out sample rate |
CODEC_PCM_SURND_DACRATE_REG equ 0x2e ; surround sound sample rate |
CODEC_PCM_LFE_DACRATE_REG equ 0x30 ; LFE sample rate |
SRV_GETVERSION equ 0 |
DEV_PLAY equ 1 |
DEV_STOP equ 2 |
DEV_CALLBACK equ 3 |
DEV_SET_BUFF equ 4 |
DEV_NOTIFY equ 5 |
DEV_SET_MASTERVOL equ 6 |
DEV_GET_MASTERVOL equ 7 |
DEV_GET_INFO equ 8 |
struc AC_CNTRL ;AC controller base class |
{ .bus dd ? |
.devfn dd ? |
.vendor dd ? |
.dev_id dd ? |
.pci_cmd dd ? |
.pci_stat dd ? |
.codec_io_base dd ? |
.codec_mem_base dd ? |
.ctrl_io_base dd ? |
.ctrl_mem_base dd ? |
.cfg_reg dd ? |
.int_line dd ? |
.vendor_ids dd ? ;vendor id string |
.ctrl_ids dd ? ;hub id string |
.buffer dd ? |
.notify_pos dd ? |
.notify_task dd ? |
.lvi_reg dd ? |
.ctrl_setup dd ? |
.user_callback dd ? |
.codec_read16 dd ? |
.codec_write16 dd ? |
.ctrl_read8 dd ? |
.ctrl_read16 dd ? |
.ctrl_read32 dd ? |
.ctrl_write8 dd ? |
.ctrl_write16 dd ? |
.ctrl_write32 dd ? |
} |
struc CODEC ;Audio Chip base class |
{ |
.chip_id dd ? |
.flags dd ? |
.status dd ? |
.ac_vendor_ids dd ? ;ac vendor id string |
.chip_ids dd ? ;chip model string |
.shadow_flag dd ? |
dd ? |
.regs dw ? ; codec registers |
.reg_master_vol dw ? ;0x02 |
.reg_aux_out_vol dw ? ;0x04 |
.reg_mone_vol dw ? ;0x06 |
.reg_master_tone dw ? ;0x08 |
.reg_beep_vol dw ? ;0x0A |
.reg_phone_vol dw ? ;0x0C |
.reg_mic_vol dw ? ;0x0E |
.reg_line_in_vol dw ? ;0x10 |
.reg_cd_vol dw ? ;0x12 |
.reg_video_vol dw ? ;0x14 |
.reg_aux_in_vol dw ? ;0x16 |
.reg_pcm_out_vol dw ? ;0x18 |
.reg_rec_select dw ? ;0x1A |
.reg_rec_gain dw ? ;0x1C |
.reg_rec_gain_mic dw ? ;0x1E |
.reg_gen dw ? ;0x20 |
.reg_3d_ctrl dw ? ;0X22 |
.reg_page dw ? ;0X24 |
.reg_powerdown dw ? ;0x26 |
.reg_ext_audio dw ? ;0x28 |
.reg_ext_st dw ? ;0x2a |
.reg_pcm_front_rate dw ? ;0x2c |
.reg_pcm_surr_rate dw ? ;0x2e |
.reg_lfe_rate dw ? ;0x30 |
.reg_pcm_in_rate dw ? ;0x32 |
dw ? ;0x34 |
.reg_cent_lfe_vol dw ? ;0x36 |
.reg_surr_vol dw ? ;0x38 |
.reg_spdif_ctrl dw ? ;0x3A |
dw ? ;0x3C |
dw ? ;0x3E |
dw ? ;0x40 |
dw ? ;0x42 |
dw ? ;0x44 |
dw ? ;0x46 |
dw ? ;0x48 |
dw ? ;0x4A |
dw ? ;0x4C |
dw ? ;0x4E |
dw ? ;0x50 |
dw ? ;0x52 |
dw ? ;0x54 |
dw ? ;0x56 |
dw ? ;0x58 |
dw ? ;0x5A |
dw ? ;0x5C |
dw ? ;0x5E |
.reg_page_0 dw ? ;0x60 |
.reg_page_1 dw ? ;0x62 |
.reg_page_2 dw ? ;0x64 |
.reg_page_3 dw ? ;0x66 |
.reg_page_4 dw ? ;0x68 |
.reg_page_5 dw ? ;0x6A |
.reg_page_6 dw ? ;0x6C |
.reg_page_7 dw ? ;0x6E |
dw ? ;0x70 |
dw ? ;0x72 |
dw ? ;0x74 |
dw ? ;0x76 |
dw ? ;0x78 |
dw ? ;0x7A |
.reg_vendor_id_1 dw ? ;0x7C |
.reg_vendor_id_2 dw ? ;0x7E |
.reset dd ? ;virual |
.set_master_vol dd ? |
} |
struc CTRL_INFO |
{ .pci_cmd dd ? |
.irq dd ? |
.glob_cntrl dd ? |
.glob_sta dd ? |
.codec_io_base dd ? |
.ctrl_io_base dd ? |
.codec_mem_base dd ? |
.ctrl_mem_base dd ? |
.codec_id dd ? |
} |
struc IOCTL |
{ .handle dd ? |
.io_code dd ? |
.input dd ? |
.inp_size dd ? |
.output dd ? |
.out_size dd ? |
} |
virtual at 0 |
IOCTL IOCTL |
end virtual |
EVENT_NOTIFY equ 0x00000200 |
public START |
public service_proc |
public version |
section '.flat' code readable align 16 |
proc START stdcall, state:dword |
cmp [state], 1 |
jne .stop |
if DEBUG |
mov eax, START |
call dword2str |
call SysMsgBoardStr |
mov esi, msgInit |
call SysMsgBoardStr |
end if |
call detect_controller |
test eax, eax |
jz .fail |
if DEBUG |
mov esi, [ctrl.vendor_ids] |
call SysMsgBoardStr |
mov esi, [ctrl.ctrl_ids] |
call SysMsgBoardStr |
end if |
call init_controller |
test eax, eax |
jz .fail |
call init_codec |
test eax, eax |
jz .fail |
call reset_controller |
call setup_codec |
mov esi, msgPrimBuff |
call SysMsgBoardStr |
call create_primary_buff |
mov esi, msgDone |
call SysMsgBoardStr |
mov eax, VALID_IRQ |
mov ebx, [ctrl.int_line] |
mov esi, msgInvIRQ |
bt eax, ebx |
jnc .fail_msg |
mov eax, ATTCH_IRQ |
mov esi, msgAttchIRQ |
bt eax, ebx |
jnc .fail_msg |
stdcall AttachIntHandler, ebx, ac97_irq, dword 0 |
.reg: |
stdcall RegService, sz_sound_srv, service_proc |
ret |
.fail: |
if DEBUG |
mov esi, msgFail |
call SysMsgBoardStr |
end if |
xor eax, eax |
ret |
.fail_msg: |
call SysMsgBoardStr |
xor eax, eax |
ret |
.stop: |
call stop |
xor eax, eax |
ret |
endp |
handle equ IOCTL.handle |
io_code equ IOCTL.io_code |
input equ IOCTL.input |
inp_size equ IOCTL.inp_size |
output equ IOCTL.output |
out_size equ IOCTL.out_size |
align 4 |
proc service_proc stdcall, ioctl:dword |
mov edi, [ioctl] |
mov eax, [edi+io_code] |
cmp eax, SRV_GETVERSION |
jne @F |
mov eax, [edi+output] |
cmp [edi+out_size], 4 |
jne .fail |
mov [eax], dword API_VERSION |
xor eax, eax |
ret |
@@: |
cmp eax, DEV_PLAY |
jne @F |
if DEBUG |
mov esi, msgPlay |
call SysMsgBoardStr |
end if |
call play |
ret |
@@: |
cmp eax, DEV_STOP |
jne @F |
if DEBUG |
mov esi, msgStop |
call SysMsgBoardStr |
end if |
call stop |
ret |
@@: |
cmp eax, DEV_CALLBACK |
jne @F |
mov ebx, [edi+input] |
stdcall set_callback, [ebx] |
ret |
@@: |
cmp eax, DEV_SET_MASTERVOL |
jne @F |
mov eax, [edi+input] |
mov eax, [eax] |
call set_master_vol ;eax= vol |
ret |
@@: |
cmp eax, DEV_GET_MASTERVOL |
jne @F |
mov ebx, [edi+output] |
stdcall get_master_vol, ebx |
ret |
;@@: |
; cmp eax, DEV_GET_INFO |
; jne @F |
; mov ebx, [edi+output] |
; stdcall get_dev_info, ebx |
; ret |
@@: |
.fail: |
or eax, -1 |
ret |
endp |
restore handle |
restore io_code |
restore input |
restore inp_size |
restore output |
restore out_size |
align 4 |
proc fill_buffer |
cmp [ctrl.user_callback], 0 |
je .exit |
mov esi, [ctrl.buffer] |
mov eax, int_flip_flop |
inc dword [eax] |
test dword [eax], 1 |
je @f |
add esi, 0x4000 |
@@: |
stdcall [ctrl.user_callback], esi |
mov edx, FM_PLAY_DMABUF1 |
mov eax, [buffer_pgaddr] |
mov esi, int_flip_flop |
test dword [esi], 1 |
je @f |
mov edx, FM_PLAY_DMABUF2 |
add eax, 0x4000 |
@@: |
call [ctrl.ctrl_write32] |
.exit: |
ret |
endp |
align 4 |
proc ac97_irq |
if DEBUG_IRQ |
mov esi, msgIRQ |
call SysMsgBoardStr |
end if |
mov edx, FM_INTSTATUS |
call [ctrl.ctrl_read16] |
test eax, FM_INTSTATUS_PLAY |
je .exit |
push eax |
call fill_buffer |
pop eax |
.exit: |
mov edx, FM_INTSTATUS |
call [ctrl.ctrl_write16] |
ret |
endp |
align 4 |
proc create_primary_buff |
stdcall KernelAlloc, 0x10000 |
mov [ctrl.buffer], eax |
mov edi, eax |
mov ecx, 0x10000/4 |
xor eax, eax |
cld |
rep stosd |
mov eax, [ctrl.buffer] |
call GetPgAddr |
mov [buffer_pgaddr], eax |
ret |
endp |
align 4 |
proc detect_controller |
locals |
last_bus dd ? |
bus dd ? |
devfn dd ? |
endl |
xor eax, eax |
mov [bus], eax |
inc eax |
call PciApi |
cmp eax, -1 |
je .err |
mov [last_bus], eax |
.next_bus: |
and [devfn], 0 |
.next_dev: |
stdcall PciRead32, [bus], [devfn], dword 0 |
test eax, eax |
jz .next |
cmp eax, -1 |
je .next |
push eax |
stdcall PciRead32, [bus], [devfn], dword 0x09 |
and eax, 0xffffff |
cmp eax, 0x060100 ;pci-isa |
jne .no_bridge |
mov eax, [bus] |
mov [brg_bus], eax |
mov eax, [devfn] |
mov [brg_devfn], eax |
.no_bridge: |
pop eax |
mov edi, devices |
@@: |
mov ebx, [edi] |
test ebx, ebx |
jz .next |
cmp eax, ebx |
je .found |
add edi, 12 |
jmp @B |
.next: |
inc [devfn] |
cmp [devfn], 256 |
jb .next_dev |
mov eax, [bus] |
inc eax |
mov [bus], eax |
cmp eax, [last_bus] |
jna .next_bus |
xor eax, eax |
ret |
.found: |
mov ebx, [bus] |
mov [ctrl.bus], ebx |
mov ecx, [devfn] |
mov [ctrl.devfn], ecx |
mov edx, eax |
and edx, 0xFFFF |
mov [ctrl.vendor], edx |
shr eax, 16 |
mov [ctrl.dev_id], eax |
mov ebx, [edi+4] |
mov [ctrl.ctrl_ids], ebx |
mov [ctrl.vendor_ids], msg_FM |
mov esi, [edi+8] |
mov [ctrl.ctrl_setup], esi |
ret |
.err: |
xor eax, eax |
ret |
endp |
align 4 |
proc init_controller |
stdcall PciRead32, [ctrl.bus], [ctrl.devfn], dword 4 |
mov ebx, eax |
and eax, 0xFFFF |
mov [ctrl.pci_cmd], eax |
shr ebx, 16 |
mov [ctrl.pci_stat], ebx |
mov esi, msgPciCmd |
call SysMsgBoardStr |
call dword2str |
call SysMsgBoardStr |
mov esi, msgPciStat |
call SysMsgBoardStr |
mov eax, [ctrl.pci_stat] |
call dword2str |
call SysMsgBoardStr |
mov esi, msgCtrlIsaIo |
call SysMsgBoardStr |
stdcall PciRead32, [ctrl.bus], [ctrl.devfn], dword 0x10 |
call dword2str |
call SysMsgBoardStr |
and eax, 0xFFFE |
mov [ctrl.ctrl_io_base], eax |
mov esi, msgIrqNum |
call SysMsgBoardStr |
stdcall PciRead32, [ctrl.bus], [ctrl.devfn], dword 0x3C |
and eax, 0xFF |
mov [ctrl.int_line], eax |
call dword2str |
call SysMsgBoardStr |
call [ctrl.ctrl_setup] |
xor eax, eax |
inc eax |
ret |
endp |
align 4 |
proc set_FM |
mov [ctrl.codec_read16], codec_io_r16 ;virtual |
mov [ctrl.codec_write16], codec_io_w16 ;virtual |
mov [ctrl.ctrl_read8 ], ctrl_io_r8 ;virtual |
mov [ctrl.ctrl_read16], ctrl_io_r16 ;virtual |
mov [ctrl.ctrl_read32], ctrl_io_r32 ;virtual |
mov [ctrl.ctrl_write8 ], ctrl_io_w8 ;virtual |
mov [ctrl.ctrl_write16], ctrl_io_w16 ;virtual |
mov [ctrl.ctrl_write32], ctrl_io_w32 ;virtual |
ret |
endp |
align 4 |
proc reset_controller |
mov esi, msgInitCtrl |
call SysMsgBoardStr |
mov edx, FM_CARD_CTL |
call [ctrl.ctrl_read8] |
push eax |
or al, 1 |
mov edx, FM_CARD_CTL |
call [ctrl.ctrl_write8] |
mov eax, 10 |
call StallExec |
pop eax |
and al, 0xFE |
mov edx, FM_CARD_CTL |
call [ctrl.ctrl_write8] |
mov eax, 10 |
call StallExec |
mov eax, 0x0404 |
mov edx, FM_PCM_VOLUME |
call [ctrl.ctrl_write16] |
mov edx, FM_FM_VOLUME |
call [ctrl.ctrl_write16] |
mov edx, FM_I2S_VOLUME |
call [ctrl.ctrl_write16] |
mov edx, FM_INTMASK |
call [ctrl.ctrl_read16] |
and eax, not FM_INTMASK_PLAY |
or eax, FM_INTMASK_REC or FM_INTMASK_MPU or FM_INTMASK_VOL |
mov edx, FM_INTMASK |
call [ctrl.ctrl_write16] |
mov eax, FM_INTMASK_PLAY or FM_INTMASK_REC or FM_INTMASK_MPU or FM_INTMASK_VOL |
mov edx, FM_INTSTATUS |
call [ctrl.ctrl_write16] |
ret |
endp |
align 4 |
proc init_codec |
mov esi, msgInitCodec |
call SysMsgBoardStr |
mov al, FM_CODEC_CMD_READ |
mov edx, FM_CODEC_CMD |
call [ctrl.ctrl_write8] |
call reset_codec |
call detect_codec |
xor eax, eax |
inc eax |
ret |
endp |
align 4 |
proc reset_codec |
mov ecx, 255 |
.L1: |
mov edx, FM_CODEC_CMD |
call [ctrl.ctrl_read16] |
test ah, FM_CODEC_CMD_VALID shr 8 |
jne .L2 |
loop .L1 |
.L2: |
mov edx, FM_CODEC_CTL |
call [ctrl.ctrl_read8] |
push eax |
or al, 0x20 |
mov edx, FM_CODEC_CTL |
call [ctrl.ctrl_write8] |
pop eax |
and al, 0xDF |
mov edx, FM_CODEC_CTL |
call [ctrl.ctrl_write8] |
xor eax, eax |
inc eax |
ret |
endp |
align 4 |
play: |
mov eax, 0x4000-1 |
mov edx, FM_PLAY_DMALEN |
call [ctrl.ctrl_write16] |
call fill_buffer |
mov eax, FM_PLAY_START or FM_PLAY_STOPNOW or FM_PLAY_STEREO or FM_PLAY_16BIT or 0xA00 |
mov edx, FM_PLAY_CTL |
call [ctrl.ctrl_write16] |
xor eax, eax |
ret |
align 4 |
stop: |
mov edx, FM_PLAY_CTL |
call [ctrl.ctrl_read16] |
and eax, not (FM_PLAY_START or FM_PLAY_STOPNOW) |
or eax, FM_PLAY_BUF1_LAST or FM_PLAY_BUF2_LAST |
mov edx, FM_PLAY_CTL |
call [ctrl.ctrl_write16] |
xor eax, eax |
ret |
align 4 |
proc get_dev_info stdcall, p_info:dword |
virtual at esi |
CTRL_INFO CTRL_INFO |
end virtual |
mov esi, [p_info] |
mov eax, [ctrl.int_line] |
mov ebx, [ctrl.codec_io_base] |
mov ecx, [ctrl.ctrl_io_base] |
mov edx, [ctrl.codec_mem_base] |
mov edi, [ctrl.ctrl_mem_base] |
mov [CTRL_INFO.irq], eax |
mov [CTRL_INFO.codec_io_base], ebx |
mov [CTRL_INFO.ctrl_io_base], ecx |
mov [CTRL_INFO.codec_mem_base], edx |
mov [CTRL_INFO.ctrl_mem_base], edi |
mov eax, [codec.chip_id] |
mov [CTRL_INFO.codec_id], eax |
mov ebx, [ctrl.pci_cmd] |
mov [CTRL_INFO.pci_cmd], ebx |
ret |
endp |
align 4 |
proc set_callback stdcall, handler:dword |
mov eax, [handler] |
mov [ctrl.user_callback], eax |
ret |
endp |
align 4 |
proc codec_read stdcall, ac_reg:dword ; reg = edx, reval = eax |
mov edx, [ac_reg] |
mov ebx, edx |
shr ebx, 1 |
bt [codec.shadow_flag], ebx |
jc .use_shadow |
call [ctrl.codec_read16] ;change edx !!! |
mov ecx, eax |
.read_ok: |
mov edx, [ac_reg] |
mov [codec.regs+edx], cx |
bts [codec.shadow_flag], ebx |
mov eax, ecx |
ret |
.use_shadow: |
movzx eax, word [codec.regs+edx] |
ret |
endp |
align 4 |
proc codec_write stdcall, ac_reg:dword |
mov esi, [ac_reg] |
mov edx, esi |
call [ctrl.codec_write16] |
mov [codec.regs+esi], ax |
shr esi, 1 |
bts [codec.shadow_flag], esi |
ret |
endp |
align 4 |
proc check_semafore |
align 4 |
.ok: |
xor eax, eax |
inc eax |
ret |
endp |
align 4 |
proc StallExec |
push ecx |
push edx |
push ebx |
push eax |
mov ecx, CPU_FREQ |
mul ecx |
mov ebx, eax ;low |
mov ecx, edx ;high |
rdtsc |
add ebx, eax |
adc ecx, edx |
@@: |
rdtsc |
sub eax, ebx |
sbb edx, ecx |
js @B |
pop eax |
pop ebx |
pop edx |
pop ecx |
ret |
endp |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
; CONTROLLER IO functions |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
proc codec_io_r16 |
push edx |
mov ecx, 255 |
.L1: |
mov edx, FM_CODEC_CMD |
call [ctrl.ctrl_read16] |
test ah, FM_CODEC_CMD_BUSY shr 8 |
je .L2 |
loop .L1 |
.L2: |
pop eax |
or al, FM_CODEC_CMD_READ |
mov edx, FM_CODEC_CMD |
call [ctrl.ctrl_write8] |
mov ecx, 255 |
.L3: |
mov edx, FM_CODEC_CMD |
call [ctrl.ctrl_read16] |
test ah, FM_CODEC_CMD_VALID shr 8 |
jne .L4 |
loop .L3 |
.L4: |
mov edx, FM_CODEC_DATA |
call [ctrl.ctrl_read16] |
ret |
endp |
align 4 |
proc codec_io_w16 |
push edx |
push eax |
mov ecx, 255 |
.L1: |
mov edx, FM_CODEC_CMD |
call [ctrl.ctrl_read16] |
test ah, FM_CODEC_CMD_BUSY shr 8 |
je .L2 |
loop .L1 |
.L2: |
pop eax |
mov edx, FM_CODEC_DATA |
call [ctrl.ctrl_write16] |
pop eax |
mov edx, FM_CODEC_CMD |
call [ctrl.ctrl_write16] |
ret |
endp |
align 4 |
proc ctrl_io_r8 |
add edx, [ctrl.ctrl_io_base] |
in al, dx |
ret |
endp |
align 4 |
proc ctrl_io_r16 |
add edx, [ctrl.ctrl_io_base] |
in ax, dx |
ret |
endp |
align 4 |
proc ctrl_io_r32 |
add edx, [ctrl.ctrl_io_base] |
in eax, dx |
ret |
endp |
align 4 |
proc ctrl_io_w8 |
add edx, [ctrl.ctrl_io_base] |
out dx, al |
ret |
endp |
align 4 |
proc ctrl_io_w16 |
add edx, [ctrl.ctrl_io_base] |
out dx, ax |
ret |
endp |
align 4 |
proc ctrl_io_w32 |
add edx, [ctrl.ctrl_io_base] |
out dx, eax |
ret |
endp |
align 4 |
dword2str: |
mov esi, hex_buff |
mov ecx, -8 |
@@: |
rol eax, 4 |
mov ebx, eax |
and ebx, 0x0F |
mov bl, [ebx+hexletters] |
mov [8+esi+ecx], bl |
inc ecx |
jnz @B |
ret |
hexletters db '0123456789ABCDEF' |
hex_buff db 8 dup(0),13,10,0 |
brg_bus dd ? |
brg_devfn dd ? |
include "codec.inc" |
align 4 |
devices dd (CTRL_FM801 shl 16)+VID_FM801, msg_FM801, set_FM |
dd 0 |
version dd (5 shl 16) or (API_VERSION and 0xFFFF) |
msg_FM801 db 'FM801 AC97 controller',13,10, 0 |
msg_FM db 'Forte Media',13,10, 0 |
sz_sound_srv db 'SOUND',0 |
msgInit db 'detect hardware...',13,10,0 |
msgFail db 'device not found',13,10,0 |
msgAttchIRQ db 'IRQ line not supported', 13,10, 0 |
msgInvIRQ db 'IRQ line not assigned or invalid', 13,10, 0 |
msgPlay db 'start play', 13,10,0 |
msgStop db 'stop play', 13,10,0 |
;msgNotify db 'call notify',13,10,0 |
msgIRQ db 'AC97 IRQ', 13,10,0 |
msgInitCtrl db 'init controller',13,10,0 |
msgInitCodec db 'init codec',13,10,0 |
msgPrimBuff db 'create primary buffer ...',0 |
msgDone db 'done',13,10,0 |
;msgReg db 'set service handler',13,10,0 |
;msgOk db 'service installed',13,10,0 |
;msgStatus db 'global status ',0 |
;msgControl db 'global control ',0 |
msgPciCmd db 'PCI command ',0 |
msgPciStat db 'PCI status ',0 |
msgCtrlIsaIo db 'controller io base ',0 |
msgIrqNum db 'IRQ default ',0 |
;msgIrqMap db 'AC97 irq map as ',0 |
section '.data' data readable writable align 16 |
codec CODEC |
ctrl AC_CNTRL |
int_flip_flop rd 1 |
buffer_pgaddr rd 1 |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |
/kernel/branches/Kolibri-acpi/drivers/intelac97.asm |
---|
0,0 → 1,1507 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
format MS COFF |
DEBUG equ 1 |
include 'proc32.inc' |
include 'imports.inc' |
API_VERSION equ 0x01000100 |
DEBUG_IRQ equ 0 |
USE_COM_IRQ equ 0 ;make irq 3 and irq 4 available for PCI devices |
IRQ_REMAP equ 0 |
IRQ_LINE equ 0 |
;irq 0,1,2,8,12,13 недоступны |
; FEDCBA9876543210 |
VALID_IRQ equ 1100111011111000b |
ATTCH_IRQ equ 0000111010100000b |
if USE_COM_IRQ |
ATTCH_IRQ equ 0000111010111000b |
end if |
CPU_FREQ equ 2600d |
BIT0 EQU 0x00000001 |
BIT1 EQU 0x00000002 |
BIT2 EQU 0x00000004 |
BIT3 EQU 0x00000008 |
BIT4 EQU 0x00000010 |
BIT5 EQU 0x00000020 |
BIT6 EQU 0x00000040 |
BIT7 EQU 0x00000080 |
BIT8 EQU 0x00000100 |
BIT9 EQU 0x00000200 |
BIT10 EQU 0x00000400 |
BIT11 EQU 0x00000800 |
BIT12 EQU 0x00001000 |
BIT13 EQU 0x00002000 |
BIT14 EQU 0x00004000 |
BIT15 EQU 0x00008000 |
BIT16 EQU 0x00010000 |
BIT17 EQU 0x00020000 |
BIT18 EQU 0x00040000 |
BIT19 EQU 0x00080000 |
BIT20 EQU 0x00100000 |
BIT21 EQU 0x00200000 |
BIT22 EQU 0x00400000 |
BIT23 EQU 0x00800000 |
BIT24 EQU 0x00100000 |
BIT25 EQU 0x02000000 |
BIT26 EQU 0x04000000 |
BIT27 EQU 0x08000000 |
BIT28 EQU 0x10000000 |
BIT29 EQU 0x20000000 |
BIT30 EQU 0x40000000 |
BIT31 EQU 0x80000000 |
PCM_4 equ BIT20 |
PCM_6 equ BIT21 |
VID_INTEL equ 0x8086 |
VID_NVIDIA equ 0x10DE |
CTRL_ICH equ 0x2415 |
CTRL_ICH0 equ 0x2425 |
CTRL_ICH2 equ 0x2435 |
CTRL_ICH3 equ 0x2445 |
CTRL_ICH4 equ 0x24C5 |
CTRL_ICH5 equ 0x24D5 |
CTRL_ICH6 equ 0x266E |
CTRL_ICH7 equ 0x27DE |
CTRL_NFORCE equ 0x01B1 |
CTRL_NFORCE2 equ 0x006A |
CTRL_NFORCE3 equ 0x00DA |
CTRL_MCP04 equ 0x003A |
CTRL_CK804 equ 0x0059 |
CTRL_CK8 equ 0x008A |
CTRL_CK8S equ 0x00EA |
CTRL_MCP51 equ 0x026B |
PCM_OUT_BDL equ 0x10 ; PCM out buffer descriptors list |
PCM_OUT_CR_REG equ 0x1b ; PCM out Control Register |
PCM_OUT_LVI_REG equ 0x15 ; PCM last valid index |
PCM_OUT_SR_REG equ 0x16 ; PCM out Status register |
PCM_OUT_PIV_REG equ 0x1a |
PCM_OUT_CIV_REG equ 0x14 ; PCM out current index |
PCM_IN_CR_REG equ 0x0b ; PCM in Control Register |
MC_IN_CR_REG equ 0x2b ; MIC in Control Register |
RR equ BIT1 ; reset registers. Nukes all regs |
CODEC_MASTER_VOL_REG equ 0x02 |
CODEC_AUX_VOL equ 0x04 ; |
CODEC_PCM_OUT_REG equ 0x18 ; PCM output volume |
CODEC_EXT_AUDIO_REG equ 0x28 ; extended audio |
CODEC_EXT_AUDIO_CTRL_REG equ 0x2a ; extended audio control |
CODEC_PCM_FRONT_DACRATE_REG equ 0x2c ; PCM out sample rate |
CODEC_PCM_SURND_DACRATE_REG equ 0x2e ; surround sound sample rate |
CODEC_PCM_LFE_DACRATE_REG equ 0x30 ; LFE sample rate |
GLOB_CTRL equ 0x2C ; Global Control |
CTRL_STAT equ 0x30 ; Global Status |
CTRL_CAS equ 0x34 ; Codec Access Semiphore |
CAS_FLAG equ 0x01 ; Codec Access Semiphore Bit |
CTRL_ST_CREADY equ BIT8+BIT9+BIT28 ; Primary Codec Ready |
CTRL_ST_RCS equ 0x00008000 ; Read Completion Status |
CTRL_CNT_CRIE equ BIT4+BIT5+BIT6 ; Codecs Resume Interrupt Enable |
CTRL_CNT_AC_OFF equ 0x00000008 ; ACLINK Off |
CTRL_CNT_WARM equ 0x00000004 ; AC97 Warm Reset |
CTRL_CNT_COLD equ 0x00000002 ; AC97 Cold Reset |
CTRL_CNT_GIE equ 0x00000001 ; GPI Interrupt Enable |
CODEC_REG_POWERDOWN equ 0x26 |
CODEC_REG_ST equ 0x26 |
SRV_GETVERSION equ 0 |
DEV_PLAY equ 1 |
DEV_STOP equ 2 |
DEV_CALLBACK equ 3 |
DEV_SET_BUFF equ 4 |
DEV_NOTIFY equ 5 |
DEV_SET_MASTERVOL equ 6 |
DEV_GET_MASTERVOL equ 7 |
DEV_GET_INFO equ 8 |
DEV_GET_POS equ 9 |
struc AC_CNTRL ;AC controller base class |
{ .bus dd ? |
.devfn dd ? |
.vendor dd ? |
.dev_id dd ? |
.pci_cmd dd ? |
.pci_stat dd ? |
.codec_io_base dd ? |
.codec_mem_base dd ? |
.ctrl_io_base dd ? |
.ctrl_mem_base dd ? |
.cfg_reg dd ? |
.int_line dd ? |
.vendor_ids dd ? ;vendor id string |
.ctrl_ids dd ? ;hub id string |
.buffer dd ? |
.notify_pos dd ? |
.notify_task dd ? |
.lvi_reg dd ? |
.ctrl_setup dd ? |
.user_callback dd ? |
.codec_read16 dd ? |
.codec_write16 dd ? |
.ctrl_read8 dd ? |
.ctrl_read16 dd ? |
.ctrl_read32 dd ? |
.ctrl_write8 dd ? |
.ctrl_write16 dd ? |
.ctrl_write32 dd ? |
} |
struc CODEC ;Audio Chip base class |
{ |
.chip_id dd ? |
.flags dd ? |
.status dd ? |
.ac_vendor_ids dd ? ;ac vendor id string |
.chip_ids dd ? ;chip model string |
.shadow_flag dd ? |
dd ? |
.regs dw ? ; codec registers |
.reg_master_vol dw ? ;0x02 |
.reg_aux_out_vol dw ? ;0x04 |
.reg_mone_vol dw ? ;0x06 |
.reg_master_tone dw ? ;0x08 |
.reg_beep_vol dw ? ;0x0A |
.reg_phone_vol dw ? ;0x0C |
.reg_mic_vol dw ? ;0x0E |
.reg_line_in_vol dw ? ;0x10 |
.reg_cd_vol dw ? ;0x12 |
.reg_video_vol dw ? ;0x14 |
.reg_aux_in_vol dw ? ;0x16 |
.reg_pcm_out_vol dw ? ;0x18 |
.reg_rec_select dw ? ;0x1A |
.reg_rec_gain dw ? ;0x1C |
.reg_rec_gain_mic dw ? ;0x1E |
.reg_gen dw ? ;0x20 |
.reg_3d_ctrl dw ? ;0X22 |
.reg_page dw ? ;0X24 |
.reg_powerdown dw ? ;0x26 |
.reg_ext_audio dw ? ;0x28 |
.reg_ext_st dw ? ;0x2a |
.reg_pcm_front_rate dw ? ;0x2c |
.reg_pcm_surr_rate dw ? ;0x2e |
.reg_lfe_rate dw ? ;0x30 |
.reg_pcm_in_rate dw ? ;0x32 |
dw ? ;0x34 |
.reg_cent_lfe_vol dw ? ;0x36 |
.reg_surr_vol dw ? ;0x38 |
.reg_spdif_ctrl dw ? ;0x3A |
dw ? ;0x3C |
dw ? ;0x3E |
dw ? ;0x40 |
dw ? ;0x42 |
dw ? ;0x44 |
dw ? ;0x46 |
dw ? ;0x48 |
dw ? ;0x4A |
dw ? ;0x4C |
dw ? ;0x4E |
dw ? ;0x50 |
dw ? ;0x52 |
dw ? ;0x54 |
dw ? ;0x56 |
dw ? ;0x58 |
dw ? ;0x5A |
dw ? ;0x5C |
dw ? ;0x5E |
.reg_page_0 dw ? ;0x60 |
.reg_page_1 dw ? ;0x62 |
.reg_page_2 dw ? ;0x64 |
.reg_page_3 dw ? ;0x66 |
.reg_page_4 dw ? ;0x68 |
.reg_page_5 dw ? ;0x6A |
.reg_page_6 dw ? ;0x6C |
.reg_page_7 dw ? ;0x6E |
dw ? ;0x70 |
dw ? ;0x72 |
dw ? ;0x74 |
dw ? ;0x76 |
dw ? ;0x78 |
dw ? ;0x7A |
.reg_vendor_id_1 dw ? ;0x7C |
.reg_vendor_id_2 dw ? ;0x7E |
.reset dd ? ;virual |
.set_master_vol dd ? |
} |
struc CTRL_INFO |
{ .pci_cmd dd ? |
.irq dd ? |
.glob_cntrl dd ? |
.glob_sta dd ? |
.codec_io_base dd ? |
.ctrl_io_base dd ? |
.codec_mem_base dd ? |
.ctrl_mem_base dd ? |
.codec_id dd ? |
} |
struc IOCTL |
{ .handle dd ? |
.io_code dd ? |
.input dd ? |
.inp_size dd ? |
.output dd ? |
.out_size dd ? |
} |
virtual at 0 |
IOCTL IOCTL |
end virtual |
EVENT_NOTIFY equ 0x00000200 |
public START |
public service_proc |
public version |
section '.flat' code readable align 16 |
proc START stdcall, state:dword |
cmp [state], 1 |
jne .stop |
if DEBUG |
mov esi, msgInit |
call SysMsgBoardStr |
end if |
call detect_controller |
test eax, eax |
jz .fail |
if DEBUG |
mov esi, [ctrl.vendor_ids] |
call SysMsgBoardStr |
mov esi, [ctrl.ctrl_ids] |
call SysMsgBoardStr |
end if |
call init_controller |
test eax, eax |
jz .fail |
call init_codec |
test eax, eax |
jz .fail |
call reset_controller |
call setup_codec |
mov esi, msgPrimBuff |
call SysMsgBoardStr |
call create_primary_buff |
mov esi, msgDone |
call SysMsgBoardStr |
if IRQ_REMAP |
pushf |
cli |
mov ebx, [ctrl.int_line] |
in al, 0xA1 |
mov ah, al |
in al, 0x21 |
test ebx, ebx |
jz .skip |
bts ax, bx ;mask old line |
.skip |
bts ax, IRQ_LINE ;mask new ine |
out 0x21, al |
mov al, ah |
out 0xA1, al |
;remap IRQ |
stdcall PciWrite8, 0, 0xF8, 0x61, IRQ_LINE |
mov dx, 0x4d0 ;8259 ELCR1 |
in al, dx |
bts ax, IRQ_LINE |
out dx, al ;set level-triggered mode |
mov [ctrl.int_line], IRQ_LINE |
popf |
mov esi, msgRemap |
call SysMsgBoardStr |
end if |
mov ebx, [ctrl.int_line] |
stdcall AttachIntHandler, ebx, ac97_irq, dword 0 |
.reg: |
stdcall RegService, sz_sound_srv, service_proc |
ret |
.fail: |
if DEBUG |
mov esi, msgFail |
call SysMsgBoardStr |
end if |
xor eax, eax |
ret |
.fail_msg: |
call SysMsgBoardStr |
xor eax, eax |
ret |
.stop: |
call stop |
xor eax, eax |
ret |
endp |
handle equ IOCTL.handle |
io_code equ IOCTL.io_code |
input equ IOCTL.input |
inp_size equ IOCTL.inp_size |
output equ IOCTL.output |
out_size equ IOCTL.out_size |
align 4 |
proc service_proc stdcall, ioctl:dword |
mov edi, [ioctl] |
mov eax, [edi+io_code] |
cmp eax, SRV_GETVERSION |
jne @F |
mov eax, [edi+output] |
cmp [edi+out_size], 4 |
jne .fail |
mov [eax], dword API_VERSION |
xor eax, eax |
ret |
@@: |
cmp eax, DEV_PLAY |
jne @F |
if DEBUG |
mov esi, msgPlay |
call SysMsgBoardStr |
end if |
call play |
ret |
@@: |
cmp eax, DEV_STOP |
jne @F |
if DEBUG |
mov esi, msgStop |
call SysMsgBoardStr |
end if |
call stop |
ret |
@@: |
cmp eax, DEV_CALLBACK |
jne @F |
mov ebx, [edi+input] |
stdcall set_callback, [ebx] |
ret |
@@: |
cmp eax, DEV_SET_MASTERVOL |
jne @F |
mov eax, [edi+input] |
mov eax, [eax] |
call set_master_vol ;eax= vol |
ret |
@@: |
cmp eax, DEV_GET_MASTERVOL |
jne @F |
mov ebx, [edi+output] |
stdcall get_master_vol, ebx |
ret |
@@: |
cmp eax, DEV_GET_POS |
jne @F |
mov ebx, 8192 |
mov edx, 0x18 |
xor eax, eax |
call [ctrl.ctrl_read16] |
sub ebx, eax |
shr ebx, 1 |
mov edx, [edi+output] |
mov [edx], ebx |
xor eax, eax |
ret |
;@@: |
; cmp eax, DEV_GET_INFO |
; jne @F |
; mov ebx, [edi+output] |
; stdcall get_dev_info, ebx |
; ret |
@@: |
.fail: |
or eax, -1 |
ret |
endp |
restore handle |
restore io_code |
restore input |
restore inp_size |
restore output |
restore out_size |
align 4 |
proc ac97_irq |
if DEBUG_IRQ |
mov esi, msgIRQ |
call SysMsgBoardStr |
end if |
mov edx, CTRL_STAT |
call [ctrl.ctrl_read32] |
cmp eax, 0xffffffff |
je .exit |
test eax, 0x40 |
jnz .do_intr |
test eax, eax |
jz .exit |
mov edx, CTRL_STAT |
call [ctrl.ctrl_write32] |
.exit: |
xor eax, eax |
ret |
.do_intr: |
push eax |
mov edx, PCM_OUT_CR_REG |
mov al, 0x10; 0x10 |
call [ctrl.ctrl_write8] |
mov ax, 0x1c |
mov edx, PCM_OUT_SR_REG |
call [ctrl.ctrl_write16] |
mov edx, PCM_OUT_CIV_REG |
call [ctrl.ctrl_read8] |
and eax, 0x1F |
cmp eax, [civ_val] |
je .skip |
mov [civ_val], eax |
dec eax |
and eax, 0x1F |
mov [ctrl.lvi_reg], eax |
mov edx, PCM_OUT_LVI_REG |
call [ctrl.ctrl_write8] |
mov edx, PCM_OUT_CR_REG |
mov ax, 0x11 ;0x1D |
call [ctrl.ctrl_write8] |
mov eax, [civ_val] |
add eax, 1 |
and eax, 31 |
mov ebx, dword [buff_list+eax*4] |
cmp [ctrl.user_callback], 0 |
je .done |
stdcall [ctrl.user_callback], ebx |
.done: |
pop eax |
and eax, 0x40 |
mov edx, CTRL_STAT |
call [ctrl.ctrl_write32] |
or eax, 1 |
ret |
.skip: |
mov edx, PCM_OUT_CR_REG |
mov ax, 0x11 ;0x1D |
call [ctrl.ctrl_write8] |
jmp .done |
endp |
align 4 |
proc create_primary_buff |
stdcall KernelAlloc, 0x10000 |
mov [ctrl.buffer], eax |
mov edi, eax |
mov ecx, 0x10000/4 |
xor eax, eax |
cld |
rep stosd |
mov eax, [ctrl.buffer] |
call GetPgAddr |
mov ebx, 0xC0002000 |
mov ecx, 4 |
mov edi, pcmout_bdl |
@@: |
mov [edi], eax |
mov [edi+4], ebx |
mov [edi+32], eax |
mov [edi+4+32], ebx |
mov [edi+64], eax |
mov [edi+4+64], ebx |
mov [edi+96], eax |
mov [edi+4+96], ebx |
mov [edi+128], eax |
mov [edi+4+128], ebx |
mov [edi+160], eax |
mov [edi+4+160], ebx |
mov [edi+192], eax |
mov [edi+4+192], ebx |
mov [edi+224], eax |
mov [edi+4+224], ebx |
add eax, 0x4000 |
add edi, 8 |
loop @B |
mov edi, buff_list |
mov eax, [ctrl.buffer] |
mov ecx, 4 |
@@: |
mov [edi], eax |
mov [edi+16], eax |
mov [edi+32], eax |
mov [edi+48], eax |
mov [edi+64], eax |
mov [edi+80], eax |
mov [edi+96], eax |
mov [edi+112], eax |
add eax, 0x4000 |
add edi, 4 |
loop @B |
mov eax, pcmout_bdl |
mov ebx, eax |
call GetPgAddr ;eax |
and ebx, 0xFFF |
add eax, ebx |
mov edx, PCM_OUT_BDL |
call [ctrl.ctrl_write32] |
mov eax, 16 |
mov [ctrl.lvi_reg], eax |
mov edx, PCM_OUT_LVI_REG |
call [ctrl.ctrl_write8] |
ret |
endp |
align 4 |
proc detect_controller |
locals |
last_bus dd ? |
bus dd ? |
devfn dd ? |
endl |
xor eax, eax |
mov [bus], eax |
inc eax |
call PciApi |
cmp eax, -1 |
je .err |
mov [last_bus], eax |
.next_bus: |
and [devfn], 0 |
.next_dev: |
stdcall PciRead32, [bus], [devfn], dword 0 |
test eax, eax |
jz .next |
cmp eax, -1 |
je .next |
mov edi, devices |
@@: |
mov ebx, [edi] |
test ebx, ebx |
jz .next |
cmp eax, ebx |
je .found |
add edi, 12 |
jmp @B |
.next: |
inc [devfn] |
cmp [devfn], 256 |
jb .next_dev |
mov eax, [bus] |
inc eax |
mov [bus], eax |
cmp eax, [last_bus] |
jna .next_bus |
xor eax, eax |
ret |
.found: |
mov ebx, [bus] |
mov [ctrl.bus], ebx |
mov ecx, [devfn] |
mov [ctrl.devfn], ecx |
mov edx, eax |
and edx, 0xFFFF |
mov [ctrl.vendor], edx |
shr eax, 16 |
mov [ctrl.dev_id], eax |
mov ebx, [edi+4] |
mov [ctrl.ctrl_ids], ebx |
mov esi, [edi+8] |
mov [ctrl.ctrl_setup], esi |
cmp edx, VID_INTEL |
jne @F |
mov [ctrl.vendor_ids], msg_Intel |
ret |
@@: |
cmp edx, VID_NVIDIA |
jne @F |
mov [ctrl.vendor_ids], msg_NVidia |
ret |
@@: |
.err: |
xor eax, eax |
mov [ctrl.vendor_ids], eax ;something wrong ? |
ret |
endp |
align 4 |
proc init_controller |
stdcall PciRead32, [ctrl.bus], [ctrl.devfn], dword 4 |
mov ebx, eax |
and eax, 0xFFFF |
mov [ctrl.pci_cmd], eax |
shr ebx, 16 |
mov [ctrl.pci_stat], ebx |
mov esi, msgPciCmd |
call SysMsgBoardStr |
call dword2str |
call SysMsgBoardStr |
mov esi, msgPciStat |
call SysMsgBoardStr |
mov eax, [ctrl.pci_stat] |
call dword2str |
call SysMsgBoardStr |
mov esi, msgMixIsaIo |
call SysMsgBoardStr |
stdcall PciRead32, [ctrl.bus], [ctrl.devfn], dword 0x10 |
call dword2str |
call SysMsgBoardStr |
and eax, 0xFFFE |
mov [ctrl.codec_io_base], eax |
mov esi, msgCtrlIsaIo |
call SysMsgBoardStr |
stdcall PciRead32, [ctrl.bus], [ctrl.devfn], dword 0x14 |
call dword2str |
call SysMsgBoardStr |
and eax, 0xFFC0 |
mov [ctrl.ctrl_io_base], eax |
mov esi, msgMixMMIo |
call SysMsgBoardStr |
stdcall PciRead32, [ctrl.bus], [ctrl.devfn], dword 0x18 |
mov [ctrl.codec_mem_base], eax |
call dword2str |
call SysMsgBoardStr |
mov esi, msgCtrlMMIo |
call SysMsgBoardStr |
stdcall PciRead32, [ctrl.bus], [ctrl.devfn], dword 0x1C |
mov [ctrl.ctrl_mem_base], eax |
call dword2str |
call SysMsgBoardStr |
if 0 |
;;patch for some ugly BIOS ICH-ICH5 compatible |
cmp [ctrl.vendor], VID_INTEL |
jne .default |
mov esi, msgIrqMap |
call SysMsgBoardStr |
stdcall PciRead8, 0, 0xF8, 0x61 |
and eax, 0xFF |
call dword2str |
call SysMsgBoardStr |
btr eax, 7 ;when bit 7 set remap disabled |
jnc @F |
xor eax, eax |
jmp @F |
end if |
.default: |
stdcall PciRead32, [ctrl.bus], [ctrl.devfn], dword 0x3C |
and eax, 0xFF |
@@: |
mov [ctrl.int_line], eax |
stdcall PciRead8, [ctrl.bus], [ctrl.devfn], dword 0x41 |
and eax, 0xFF |
mov [ctrl.cfg_reg], eax |
mov [ctrl.user_callback], 0 |
call [ctrl.ctrl_setup] |
xor eax, eax |
inc eax |
ret |
endp |
align 4 |
proc set_ICH |
mov [ctrl.codec_read16], codec_io_r16 ;virtual |
mov [ctrl.codec_write16], codec_io_w16 ;virtual |
mov [ctrl.ctrl_read8 ], ctrl_io_r8 ;virtual |
mov [ctrl.ctrl_read16], ctrl_io_r16 ;virtual |
mov [ctrl.ctrl_read32], ctrl_io_r32 ;virtual |
mov [ctrl.ctrl_write8 ], ctrl_io_w8 ;virtual |
mov [ctrl.ctrl_write16], ctrl_io_w16 ;virtual |
mov [ctrl.ctrl_write32], ctrl_io_w32 ;virtual |
ret |
endp |
PG_SW equ 0x003 |
PG_NOCACHE equ 0x018 |
align 4 |
proc set_ICH4 |
stdcall MapIoMem, [ctrl.codec_mem_base], 0x1000, PG_SW+PG_NOCACHE |
mov [ctrl.codec_mem_base], eax |
stdcall MapIoMem, [ctrl.ctrl_mem_base], 0x1000, PG_SW+PG_NOCACHE |
mov [ctrl.ctrl_mem_base], eax |
mov [ctrl.codec_read16], codec_mem_r16 ;virtual |
mov [ctrl.codec_write16], codec_mem_w16 ;virtual |
mov [ctrl.ctrl_read8 ], ctrl_mem_r8 ;virtual |
mov [ctrl.ctrl_read16], ctrl_mem_r16 ;virtual |
mov [ctrl.ctrl_read32], ctrl_mem_r32 ;virtual |
mov [ctrl.ctrl_write8 ], ctrl_mem_w8 ;virtual |
mov [ctrl.ctrl_write16], ctrl_mem_w16 ;virtual |
mov [ctrl.ctrl_write32], ctrl_mem_w32 ;virtual |
ret |
endp |
align 4 |
proc reset_controller |
xor eax, eax |
mov edx, PCM_IN_CR_REG |
call [ctrl.ctrl_write8] |
mov edx, PCM_OUT_CR_REG |
call [ctrl.ctrl_write8] |
mov edx, MC_IN_CR_REG |
call [ctrl.ctrl_write8] |
mov eax, RR |
mov edx, PCM_IN_CR_REG |
call [ctrl.ctrl_write8] |
mov edx, PCM_OUT_CR_REG |
call [ctrl.ctrl_write8] |
mov edx, MC_IN_CR_REG |
call [ctrl.ctrl_write8] |
ret |
endp |
align 4 |
proc init_codec |
locals |
counter dd ? |
endl |
mov esi, msgControl |
call SysMsgBoardStr |
mov edx, GLOB_CTRL |
call [ctrl.ctrl_read32] |
call dword2str |
call SysMsgBoardStr |
mov esi, msgStatus |
call SysMsgBoardStr |
mov edx, CTRL_STAT |
call [ctrl.ctrl_read32] |
push eax |
call dword2str |
call SysMsgBoardStr |
pop eax |
cmp eax, 0xFFFFFFFF |
je .err |
test eax, CTRL_ST_CREADY |
jnz .ready |
call reset_codec |
test eax, eax |
jz .err |
.ready: |
xor edx, edx ;ac_reg_0 |
call [ctrl.codec_write16] |
xor eax, eax |
mov edx, CODEC_REG_POWERDOWN |
call [ctrl.codec_write16] |
mov [counter], 200 ; total 200*5 ms = 1s |
.wait: |
mov eax, 5000 ; wait 5 ms |
call StallExec |
mov edx, CODEC_REG_POWERDOWN |
call [ctrl.codec_read16] |
and eax, 0x0F |
cmp eax, 0x0F |
jz .done |
sub [counter] , 1 |
jnz .wait |
.err: |
xor eax, eax ; timeout error |
ret |
.done: |
mov eax, 2 ;force set 16-bit 2-channel PCM |
mov edx, GLOB_CTRL |
call [ctrl.ctrl_write32] |
mov eax, 5000 ; wait 5 ms |
call StallExec |
call detect_codec |
xor eax, eax |
inc eax |
ret |
endp |
align 4 |
proc reset_codec |
mov edx, GLOB_CTRL |
call [ctrl.ctrl_read32] |
test eax, 0x02 |
jz .cold |
call warm_reset |
jnc .ok |
.cold: |
call cold_reset |
jnc .ok |
if DEBUG |
mov esi, msgCFail |
call SysMsgBoardStr |
end if |
xor eax, eax ; timeout error |
ret |
.ok: |
if DEBUG |
mov esi, msgResetOk |
call SysMsgBoardStr |
end if |
xor eax, eax |
inc eax |
ret |
endp |
align 4 |
proc warm_reset |
locals |
counter dd ? |
endl |
mov eax, 0x06 |
mov edx, GLOB_CTRL |
call [ctrl.ctrl_write32] |
if DEBUG |
mov esi, msgWarm |
call SysMsgBoardStr |
end if |
mov [counter], 10 ; total 10*100 ms = 1s |
.wait: |
mov eax, 100000 ; wait 100 ms |
call StallExec |
mov edx, CTRL_STAT |
call [ctrl.ctrl_read32] |
test eax, CTRL_ST_CREADY |
jnz .ok |
dec [counter] |
jnz .wait |
if DEBUG |
mov esi, msgWRFail |
call SysMsgBoardStr |
end if |
.fail: |
stc |
ret |
.ok: |
clc |
ret |
endp |
align 4 |
proc cold_reset |
locals |
counter dd ? |
endl |
mov eax, 0x02 |
mov edx, GLOB_CTRL |
call [ctrl.ctrl_write32] |
if DEBUG |
mov esi, msgCold |
call SysMsgBoardStr |
end if |
mov eax, 400000 ; wait 400 ms |
call StallExec |
mov [counter], 16 ; total 20*100 ms = 2s |
.wait: |
mov edx, CTRL_STAT |
call [ctrl.ctrl_read32] |
test eax, CTRL_ST_CREADY |
jnz .ok |
mov eax, 100000 ; wait 100 ms |
call StallExec |
dec [counter] |
jnz .wait |
if DEBUG |
mov esi, msgCRFail |
call SysMsgBoardStr |
end if |
.fail: |
stc |
ret |
.ok: |
mov esi, msgControl |
call SysMsgBoardStr |
mov edx, GLOB_CTRL |
call [ctrl.ctrl_read32] |
call dword2str |
call SysMsgBoardStr |
mov esi, msgStatus |
call SysMsgBoardStr |
mov edx, CTRL_STAT |
call [ctrl.ctrl_read32] |
push eax |
call dword2str |
call SysMsgBoardStr |
pop eax |
test eax, CTRL_ST_CREADY |
jz .fail |
clc |
ret |
endp |
align 4 |
play: |
mov eax, 16 |
mov [ctrl.lvi_reg], eax |
mov edx, PCM_OUT_LVI_REG |
call [ctrl.ctrl_write8] |
mov edx, PCM_OUT_CR_REG |
mov ax, 0x1D |
call [ctrl.ctrl_write8] |
xor eax, eax |
ret |
align 4 |
stop: |
mov edx, PCM_OUT_CR_REG |
mov ax, 0x0 |
call [ctrl.ctrl_write8] |
mov ax, 0x1c |
mov edx, PCM_OUT_SR_REG |
call [ctrl.ctrl_write16] |
xor eax, eax |
ret |
align 4 |
proc get_dev_info stdcall, p_info:dword |
virtual at esi |
CTRL_INFO CTRL_INFO |
end virtual |
mov esi, [p_info] |
mov eax, [ctrl.int_line] |
mov ebx, [ctrl.codec_io_base] |
mov ecx, [ctrl.ctrl_io_base] |
mov edx, [ctrl.codec_mem_base] |
mov edi, [ctrl.ctrl_mem_base] |
mov [CTRL_INFO.irq], eax |
mov [CTRL_INFO.codec_io_base], ebx |
mov [CTRL_INFO.ctrl_io_base], ecx |
mov [CTRL_INFO.codec_mem_base], edx |
mov [CTRL_INFO.ctrl_mem_base], edi |
mov eax, [codec.chip_id] |
mov [CTRL_INFO.codec_id], eax |
mov edx, GLOB_CTRL |
call [ctrl.ctrl_read32] |
mov [CTRL_INFO.glob_cntrl], eax |
mov edx, CTRL_STAT |
call [ctrl.ctrl_read32] |
mov [CTRL_INFO.glob_sta], eax |
mov ebx, [ctrl.pci_cmd] |
mov [CTRL_INFO.pci_cmd], ebx |
ret |
endp |
align 4 |
proc set_callback stdcall, handler:dword |
mov eax, [handler] |
mov [ctrl.user_callback], eax |
ret |
endp |
align 4 |
proc codec_read stdcall, ac_reg:dword ; reg = edx, reval = eax |
mov edx, [ac_reg] |
mov ebx, edx |
shr ebx, 1 |
bt [codec.shadow_flag], ebx |
jc .use_shadow |
call [ctrl.codec_read16] ;change edx !!! |
mov ecx, eax |
mov edx, CTRL_STAT |
call [ctrl.ctrl_read32] |
test eax, CTRL_ST_RCS |
jz .read_ok |
mov edx, CTRL_STAT |
call [ctrl.ctrl_write32] |
xor eax, eax |
not eax ;timeout |
ret |
.read_ok: |
mov edx, [ac_reg] |
mov [codec.regs+edx], cx |
bts [codec.shadow_flag], ebx |
mov eax, ecx |
ret |
.use_shadow: |
movzx eax, word [codec.regs+edx] |
ret |
endp |
align 4 |
proc codec_write stdcall, ac_reg:dword |
push eax |
call check_semafore |
and eax, eax |
jz .err |
pop eax |
mov esi, [ac_reg] |
mov edx, esi |
call [ctrl.codec_write16] |
mov [codec.regs+esi], ax |
shr esi, 1 |
bts [codec.shadow_flag], esi |
ret |
.err: |
pop eax |
ret |
endp |
align 4 |
proc codec_check_ready |
mov edx, CTRL_ST |
call [ctrl.ctrl_read32] |
and eax, CTRL_ST_CREADY |
jz .not_ready |
xor eax, wax |
inc eax |
ret |
.not_ready: |
xor eax, eax |
ret |
endp |
align 4 |
proc check_semafore |
local counter:DWORD |
mov [counter], 100 |
.l1: |
mov edx, CTRL_CAS |
call [ctrl.ctrl_read8] |
and eax, CAS_FLAG |
jz .ok |
mov eax, 1 |
call StallExec |
sub [counter], 1 |
jnz .l1 |
xor eax, eax |
ret |
align 4 |
.ok: |
xor eax, eax |
inc eax |
ret |
endp |
align 4 |
proc StallExec |
push ecx |
push edx |
push ebx |
push eax |
mov ecx, CPU_FREQ |
mul ecx |
mov ebx, eax ;low |
mov ecx, edx ;high |
rdtsc |
add ebx, eax |
adc ecx, edx |
@@: |
rdtsc |
sub eax, ebx |
sbb edx, ecx |
js @B |
pop eax |
pop ebx |
pop edx |
pop ecx |
ret |
endp |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
; CONTROLLER IO functions |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
proc codec_io_r16 |
add edx, [ctrl.codec_io_base] |
in ax, dx |
ret |
endp |
align 4 |
proc codec_io_w16 |
add edx, [ctrl.codec_io_base] |
out dx, ax |
ret |
endp |
align 4 |
proc ctrl_io_r8 |
add edx, [ctrl.ctrl_io_base] |
in al, dx |
ret |
endp |
align 4 |
proc ctrl_io_r16 |
add edx, [ctrl.ctrl_io_base] |
in ax, dx |
ret |
endp |
align 4 |
proc ctrl_io_r32 |
add edx, [ctrl.ctrl_io_base] |
in eax, dx |
ret |
endp |
align 4 |
proc ctrl_io_w8 |
add edx, [ctrl.ctrl_io_base] |
out dx, al |
ret |
endp |
align 4 |
proc ctrl_io_w16 |
add edx, [ctrl.ctrl_io_base] |
out dx, ax |
ret |
endp |
align 4 |
proc ctrl_io_w32 |
add edx, [ctrl.ctrl_io_base] |
out dx, eax |
ret |
endp |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
; MEMORY MAPPED IO (os depended) |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
proc codec_mem_r16 |
add edx, [ctrl.codec_mem_base] |
mov ax, word [edx] |
ret |
endp |
align 4 |
proc codec_mem_w16 |
add edx, [ctrl.codec_mem_base] |
mov word [edx], ax |
ret |
endp |
align 4 |
proc ctrl_mem_r8 |
add edx, [ctrl.ctrl_mem_base] |
mov al, [edx] |
ret |
endp |
align 4 |
proc ctrl_mem_r16 |
add edx, [ctrl.ctrl_mem_base] |
mov ax, [edx] |
ret |
endp |
align 4 |
proc ctrl_mem_r32 |
add edx, [ctrl.ctrl_mem_base] |
mov eax, [edx] |
ret |
endp |
align 4 |
proc ctrl_mem_w8 |
add edx, [ctrl.ctrl_mem_base] |
mov [edx], al |
ret |
endp |
align 4 |
proc ctrl_mem_w16 |
add edx, [ctrl.ctrl_mem_base] |
mov [edx], ax |
ret |
endp |
align 4 |
proc ctrl_mem_w32 |
add edx, [ctrl.ctrl_mem_base] |
mov [edx], eax |
ret |
endp |
align 4 |
dword2str: |
mov esi, hex_buff |
mov ecx, -8 |
@@: |
rol eax, 4 |
mov ebx, eax |
and ebx, 0x0F |
mov bl, [ebx+hexletters] |
mov [8+esi+ecx], bl |
inc ecx |
jnz @B |
ret |
hexletters db '0123456789ABCDEF' |
hex_buff db 8 dup(0),13,10,0 |
include "codec.inc" |
align 4 |
devices dd (CTRL_ICH shl 16)+VID_INTEL,msg_ICH, set_ICH |
dd (CTRL_ICH0 shl 16)+VID_INTEL,msg_ICH0,set_ICH |
dd (CTRL_ICH2 shl 16)+VID_INTEL,msg_ICH2,set_ICH |
dd (CTRL_ICH3 shl 16)+VID_INTEL,msg_ICH3,set_ICH |
dd (CTRL_ICH4 shl 16)+VID_INTEL,msg_ICH4,set_ICH4 |
dd (CTRL_ICH5 shl 16)+VID_INTEL,msg_ICH5,set_ICH4 |
dd (CTRL_ICH6 shl 16)+VID_INTEL,msg_ICH6,set_ICH4 |
dd (CTRL_ICH7 shl 16)+VID_INTEL,msg_ICH7,set_ICH4 |
dd (CTRL_NFORCE shl 16)+VID_NVIDIA,msg_NForce, set_ICH |
dd (CTRL_NFORCE2 shl 16)+VID_NVIDIA,msg_NForce2,set_ICH |
dd (CTRL_NFORCE3 shl 16)+VID_NVIDIA,msg_NForce3,set_ICH |
dd (CTRL_MCP04 shl 16)+VID_NVIDIA,msg_MCP04,set_ICH |
dd (CTRL_CK804 shl 16)+VID_NVIDIA,msg_CK804,set_ICH |
dd (CTRL_CK8 shl 16)+VID_NVIDIA,msg_CK8,set_ICH |
dd (CTRL_CK8S shl 16)+VID_NVIDIA,msg_CK8S,set_ICH |
dd (CTRL_MCP51 shl 16)+VID_NVIDIA,msg_MCP51,set_ICH |
dd 0 ;terminator |
version dd (5 shl 16) or (API_VERSION and 0xFFFF) |
msg_ICH db '802801AA (ICH)', 13,10, 0 |
msg_ICH0 db '802801AB (ICH0)', 13,10, 0 |
msg_ICH2 db '802801BA (ICH2)', 13,10, 0 |
msg_ICH3 db '802801CA (ICH3)', 13,10, 0 |
msg_ICH4 db '802801DB (ICH4)', 13,10, 0 |
msg_ICH5 db '802801EB (ICH5)', 13,10, 0 |
msg_ICH6 db '802801FB (ICH6)', 13,10, 0 |
msg_ICH7 db '802801GB (ICH7)', 13,10, 0 |
msg_Intel db 'Intel ', 0 |
msg_NForce db 'NForce', 13,10, 0 |
msg_NForce2 db 'NForce 2', 13,10, 0 |
msg_NForce3 db 'NForce 3', 13,10, 0 |
msg_MCP04 db 'NForce MCP04',13,10, 0 |
msg_CK804 db 'NForce CK804',13,10, 0 |
msg_CK8 db 'NForce CK8', 13,10, 0 |
msg_CK8S db 'NForce CK8S', 13,10, 0 |
msg_MCP51 db 'NForce MCP51',13,10, 0 |
msg_NVidia db 'NVidia', 0 |
szKernel db 'KERNEL', 0 |
sz_sound_srv db 'SOUND',0 |
msgInit db 'detect hardware...',13,10,0 |
msgFail db 'device not found',13,10,0 |
msgAttchIRQ db 'IRQ line not supported', 13,10, 0 |
msgInvIRQ db 'IRQ line not assigned or invalid', 13,10, 0 |
msgPlay db 'start play', 13,10,0 |
msgStop db 'stop play', 13,10,0 |
;msgNotify db 'call notify',13,10,0 |
msgIRQ db 'AC97 IRQ', 13,10,0 |
msgInitCtrl db 'init controller',13,10,0 |
;msgInitCodec db 'init codec',13,10,0 |
msgPrimBuff db 'create primary buffer ...',0 |
msgDone db 'done',13,10,0 |
msgRemap db 'Remap IRQ',13,10,0 |
;msgReg db 'set service handler',13,10,0 |
msgOk db 'service installed',13,10,0 |
msgCold db 'cold reset',13,10,0 |
msgWarm db 'warm reset',13,10,0 |
msgWRFail db 'warm reset failed',13,10,0 |
msgCRFail db 'cold reset failed',13,10,0 |
msgCFail db 'codec not ready',13,10,0 |
msgResetOk db 'reset complete',13,10,0 |
msgStatus db 'global status ',0 |
msgControl db 'global control ',0 |
msgPciCmd db 'PCI command ',0 |
msgPciStat db 'PCI status ',0 |
msgCtrlIsaIo db 'controller io base ',0 |
msgMixIsaIo db 'codec io base ',0 |
msgCtrlMMIo db 'controller mmio base ',0 |
msgMixMMIo db 'codec mmio base ',0 |
msgIrqMap db 'AC97 irq map as ',0 |
section '.data' data readable writable align 16 |
pcmout_bdl rq 32 |
buff_list rd 32 |
codec CODEC |
ctrl AC_CNTRL |
lpc_bus rd 1 |
civ_val rd 1 |
/kernel/branches/Kolibri-acpi/drivers/sis.asm |
---|
0,0 → 1,1307 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
format MS COFF |
DEBUG equ 1 |
include 'proc32.inc' |
include 'imports.inc' |
API_VERSION equ 0x01000100 |
DEBUG_IRQ equ 0 |
USE_COM_IRQ equ 0 ;make irq 3 and irq 4 available for PCI devices |
IRQ_REMAP equ 0 |
IRQ_LINE equ 0 |
;irq 0,1,2,8,12,13 недоступны |
; FEDCBA9876543210 |
VALID_IRQ equ 1100111011111000b |
ATTCH_IRQ equ 0000111010100000b |
if USE_COM_IRQ |
ATTCH_IRQ equ 0000111010111000b |
end if |
CPU_FREQ equ 2600d |
BIT0 EQU 0x00000001 |
BIT1 EQU 0x00000002 |
BIT2 EQU 0x00000004 |
BIT3 EQU 0x00000008 |
BIT4 EQU 0x00000010 |
BIT5 EQU 0x00000020 |
BIT6 EQU 0x00000040 |
BIT7 EQU 0x00000080 |
BIT8 EQU 0x00000100 |
BIT9 EQU 0x00000200 |
BIT10 EQU 0x00000400 |
BIT11 EQU 0x00000800 |
BIT12 EQU 0x00001000 |
BIT13 EQU 0x00002000 |
BIT14 EQU 0x00004000 |
BIT15 EQU 0x00008000 |
BIT16 EQU 0x00010000 |
BIT17 EQU 0x00020000 |
BIT18 EQU 0x00040000 |
BIT19 EQU 0x00080000 |
BIT20 EQU 0x00100000 |
BIT21 EQU 0x00200000 |
BIT22 EQU 0x00400000 |
BIT23 EQU 0x00800000 |
BIT24 EQU 0x00100000 |
BIT25 EQU 0x02000000 |
BIT26 EQU 0x04000000 |
BIT27 EQU 0x08000000 |
BIT28 EQU 0x10000000 |
BIT29 EQU 0x20000000 |
BIT30 EQU 0x40000000 |
BIT31 EQU 0x80000000 |
VID_SIS equ 0x1039 |
CTRL_SIS equ 0x7012 |
PCM_OUT_BDL equ 0x10 ; PCM out buffer descriptors list |
PCM_OUT_CR_REG equ 0x1b ; PCM out Control Register |
PCM_OUT_LVI_REG equ 0x15 ; PCM last valid index |
PCM_OUT_SR_REG equ 0x18 ; PCM out Status register |
PCM_OUT_PIV_REG equ 0x1a ; PCM out prefetched index |
PCM_OUT_CIV_REG equ 0x14 ; PCM out current index |
PCM_IN_CR_REG equ 0x0b ; PCM in Control Register |
MC_IN_CR_REG equ 0x2b ; MIC in Control Register |
RR equ BIT1 ; reset registers. Nukes all regs |
CODEC_MASTER_VOL_REG equ 0x02 |
CODEC_AUX_VOL equ 0x04 ; |
CODEC_PCM_OUT_REG equ 0x18 ; PCM output volume |
CODEC_EXT_AUDIO_REG equ 0x28 ; extended audio |
CODEC_EXT_AUDIO_CTRL_REG equ 0x2a ; extended audio control |
CODEC_PCM_FRONT_DACRATE_REG equ 0x2c ; PCM out sample rate |
CODEC_PCM_SURND_DACRATE_REG equ 0x2e ; surround sound sample rate |
CODEC_PCM_LFE_DACRATE_REG equ 0x30 ; LFE sample rate |
GLOB_CTRL equ 0x2C ; Global Control |
CTRL_STAT equ 0x30 ; Global Status |
CTRL_CAS equ 0x34 ; Codec Access Semiphore |
CAS_FLAG equ 0x01 ; Codec Access Semiphore Bit |
CTRL_ST_CREADY equ BIT8+BIT9+BIT28 ; Primary Codec Ready |
CTRL_ST_RCS equ 0x00008000 ; Read Completion Status |
CTRL_CNT_CRIE equ BIT4+BIT5+BIT6 ; Codecs Resume Interrupt Enable |
CTRL_CNT_AC_OFF equ 0x00000008 ; ACLINK Off |
CTRL_CNT_WARM equ 0x00000004 ; AC97 Warm Reset |
CTRL_CNT_COLD equ 0x00000002 ; AC97 Cold Reset |
CTRL_CNT_GIE equ 0x00000001 ; GPI Interrupt Enable |
CODEC_REG_POWERDOWN equ 0x26 |
CODEC_REG_ST equ 0x26 |
SRV_GETVERSION equ 0 |
DEV_PLAY equ 1 |
DEV_STOP equ 2 |
DEV_CALLBACK equ 3 |
DEV_SET_BUFF equ 4 |
DEV_NOTIFY equ 5 |
DEV_SET_MASTERVOL equ 6 |
DEV_GET_MASTERVOL equ 7 |
DEV_GET_INFO equ 8 |
struc AC_CNTRL ;AC controller base class |
{ .bus dd ? |
.devfn dd ? |
.vendor dd ? |
.dev_id dd ? |
.pci_cmd dd ? |
.pci_stat dd ? |
.codec_io_base dd ? |
.codec_mem_base dd ? |
.ctrl_io_base dd ? |
.ctrl_mem_base dd ? |
.cfg_reg dd ? |
.int_line dd ? |
.vendor_ids dd ? ;vendor id string |
.ctrl_ids dd ? ;hub id string |
.buffer dd ? |
.notify_pos dd ? |
.notify_task dd ? |
.lvi_reg dd ? |
.ctrl_setup dd ? |
.user_callback dd ? |
.codec_read16 dd ? |
.codec_write16 dd ? |
.ctrl_read8 dd ? |
.ctrl_read16 dd ? |
.ctrl_read32 dd ? |
.ctrl_write8 dd ? |
.ctrl_write16 dd ? |
.ctrl_write32 dd ? |
} |
struc CODEC ;Audio Chip base class |
{ |
.chip_id dd ? |
.flags dd ? |
.status dd ? |
.ac_vendor_ids dd ? ;ac vendor id string |
.chip_ids dd ? ;chip model string |
.shadow_flag dd ? |
dd ? |
.regs dw ? ; codec registers |
.reg_master_vol dw ? ;0x02 |
.reg_aux_out_vol dw ? ;0x04 |
.reg_mone_vol dw ? ;0x06 |
.reg_master_tone dw ? ;0x08 |
.reg_beep_vol dw ? ;0x0A |
.reg_phone_vol dw ? ;0x0C |
.reg_mic_vol dw ? ;0x0E |
.reg_line_in_vol dw ? ;0x10 |
.reg_cd_vol dw ? ;0x12 |
.reg_video_vol dw ? ;0x14 |
.reg_aux_in_vol dw ? ;0x16 |
.reg_pcm_out_vol dw ? ;0x18 |
.reg_rec_select dw ? ;0x1A |
.reg_rec_gain dw ? ;0x1C |
.reg_rec_gain_mic dw ? ;0x1E |
.reg_gen dw ? ;0x20 |
.reg_3d_ctrl dw ? ;0X22 |
.reg_page dw ? ;0X24 |
.reg_powerdown dw ? ;0x26 |
.reg_ext_audio dw ? ;0x28 |
.reg_ext_st dw ? ;0x2a |
.reg_pcm_front_rate dw ? ;0x2c |
.reg_pcm_surr_rate dw ? ;0x2e |
.reg_lfe_rate dw ? ;0x30 |
.reg_pcm_in_rate dw ? ;0x32 |
dw ? ;0x34 |
.reg_cent_lfe_vol dw ? ;0x36 |
.reg_surr_vol dw ? ;0x38 |
.reg_spdif_ctrl dw ? ;0x3A |
dw ? ;0x3C |
dw ? ;0x3E |
dw ? ;0x40 |
dw ? ;0x42 |
dw ? ;0x44 |
dw ? ;0x46 |
dw ? ;0x48 |
dw ? ;0x4A |
dw ? ;0x4C |
dw ? ;0x4E |
dw ? ;0x50 |
dw ? ;0x52 |
dw ? ;0x54 |
dw ? ;0x56 |
dw ? ;0x58 |
dw ? ;0x5A |
dw ? ;0x5C |
dw ? ;0x5E |
.reg_page_0 dw ? ;0x60 |
.reg_page_1 dw ? ;0x62 |
.reg_page_2 dw ? ;0x64 |
.reg_page_3 dw ? ;0x66 |
.reg_page_4 dw ? ;0x68 |
.reg_page_5 dw ? ;0x6A |
.reg_page_6 dw ? ;0x6C |
.reg_page_7 dw ? ;0x6E |
dw ? ;0x70 |
dw ? ;0x72 |
dw ? ;0x74 |
dw ? ;0x76 |
dw ? ;0x78 |
dw ? ;0x7A |
.reg_vendor_id_1 dw ? ;0x7C |
.reg_vendor_id_2 dw ? ;0x7E |
.reset dd ? ;virual |
.set_master_vol dd ? |
} |
struc CTRL_INFO |
{ .pci_cmd dd ? |
.irq dd ? |
.glob_cntrl dd ? |
.glob_sta dd ? |
.codec_io_base dd ? |
.ctrl_io_base dd ? |
.codec_mem_base dd ? |
.ctrl_mem_base dd ? |
.codec_id dd ? |
} |
struc IOCTL |
{ .handle dd ? |
.io_code dd ? |
.input dd ? |
.inp_size dd ? |
.output dd ? |
.out_size dd ? |
} |
virtual at 0 |
IOCTL IOCTL |
end virtual |
EVENT_NOTIFY equ 0x00000200 |
public START |
public service_proc |
public version |
section '.flat' code readable align 16 |
proc START stdcall, state:dword |
cmp [state], 1 |
jne .stop |
if DEBUG |
mov esi, msgInit |
call SysMsgBoardStr |
end if |
call detect_controller |
test eax, eax |
jz .fail |
if DEBUG |
mov esi, [ctrl.vendor_ids] |
call SysMsgBoardStr |
mov esi, [ctrl.ctrl_ids] |
call SysMsgBoardStr |
end if |
call init_controller |
test eax, eax |
jz .fail |
call init_codec |
test eax, eax |
jz .fail |
call reset_controller |
call setup_codec |
mov esi, msgPrimBuff |
call SysMsgBoardStr |
call create_primary_buff |
mov esi, msgDone |
call SysMsgBoardStr |
if IRQ_REMAP |
pushf |
cli |
mov ebx, [ctrl.int_line] |
in al, 0xA1 |
mov ah, al |
in al, 0x21 |
test ebx, ebx |
jz .skip |
bts ax, bx ;mask old line |
.skip |
bts ax, IRQ_LINE ;mask new ine |
out 0x21, al |
mov al, ah |
out 0xA1, al |
;remap IRQ |
stdcall PciWrite8, 0, 0xF8, 0x61, IRQ_LINE |
mov dx, 0x4d0 ;8259 ELCR1 |
in al, dx |
bts ax, IRQ_LINE |
out dx, al ;set level-triggered mode |
mov [ctrl.int_line], IRQ_LINE |
popf |
mov esi, msgRemap |
call SysMsgBoardStr |
end if |
mov eax, VALID_IRQ |
mov ebx, [ctrl.int_line] |
mov esi, msgInvIRQ |
bt eax, ebx |
jnc .fail_msg |
mov eax, ATTCH_IRQ |
mov esi, msgAttchIRQ |
bt eax, ebx |
jnc .fail_msg |
stdcall AttachIntHandler, ebx, ac97_irq, dword 0 |
.reg: |
stdcall RegService, sz_sound_srv, service_proc |
ret |
.fail: |
if DEBUG |
mov esi, msgFail |
call SysMsgBoardStr |
end if |
xor eax, eax |
ret |
.fail_msg: |
call SysMsgBoardStr |
xor eax, eax |
ret |
.stop: |
call stop |
xor eax, eax |
ret |
endp |
handle equ IOCTL.handle |
io_code equ IOCTL.io_code |
input equ IOCTL.input |
inp_size equ IOCTL.inp_size |
output equ IOCTL.output |
out_size equ IOCTL.out_size |
align 4 |
proc service_proc stdcall, ioctl:dword |
mov edi, [ioctl] |
mov eax, [edi+io_code] |
cmp eax, SRV_GETVERSION |
jne @F |
mov eax, [edi+output] |
cmp [edi+out_size], 4 |
jne .fail |
mov [eax], dword API_VERSION |
xor eax, eax |
ret |
@@: |
cmp eax, DEV_PLAY |
jne @F |
if DEBUG |
mov esi, msgPlay |
call SysMsgBoardStr |
end if |
call play |
ret |
@@: |
cmp eax, DEV_STOP |
jne @F |
if DEBUG |
mov esi, msgStop |
call SysMsgBoardStr |
end if |
call stop |
ret |
@@: |
cmp eax, DEV_CALLBACK |
jne @F |
mov ebx, [edi+input] |
stdcall set_callback, [ebx] |
ret |
@@: |
cmp eax, DEV_SET_MASTERVOL |
jne @F |
mov eax, [edi+input] |
mov eax, [eax] |
call set_master_vol ;eax= vol |
ret |
@@: |
cmp eax, DEV_GET_MASTERVOL |
jne @F |
mov ebx, [edi+output] |
stdcall get_master_vol, ebx |
ret |
;@@: |
; cmp eax, DEV_GET_INFO |
; jne @F |
; mov ebx, [edi+output] |
; stdcall get_dev_info, ebx |
; ret |
@@: |
.fail: |
or eax, -1 |
ret |
endp |
restore handle |
restore io_code |
restore input |
restore inp_size |
restore output |
restore out_size |
align 4 |
proc ac97_irq |
if DEBUG_IRQ |
mov esi, msgIRQ |
call SysMsgBoardStr |
end if |
mov edx, PCM_OUT_CR_REG |
mov al, 0x10 |
call [ctrl.ctrl_write8] |
mov ax, 0x1c |
mov edx, PCM_OUT_SR_REG |
call [ctrl.ctrl_write16] |
mov edx, PCM_OUT_CIV_REG |
call [ctrl.ctrl_read8] |
and eax, 0x1F |
cmp eax, [civ_val] |
je .skip |
mov [civ_val], eax |
dec eax |
and eax, 0x1F |
mov [ctrl.lvi_reg], eax |
mov edx, PCM_OUT_LVI_REG |
call [ctrl.ctrl_write8] |
mov edx, PCM_OUT_CR_REG |
mov ax, 0x11 |
call [ctrl.ctrl_write8] |
mov eax, [civ_val] |
add eax, 1 |
and eax, 31 |
mov ebx, dword [buff_list+eax*4] |
cmp [ctrl.user_callback], 0 |
je @f |
stdcall [ctrl.user_callback], ebx |
@@: |
ret |
.skip: |
mov edx, PCM_OUT_CR_REG |
mov ax, 0x11 |
call [ctrl.ctrl_write8] |
ret |
endp |
align 4 |
proc create_primary_buff |
stdcall KernelAlloc, 0x10000 |
mov [ctrl.buffer], eax |
mov edi, eax |
mov ecx, 0x10000/4 |
xor eax, eax |
cld |
rep stosd |
mov eax, [ctrl.buffer] |
call GetPgAddr |
mov ebx, 0xC0004000 |
mov ecx, 4 |
mov edi, pcmout_bdl |
@@: |
mov [edi], eax |
mov [edi+4], ebx |
mov [edi+32], eax |
mov [edi+4+32], ebx |
mov [edi+64], eax |
mov [edi+4+64], ebx |
mov [edi+96], eax |
mov [edi+4+96], ebx |
mov [edi+128], eax |
mov [edi+4+128], ebx |
mov [edi+160], eax |
mov [edi+4+160], ebx |
mov [edi+192], eax |
mov [edi+4+192], ebx |
mov [edi+224], eax |
mov [edi+4+224], ebx |
add eax, 0x4000 |
add edi, 8 |
loop @B |
mov edi, buff_list |
mov eax, [ctrl.buffer] |
mov ecx, 4 |
@@: |
mov [edi], eax |
mov [edi+16], eax |
mov [edi+32], eax |
mov [edi+48], eax |
mov [edi+64], eax |
mov [edi+80], eax |
mov [edi+96], eax |
mov [edi+112], eax |
add eax, 0x4000 |
add edi, 4 |
loop @B |
mov eax, pcmout_bdl |
mov ebx, eax |
call GetPgAddr ;eax |
and ebx, 0xFFF |
add eax, ebx |
mov edx, PCM_OUT_BDL |
call [ctrl.ctrl_write32] |
mov eax, 16 |
mov [ctrl.lvi_reg], eax |
mov edx, PCM_OUT_LVI_REG |
call [ctrl.ctrl_write8] |
mov edx, GLOB_CTRL |
call [ctrl.ctrl_read32] |
and eax, not 0x000000C0 |
mov edx, GLOB_CTRL |
call [ctrl.ctrl_write32] |
ret |
endp |
align 4 |
proc detect_controller |
locals |
last_bus dd ? |
bus dd ? |
devfn dd ? |
endl |
xor eax, eax |
mov [bus], eax |
inc eax |
call PciApi |
cmp eax, -1 |
je .err |
mov [last_bus], eax |
.next_bus: |
and [devfn], 0 |
.next_dev: |
stdcall PciRead32, [bus], [devfn], dword 0 |
test eax, eax |
jz .next |
cmp eax, -1 |
je .next |
mov edi, devices |
@@: |
mov ebx, [edi] |
test ebx, ebx |
jz .next |
cmp eax, ebx |
je .found |
add edi, 12 |
jmp @B |
.next: |
inc [devfn] |
cmp [devfn], 256 |
jb .next_dev |
mov eax, [bus] |
inc eax |
mov [bus], eax |
cmp eax, [last_bus] |
jna .next_bus |
xor eax, eax |
ret |
.found: |
mov ebx, [bus] |
mov [ctrl.bus], ebx |
mov ecx, [devfn] |
mov [ctrl.devfn], ecx |
mov edx, eax |
and edx, 0xFFFF |
mov [ctrl.vendor], edx |
shr eax, 16 |
mov [ctrl.dev_id], eax |
mov ebx, [edi+4] |
mov [ctrl.ctrl_ids], ebx |
mov [ctrl.vendor_ids], msg_SIS |
mov esi, [edi+8] |
mov [ctrl.ctrl_setup], esi |
ret |
.err: |
xor eax, eax |
ret |
endp |
align 4 |
proc init_controller |
stdcall PciRead32, [ctrl.bus], [ctrl.devfn], dword 4 |
mov ebx, eax |
and eax, 0xFFFF |
mov [ctrl.pci_cmd], eax |
shr ebx, 16 |
mov [ctrl.pci_stat], ebx |
mov esi, msgPciCmd |
call SysMsgBoardStr |
call dword2str |
call SysMsgBoardStr |
mov esi, msgPciStat |
call SysMsgBoardStr |
mov eax, [ctrl.pci_stat] |
call dword2str |
call SysMsgBoardStr |
mov esi, msgMixIsaIo |
call SysMsgBoardStr |
stdcall PciRead32, [ctrl.bus], [ctrl.devfn], dword 0x10 |
call dword2str |
call SysMsgBoardStr |
and eax, 0xFFFE |
mov [ctrl.codec_io_base], eax |
mov esi, msgCtrlIsaIo |
call SysMsgBoardStr |
stdcall PciRead32, [ctrl.bus], [ctrl.devfn], dword 0x14 |
call dword2str |
call SysMsgBoardStr |
and eax, 0xFFC0 |
mov [ctrl.ctrl_io_base], eax |
mov esi, msgMixMMIo |
call SysMsgBoardStr |
stdcall PciRead32, [ctrl.bus], [ctrl.devfn], dword 0x18 |
mov [ctrl.codec_mem_base], eax |
call dword2str |
call SysMsgBoardStr |
mov esi, msgCtrlMMIo |
call SysMsgBoardStr |
stdcall PciRead32, [ctrl.bus], [ctrl.devfn], dword 0x1C |
mov [ctrl.ctrl_mem_base], eax |
call dword2str |
call SysMsgBoardStr |
.default: |
stdcall PciRead32, [ctrl.bus], [ctrl.devfn], dword 0x3C |
and eax, 0xFF |
@@: |
mov [ctrl.int_line], eax |
stdcall PciRead8, [ctrl.bus], [ctrl.devfn], dword 0x41 |
and eax, 0xFF |
mov [ctrl.cfg_reg], eax |
call [ctrl.ctrl_setup] |
xor eax, eax |
inc eax |
ret |
endp |
align 4 |
proc set_SIS |
mov [ctrl.codec_read16], codec_io_r16 ;virtual |
mov [ctrl.codec_write16], codec_io_w16 ;virtual |
mov [ctrl.ctrl_read8 ], ctrl_io_r8 ;virtual |
mov [ctrl.ctrl_read16], ctrl_io_r16 ;virtual |
mov [ctrl.ctrl_read32], ctrl_io_r32 ;virtual |
mov [ctrl.ctrl_write8 ], ctrl_io_w8 ;virtual |
mov [ctrl.ctrl_write16], ctrl_io_w16 ;virtual |
mov [ctrl.ctrl_write32], ctrl_io_w32 ;virtual |
ret |
endp |
align 4 |
proc reset_controller |
xor eax, eax |
mov edx, PCM_IN_CR_REG |
call [ctrl.ctrl_write8] |
mov edx, PCM_OUT_CR_REG |
call [ctrl.ctrl_write8] |
mov edx, MC_IN_CR_REG |
call [ctrl.ctrl_write8] |
mov eax, RR |
mov edx, PCM_IN_CR_REG |
call [ctrl.ctrl_write8] |
mov edx, PCM_OUT_CR_REG |
call [ctrl.ctrl_write8] |
mov edx, MC_IN_CR_REG |
call [ctrl.ctrl_write8] |
ret |
endp |
align 4 |
proc init_codec |
locals |
counter dd ? |
endl |
mov esi, msgControl |
call SysMsgBoardStr |
mov edx, GLOB_CTRL |
call [ctrl.ctrl_read32] |
call dword2str |
call SysMsgBoardStr |
mov esi, msgStatus |
call SysMsgBoardStr |
mov edx, CTRL_STAT |
call [ctrl.ctrl_read32] |
push eax |
call dword2str |
call SysMsgBoardStr |
pop eax |
cmp eax, 0xFFFFFFFF |
je .err |
test eax, CTRL_ST_CREADY |
jnz .done ;;;;;.ready |
call reset_codec |
test eax, eax |
jz .err |
.ready: |
xor edx, edx ;ac_reg_0 |
call [ctrl.codec_write16] |
xor eax, eax |
mov edx, CODEC_REG_POWERDOWN |
call [ctrl.codec_write16] |
mov [counter], 200 ; total 200*5 ms = 1s |
.wait: |
mov eax, 5000 ; wait 5 ms |
call StallExec |
mov edx, CODEC_REG_POWERDOWN |
call [ctrl.codec_read16] |
and eax, 0x0F |
cmp eax, 0x0F |
je .done |
sub [counter] , 1 |
jnz .wait |
.err: |
xor eax, eax ; timeout error |
ret |
.done: |
mov eax, 2 ;force set 16-bit 2-channel PCM |
mov edx, GLOB_CTRL |
call [ctrl.ctrl_write32] |
mov eax, 5000 ; wait 5 ms |
call StallExec |
call detect_codec |
xor eax, eax |
inc eax |
ret |
endp |
align 4 |
proc reset_codec |
mov edx, GLOB_CTRL |
call [ctrl.ctrl_read32] |
test eax, 0x02 |
jz .cold |
call warm_reset |
jnc .ok |
.cold: |
call cold_reset |
jnc .ok |
if DEBUG |
mov esi, msgCFail |
call SysMsgBoardStr |
end if |
xor eax, eax ; timeout error |
ret |
.ok: |
xor eax, eax |
inc eax |
ret |
endp |
align 4 |
proc warm_reset |
locals |
counter dd ? |
endl |
mov eax, 0x06 |
mov edx, GLOB_CTRL |
call [ctrl.ctrl_write32] |
if DEBUG |
mov esi, msgWarm |
call SysMsgBoardStr |
end if |
mov [counter], 10 ; total 10*100 ms = 1s |
.wait: |
mov eax, 100000 ; wait 100 ms |
call StallExec |
mov edx, CTRL_STAT |
call [ctrl.ctrl_read32] |
test eax, CTRL_ST_CREADY |
jnz .ok |
dec [counter] |
jnz .wait |
if DEBUG |
mov esi, msgWRFail |
call SysMsgBoardStr |
end if |
.fail: |
stc |
ret |
.ok: |
clc |
ret |
endp |
align 4 |
proc cold_reset |
locals |
counter dd ? |
endl |
mov eax, 0x02 |
mov edx, GLOB_CTRL |
call [ctrl.ctrl_write32] |
if DEBUG |
mov esi, msgCold |
call SysMsgBoardStr |
end if |
mov eax, 400000 ; wait 400 ms |
call StallExec |
mov [counter], 16 ; total 20*100 ms = 2s |
.wait: |
mov edx, CTRL_STAT |
call [ctrl.ctrl_read32] |
test eax, CTRL_ST_CREADY |
jnz .ok |
mov eax, 100000 ; wait 100 ms |
call StallExec |
dec [counter] |
jnz .wait |
if DEBUG |
mov esi, msgCRFail |
call SysMsgBoardStr |
end if |
.fail: |
stc |
ret |
.ok: |
mov esi, msgControl |
call SysMsgBoardStr |
mov edx, GLOB_CTRL |
call [ctrl.ctrl_read32] |
call dword2str |
call SysMsgBoardStr |
mov esi, msgStatus |
call SysMsgBoardStr |
mov edx, CTRL_STAT |
call [ctrl.ctrl_read32] |
push eax |
call dword2str |
call SysMsgBoardStr |
pop eax |
test eax, CTRL_ST_CREADY |
jz .fail |
clc |
ret |
endp |
align 4 |
play: |
xor eax, eax |
mov [civ_val], eax |
mov edx, PCM_OUT_CIV_REG |
call [ctrl.ctrl_write8] |
mov eax, 16 |
mov [ctrl.lvi_reg], eax |
mov edx, PCM_OUT_LVI_REG |
call [ctrl.ctrl_write8] |
mov edx, PCM_OUT_CR_REG |
mov ax, 0x1D |
call [ctrl.ctrl_write8] |
xor eax, eax |
ret |
align 4 |
stop: |
mov edx, PCM_OUT_CR_REG |
mov ax, 0x0 |
call [ctrl.ctrl_write8] |
mov ax, 0x1c |
mov edx, PCM_OUT_SR_REG |
call [ctrl.ctrl_write16] |
xor eax, eax |
ret |
align 4 |
proc get_dev_info stdcall, p_info:dword |
virtual at esi |
CTRL_INFO CTRL_INFO |
end virtual |
mov esi, [p_info] |
mov eax, [ctrl.int_line] |
mov ebx, [ctrl.codec_io_base] |
mov ecx, [ctrl.ctrl_io_base] |
mov edx, [ctrl.codec_mem_base] |
mov edi, [ctrl.ctrl_mem_base] |
mov [CTRL_INFO.irq], eax |
mov [CTRL_INFO.codec_io_base], ebx |
mov [CTRL_INFO.ctrl_io_base], ecx |
mov [CTRL_INFO.codec_mem_base], edx |
mov [CTRL_INFO.ctrl_mem_base], edi |
mov eax, [codec.chip_id] |
mov [CTRL_INFO.codec_id], eax |
mov edx, GLOB_CTRL |
call [ctrl.ctrl_read32] |
mov [CTRL_INFO.glob_cntrl], eax |
mov edx, CTRL_STAT |
call [ctrl.ctrl_read32] |
mov [CTRL_INFO.glob_sta], eax |
mov ebx, [ctrl.pci_cmd] |
mov [CTRL_INFO.pci_cmd], ebx |
ret |
endp |
align 4 |
proc set_callback stdcall, handler:dword |
mov eax, [handler] |
mov [ctrl.user_callback], eax |
ret |
endp |
align 4 |
proc codec_read stdcall, ac_reg:dword ; reg = edx, reval = eax |
mov edx, [ac_reg] |
mov ebx, edx |
shr ebx, 1 |
bt [codec.shadow_flag], ebx |
jc .use_shadow |
call [ctrl.codec_read16] ;change edx !!! |
mov ecx, eax |
mov edx, CTRL_STAT |
call [ctrl.ctrl_read32] |
test eax, CTRL_ST_RCS |
jz .read_ok |
mov edx, CTRL_STAT |
call [ctrl.ctrl_write32] |
xor eax, eax |
not eax ;timeout |
ret |
.read_ok: |
mov edx, [ac_reg] |
mov [codec.regs+edx], cx |
bts [codec.shadow_flag], ebx |
mov eax, ecx |
ret |
.use_shadow: |
movzx eax, word [codec.regs+edx] |
ret |
endp |
align 4 |
proc codec_write stdcall, ac_reg:dword |
push eax |
call check_semafore |
and eax, eax |
jz .err |
pop eax |
mov esi, [ac_reg] |
mov edx, esi |
call [ctrl.codec_write16] |
mov [codec.regs+esi], ax |
shr esi, 1 |
bts [codec.shadow_flag], esi |
ret |
.err: |
pop eax |
ret |
endp |
align 4 |
proc codec_check_ready |
mov edx, CTRL_ST |
call [ctrl.ctrl_read32] |
and eax, CTRL_ST_CREADY |
jz .not_ready |
xor eax, wax |
inc eax |
ret |
.not_ready: |
xor eax, eax |
ret |
endp |
align 4 |
proc check_semafore |
local counter:DWORD |
mov [counter], 100 |
.l1: |
mov edx, CTRL_CAS |
call [ctrl.ctrl_read8] |
and eax, CAS_FLAG |
jz .ok |
mov eax, 1 |
call StallExec |
sub [counter], 1 |
jnz .l1 |
xor eax, eax |
ret |
align 4 |
.ok: |
xor eax, eax |
inc eax |
ret |
endp |
align 4 |
proc StallExec |
push ecx |
push edx |
push ebx |
push eax |
mov ecx, CPU_FREQ |
mul ecx |
mov ebx, eax ;low |
mov ecx, edx ;high |
rdtsc |
add ebx, eax |
adc ecx, edx |
@@: |
rdtsc |
sub eax, ebx |
sbb edx, ecx |
js @B |
pop eax |
pop ebx |
pop edx |
pop ecx |
ret |
endp |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
; CONTROLLER IO functions |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
proc codec_io_r16 |
add edx, [ctrl.codec_io_base] |
in ax, dx |
ret |
endp |
align 4 |
proc codec_io_w16 |
add edx, [ctrl.codec_io_base] |
out dx, ax |
ret |
endp |
align 4 |
proc ctrl_io_r8 |
add edx, [ctrl.ctrl_io_base] |
in al, dx |
ret |
endp |
align 4 |
proc ctrl_io_r16 |
add edx, [ctrl.ctrl_io_base] |
in ax, dx |
ret |
endp |
align 4 |
proc ctrl_io_r32 |
add edx, [ctrl.ctrl_io_base] |
in eax, dx |
ret |
endp |
align 4 |
proc ctrl_io_w8 |
add edx, [ctrl.ctrl_io_base] |
out dx, al |
ret |
endp |
align 4 |
proc ctrl_io_w16 |
add edx, [ctrl.ctrl_io_base] |
out dx, ax |
ret |
endp |
align 4 |
proc ctrl_io_w32 |
add edx, [ctrl.ctrl_io_base] |
out dx, eax |
ret |
endp |
align 4 |
dword2str: |
mov esi, hex_buff |
mov ecx, -8 |
@@: |
rol eax, 4 |
mov ebx, eax |
and ebx, 0x0F |
mov bl, [ebx+hexletters] |
mov [8+esi+ecx], bl |
inc ecx |
jnz @B |
ret |
hexletters db '0123456789ABCDEF' |
hex_buff db 8 dup(0),13,10,0 |
include "codec.inc" |
align 4 |
devices dd (CTRL_SIS shl 16)+VID_SIS,msg_AC, set_SIS |
dd 0 |
version dd (5 shl 16) or (API_VERSION and 0xFFFF) |
msg_AC db '7012 AC97 controller',13,10, 0 |
msg_SIS db 'Silicon Integrated Systems',13,10, 0 |
sz_sound_srv db 'SOUND',0 |
msgInit db 'detect hardware...',13,10,0 |
msgFail db 'device not found',13,10,0 |
msgAttchIRQ db 'IRQ line not supported', 13,10, 0 |
msgInvIRQ db 'IRQ line not assigned or invalid', 13,10, 0 |
msgPlay db 'start play', 13,10,0 |
msgStop db 'stop play', 13,10,0 |
;msgNotify db 'call notify',13,10,0 |
msgIRQ db 'AC97 IRQ', 13,10,0 |
msgInitCtrl db 'init controller',13,10,0 |
;msgInitCodec db 'init codec',13,10,0 |
msgPrimBuff db 'create primary buffer ...',0 |
msgDone db 'done',13,10,0 |
msgRemap db 'Remap IRQ',13,10,0 |
;msgReg db 'set service handler',13,10,0 |
msgOk db 'service installed',13,10,0 |
msgCold db 'cold reset',13,10,0 |
msgWarm db 'warm reset',13,10,0 |
msgWRFail db 'warm reset failed',13,10,0 |
msgCRFail db 'cold reset failed',13,10,0 |
msgCFail db 'codec not ready',13,10,0 |
msgResetOk db 'reset complete',13,10,0 |
msgStatus db 'global status ',0 |
msgControl db 'global control ',0 |
msgPciCmd db 'PCI command ',0 |
msgPciStat db 'PCI status ',0 |
msgCtrlIsaIo db 'controller io base ',0 |
msgMixIsaIo db 'codec io base ',0 |
msgCtrlMMIo db 'controller mmio base ',0 |
msgMixMMIo db 'codec mmio base ',0 |
msgIrqMap db 'AC97 irq map as ',0 |
section '.data' data readable writable align 16 |
pcmout_bdl rq 32 |
buff_list rd 32 |
codec CODEC |
ctrl AC_CNTRL |
lpc_bus rd 1 |
civ_val rd 1 |
/kernel/branches/Kolibri-acpi/drivers/vt823x.asm |
---|
0,0 → 1,1281 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
format MS COFF |
DEBUG equ 1 |
include 'proc32.inc' |
include 'imports.inc' |
API_VERSION equ 0x01000100 |
USE_COM_IRQ equ 0 ;make irq 3 and irq 4 available for PCI devices |
IRQ_REMAP equ 0 |
IRQ_LINE equ 0 |
;irq 0,1,2,8,12,13 недоступны |
; FEDCBA9876543210 |
VALID_IRQ equ 1100111011111000b |
ATTCH_IRQ equ 0000111010100000b |
if USE_COM_IRQ |
ATTCH_IRQ equ 0000111010111000b |
end if |
CPU_FREQ equ 2600d |
BIT0 EQU 0x00000001 |
BIT1 EQU 0x00000002 |
BIT5 EQU 0x00000020 |
BIT10 EQU 0x00000400 |
VID_VIA equ 0x1106 |
CTRL_VT82C686 equ 0x3058 |
CTRL_VT8233_5 equ 0x3059 |
CODEC_MASTER_VOL_REG equ 0x02 |
CODEC_AUX_VOL equ 0x04 ; |
CODEC_PCM_OUT_REG equ 0x18 ; PCM output volume |
CODEC_EXT_AUDIO_REG equ 0x28 ; extended audio |
CODEC_EXT_AUDIO_CTRL_REG equ 0x2a ; extended audio control |
CODEC_PCM_FRONT_DACRATE_REG equ 0x2c ; PCM out sample rate |
CODEC_PCM_SURND_DACRATE_REG equ 0x2e ; surround sound sample rate |
CODEC_PCM_LFE_DACRATE_REG equ 0x30 ; LFE sample rate |
;VIA host controller registers set |
;; common offsets |
VIA_REG_OFFSET_STATUS equ 0x00 ;; byte - channel status |
VIA_REG_STAT_ACTIVE equ 0x80 ;; RO |
VIA_REG_STAT_PAUSED equ 0x40 ;; RO |
VIA_REG_STAT_TRIGGER_QUEUED equ 0x08 ;; RO |
VIA_REG_STAT_STOPPED equ 0x04 ;; RWC |
VIA_REG_STAT_EOL equ 0x02 ;; RWC |
VIA_REG_STAT_FLAG equ 0x01 ;; RWC |
VIA_REG_OFFSET_CONTROL equ 0x01 ;; byte - channel control |
VIA_REG_CTRL_START equ 0x80 ;; WO |
VIA_REG_CTRL_TERMINATE equ 0x40 ;; WO |
VIA_REG_CTRL_AUTOSTART equ 0x20 |
VIA_REG_CTRL_PAUSE equ 0x08 ;; RW |
VIA_REG_CTRL_INT_STOP equ 0x04 |
VIA_REG_CTRL_INT_EOL equ 0x02 |
VIA_REG_CTRL_INT_FLAG equ 0x01 |
VIA_REG_CTRL_RESET equ 0x01 ;; RW - probably reset? undocumented |
VIA_REG_CTRL_INT equ (VIA_REG_CTRL_INT_FLAG or \ |
VIA_REG_CTRL_INT_EOL or \ |
VIA_REG_CTRL_AUTOSTART) |
VIA_REG_OFFSET_TYPE equ 0x02 ;; byte - channel type (686 only) |
VIA_REG_TYPE_AUTOSTART equ 0x80 ;; RW - autostart at EOL |
VIA_REG_TYPE_16BIT equ 0x20 ;; RW |
VIA_REG_TYPE_STEREO equ 0x10 ;; RW |
VIA_REG_TYPE_INT_LLINE equ 0x00 |
VIA_REG_TYPE_INT_LSAMPLE equ 0x04 |
VIA_REG_TYPE_INT_LESSONE equ 0x08 |
VIA_REG_TYPE_INT_MASK equ 0x0c |
VIA_REG_TYPE_INT_EOL equ 0x02 |
VIA_REG_TYPE_INT_FLAG equ 0x01 |
VIA_REG_OFFSET_TABLE_PTR equ 0x04 ;; dword - channel table pointer |
VIA_REG_OFFSET_CURR_PTR equ 0x04 ;; dword - channel current pointer |
VIA_REG_OFFSET_STOP_IDX equ 0x08 ;; dword - stop index, channel type, sample rate |
VIA8233_REG_TYPE_16BIT equ 0x00200000 ;; RW |
VIA8233_REG_TYPE_STEREO equ 0x00100000 ;; RW |
VIA_REG_OFFSET_CURR_COUNT equ 0x0c ;; dword - channel current count (24 bit) |
VIA_REG_OFFSET_CURR_INDEX equ 0x0f ;; byte - channel current index (for via8233 only) |
VIADEV_PLAYBACK equ 0x00 |
VIADEV_CAPTURE equ 0x10 |
VIADEV_FM equ 0x20 |
;; AC'97 ;; |
VIA_REG_AC97 equ 0x80 ; dword |
VIA_REG_AC97_CODEC_ID_MASK equ 0xC0000000 ;(3<<30) |
VIA_REG_AC97_CODEC_ID_SHIFT equ 30 |
VIA_REG_AC97_CODEC_ID_PRIMARY equ 0x00 |
VIA_REG_AC97_CODEC_ID_SECONDARY equ 0x01 |
VIA_REG_AC97_SECONDARY_VALID equ 0x08000000 ;(1<<27) |
VIA_REG_AC97_PRIMARY_VALID equ 0x02000000 ;(1<<25) |
VIA_REG_AC97_BUSY equ 0x01000000 ;(1<<24) |
VIA_REG_AC97_READ equ 0x00800000 ;(1<<23) |
VIA_REG_AC97_CMD_SHIFT equ 16 |
VIA_REG_AC97_CMD_MASK equ 0x7E |
VIA_REG_AC97_DATA_SHIFT equ 0 |
VIA_REG_AC97_DATA_MASK equ 0xFFFF |
VIA_REG_SGD_SHADOW equ 0x84 ; dword |
;; via8233-specific registers ;; |
VIA_REG_OFS_PLAYBACK_VOLUME_L equ 0x02 ;; byte |
VIA_REG_OFS_PLAYBACK_VOLUME_R equ 0x03 ;; byte |
VIA_REG_OFS_MULTPLAY_FORMAT equ 0x02 ;; byte - format and channels |
VIA_REG_MULTPLAY_FMT_8BIT equ 0x00 |
VIA_REG_MULTPLAY_FMT_16BIT equ 0x80 |
VIA_REG_MULTPLAY_FMT_CH_MASK equ 0x70 ;; # channels << 4 (valid = 1,2,4,6) |
VIA_REG_OFS_CAPTURE_FIFO equ 0x02 ;; byte - bit 6 = fifo enable |
VIA_REG_CAPTURE_FIFO_ENABLE equ 0x40 |
VIA_DXS_MAX_VOLUME equ 31 ;; max. volume (attenuation) of reg 0x32/33 |
VIA_TBL_BIT_FLAG equ 0x40000000 |
VIA_TBL_BIT_EOL equ 0x80000000 |
;; pci space ;; |
VIA_ACLINK_STAT equ 0x40 |
;... |
VIA_ACLINK_C00_READY equ 0x01 ; primary codec ready |
VIA_ACLINK_CTRL equ 0x41 |
VIA_ACLINK_CTRL_ENABLE equ 0x80 ; 0: disable, 1: enable |
VIA_ACLINK_CTRL_RESET equ 0x40 ; 0: assert, 1: de-assert |
VIA_ACLINK_CTRL_SYNC equ 0x20 ; 0: release SYNC, 1: force SYNC hi |
VIA_ACLINK_CTRL_SDO equ 0x10 ; 0: release SDO, 1: force SDO hi |
VIA_ACLINK_CTRL_VRA equ 0x08 ; 0: disable VRA, 1: enable VRA |
VIA_ACLINK_CTRL_PCM equ 0x04 ; 0: disable PCM, 1: enable PCM |
VIA_ACLINK_CTRL_FM equ 0x02 ; via686 only |
VIA_ACLINK_CTRL_SB equ 0x01 ; via686 only |
VIA_ACLINK_CTRL_INIT equ (VIA_ACLINK_CTRL_ENABLE or \ |
VIA_ACLINK_CTRL_RESET or \ |
VIA_ACLINK_CTRL_PCM or \ |
VIA_ACLINK_CTRL_VRA) |
VIA_FUNC_ENABLE equ 0x42 |
VIA_FUNC_MIDI_PNP equ 0x80 ; FIXME: it's 0x40 in the datasheet! |
VIA_FUNC_MIDI_IRQMASK equ 0x40 ; FIXME: not documented! |
VIA_FUNC_RX2C_WRITE equ 0x20 |
VIA_FUNC_SB_FIFO_EMPTY equ 0x10 |
VIA_FUNC_ENABLE_GAME equ 0x08 |
VIA_FUNC_ENABLE_FM equ 0x04 |
VIA_FUNC_ENABLE_MIDI equ 0x02 |
VIA_FUNC_ENABLE_SB equ 0x01 |
VIA_PNP_CONTROL equ 0x43 |
VIA_FM_NMI_CTRL equ 0x48 |
VIA8233_VOLCHG_CTRL equ 0x48 |
VIA8233_SPDIF_CTRL equ 0x49 |
VIA8233_SPDIF_DX3 equ 0x08 |
VIA8233_SPDIF_SLOT_MASK equ 0x03 |
VIA8233_SPDIF_SLOT_1011 equ 0x00 |
VIA8233_SPDIF_SLOT_34 equ 0x01 |
VIA8233_SPDIF_SLOT_78 equ 0x02 |
VIA8233_SPDIF_SLOT_69 equ 0x03 |
;] Asper |
SRV_GETVERSION equ 0 |
DEV_PLAY equ 1 |
DEV_STOP equ 2 |
DEV_CALLBACK equ 3 |
DEV_SET_BUFF equ 4 |
DEV_NOTIFY equ 5 |
DEV_SET_MASTERVOL equ 6 |
DEV_GET_MASTERVOL equ 7 |
DEV_GET_INFO equ 8 |
struc AC_CNTRL ;AC controller base class |
{ .bus dd ? |
.devfn dd ? |
.vendor dd ? |
.dev_id dd ? |
.pci_cmd dd ? |
.pci_stat dd ? |
.codec_io_base dd ? |
.codec_mem_base dd ? |
.ctrl_io_base dd ? |
.ctrl_mem_base dd ? |
.cfg_reg dd ? |
.int_line dd ? |
.vendor_ids dd ? ;vendor id string |
.ctrl_ids dd ? ;hub id string |
.buffer dd ? |
.notify_pos dd ? |
.notify_task dd ? |
.lvi_reg dd ? |
.ctrl_setup dd ? |
.user_callback dd ? |
.codec_read16 dd ? |
.codec_write16 dd ? |
.ctrl_read8 dd ? |
.ctrl_read16 dd ? |
.ctrl_read32 dd ? |
.ctrl_write8 dd ? |
.ctrl_write16 dd ? |
.ctrl_write32 dd ? |
} |
struc CODEC ;Audio Chip base class |
{ |
.chip_id dd ? |
.flags dd ? |
.status dd ? |
.ac_vendor_ids dd ? ;ac vendor id string |
.chip_ids dd ? ;chip model string |
.shadow_flag dd ? |
dd ? |
.regs dw ? ; codec registers |
.reg_master_vol dw ? ;0x02 |
.reg_aux_out_vol dw ? ;0x04 |
.reg_mone_vol dw ? ;0x06 |
.reg_master_tone dw ? ;0x08 |
.reg_beep_vol dw ? ;0x0A |
.reg_phone_vol dw ? ;0x0C |
.reg_mic_vol dw ? ;0x0E |
.reg_line_in_vol dw ? ;0x10 |
.reg_cd_vol dw ? ;0x12 |
.reg_video_vol dw ? ;0x14 |
.reg_aux_in_vol dw ? ;0x16 |
.reg_pcm_out_vol dw ? ;0x18 |
.reg_rec_select dw ? ;0x1A |
.reg_rec_gain dw ? ;0x1C |
.reg_rec_gain_mic dw ? ;0x1E |
.reg_gen dw ? ;0x20 |
.reg_3d_ctrl dw ? ;0X22 |
.reg_page dw ? ;0X24 |
.reg_powerdown dw ? ;0x26 |
.reg_ext_audio dw ? ;0x28 |
.reg_ext_st dw ? ;0x2a |
.reg_pcm_front_rate dw ? ;0x2c |
.reg_pcm_surr_rate dw ? ;0x2e |
.reg_lfe_rate dw ? ;0x30 |
.reg_pcm_in_rate dw ? ;0x32 |
dw ? ;0x34 |
.reg_cent_lfe_vol dw ? ;0x36 |
.reg_surr_vol dw ? ;0x38 |
.reg_spdif_ctrl dw ? ;0x3A |
dw ? ;0x3C |
dw ? ;0x3E |
dw ? ;0x40 |
dw ? ;0x42 |
dw ? ;0x44 |
dw ? ;0x46 |
dw ? ;0x48 |
dw ? ;0x4A |
dw ? ;0x4C |
dw ? ;0x4E |
dw ? ;0x50 |
dw ? ;0x52 |
dw ? ;0x54 |
dw ? ;0x56 |
dw ? ;0x58 |
dw ? ;0x5A |
dw ? ;0x5C |
dw ? ;0x5E |
.reg_page_0 dw ? ;0x60 |
.reg_page_1 dw ? ;0x62 |
.reg_page_2 dw ? ;0x64 |
.reg_page_3 dw ? ;0x66 |
.reg_page_4 dw ? ;0x68 |
.reg_page_5 dw ? ;0x6A |
.reg_page_6 dw ? ;0x6C |
.reg_page_7 dw ? ;0x6E |
dw ? ;0x70 |
dw ? ;0x72 |
dw ? ;0x74 |
dw ? ;0x76 |
dw ? ;0x78 |
dw ? ;0x7A |
.reg_vendor_id_1 dw ? ;0x7C |
.reg_vendor_id_2 dw ? ;0x7E |
.reset dd ? ;virual |
.set_master_vol dd ? |
} |
struc CTRL_INFO |
{ .pci_cmd dd ? |
.irq dd ? |
.glob_cntrl dd ? |
.glob_sta dd ? |
.codec_io_base dd ? |
.ctrl_io_base dd ? |
.codec_mem_base dd ? |
.ctrl_mem_base dd ? |
.codec_id dd ? |
} |
struc IOCTL |
{ .handle dd ? |
.io_code dd ? |
.input dd ? |
.inp_size dd ? |
.output dd ? |
.out_size dd ? |
} |
virtual at 0 |
IOCTL IOCTL |
end virtual |
EVENT_NOTIFY equ 0x00000200 |
public START |
public service_proc |
public version |
section '.flat' code readable align 16 |
proc START stdcall, state:dword |
cmp [state], 1 |
jne .stop |
if DEBUG |
mov esi, msgInit |
call SysMsgBoardStr |
end if |
call detect_controller |
test eax, eax |
jz .fail |
if DEBUG |
mov esi, [ctrl.vendor_ids] |
call SysMsgBoardStr |
mov esi, [ctrl.ctrl_ids] |
call SysMsgBoardStr |
end if |
call init_controller |
test eax, eax |
jz .fail |
call init_codec |
test eax, eax |
jz .fail |
call setup_codec |
mov esi, msgPrimBuff |
call SysMsgBoardStr |
call create_primary_buff |
mov esi, msgDone |
call SysMsgBoardStr |
if IRQ_REMAP |
pushf |
cli |
mov ebx, [ctrl.int_line] |
in al, 0xA1 |
mov ah, al |
in al, 0x21 |
test ebx, ebx |
jz .skip |
bts ax, bx ;mask old line |
.skip: |
bts ax, IRQ_LINE ;mask new ine |
out 0x21, al |
mov al, ah |
out 0xA1, al |
stdcall PciWrite8, 0, 0xF8, 0x61, IRQ_LINE ;remap IRQ |
mov dx, 0x4d0 ;8259 ELCR1 |
in al, dx |
bts ax, IRQ_LINE |
out dx, al ;set level-triggered mode |
mov [ctrl.int_line], IRQ_LINE |
popf |
mov esi, msgRemap |
call SysMsgBoardStr |
end if |
mov eax, VALID_IRQ |
mov ebx, [ctrl.int_line] |
mov esi, msgInvIRQ |
bt eax, ebx |
jnc .fail_msg |
mov eax, ATTCH_IRQ |
mov esi, msgAttchIRQ |
bt eax, ebx |
jnc .fail_msg |
stdcall AttachIntHandler, ebx, ac97_irq_VIA, dword 0 |
.reg: |
stdcall RegService, sz_sound_srv, service_proc |
ret |
.fail: |
if DEBUG |
mov esi, msgFail |
call SysMsgBoardStr |
end if |
xor eax, eax |
ret |
.fail_msg: |
call SysMsgBoardStr |
xor eax, eax |
ret |
.stop: |
call stop |
xor eax, eax |
ret |
endp |
handle equ IOCTL.handle |
io_code equ IOCTL.io_code |
input equ IOCTL.input |
inp_size equ IOCTL.inp_size |
output equ IOCTL.output |
out_size equ IOCTL.out_size |
align 4 |
proc service_proc stdcall, ioctl:dword |
mov edi, [ioctl] |
mov eax, [edi+io_code] |
cmp eax, SRV_GETVERSION |
jne @F |
mov eax, [edi+output] |
cmp [edi+out_size], 4 |
jne .fail |
mov [eax], dword API_VERSION |
xor eax, eax |
ret |
@@: |
cmp eax, DEV_PLAY |
jne @F |
if DEBUG |
mov esi, msgPlay |
call SysMsgBoardStr |
end if |
call play |
ret |
@@: |
cmp eax, DEV_STOP |
jne @F |
if DEBUG |
mov esi, msgStop |
call SysMsgBoardStr |
end if |
call stop |
ret |
@@: |
cmp eax, DEV_CALLBACK |
jne @F |
mov ebx, [edi+input] |
stdcall set_callback, [ebx] |
ret |
@@: |
cmp eax, DEV_SET_MASTERVOL |
jne @F |
mov eax, [edi+input] |
mov eax, [eax] |
call set_master_vol ;eax= vol |
ret |
@@: |
cmp eax, DEV_GET_MASTERVOL |
jne @F |
mov ebx, [edi+output] |
stdcall get_master_vol, ebx |
ret |
@@: |
cmp eax, DEV_GET_INFO |
jne @F |
mov ebx, [edi+output] |
stdcall get_dev_info, ebx |
ret |
@@: |
.fail: |
or eax, -1 |
ret |
endp |
restore handle |
restore io_code |
restore input |
restore inp_size |
restore output |
restore out_size |
align 4 |
proc ac97_irq_VIA |
locals |
status db 0 |
endl |
mov edx, VIADEV_PLAYBACK +VIA_REG_OFFSET_STATUS |
call [ctrl.ctrl_read8] |
test al, VIA_REG_STAT_ACTIVE |
jz @f |
and al, VIA_REG_STAT_EOL or VIA_REG_STAT_FLAG or VIA_REG_STAT_STOPPED |
mov byte [status], al |
mov ebx, dword [buff_list] |
cmp [ctrl.user_callback], 0 |
je @f |
stdcall [ctrl.user_callback], ebx |
@@: |
mov al, byte [status] ;; ack ;; |
mov edx, VIADEV_PLAYBACK +VIA_REG_OFFSET_STATUS |
call [ctrl.ctrl_write8] |
ret |
endp |
align 4 |
proc create_primary_buff |
stdcall KernelAlloc, 0x10000 |
mov [ctrl.buffer], eax |
mov edi, eax |
mov ecx, 0x10000/4 |
xor eax, eax |
cld |
rep stosd |
mov eax, [ctrl.buffer] |
call GetPgAddr |
mov edi, pcmout_bdl |
stosd |
mov eax, 0x80004000 |
stosd |
mov edi, buff_list |
mov eax, [ctrl.buffer] |
mov ecx, 4 |
@@: |
mov [edi], eax |
mov [edi+16], eax |
mov [edi+32], eax |
mov [edi+48], eax |
mov [edi+64], eax |
mov [edi+80], eax |
mov [edi+96], eax |
mov [edi+112], eax |
;add eax, 0x4000 |
add edi, 4 |
loop @B |
stdcall channel_reset, VIADEV_PLAYBACK |
stdcall codec_check_ready |
mov eax, pcmout_bdl |
mov ebx, eax |
call GetPgAddr |
and ebx, 0xFFF |
add eax, ebx |
mov edx, VIADEV_PLAYBACK +VIA_REG_OFFSET_TABLE_PTR |
call [ctrl.ctrl_write32] |
stdcall codec_check_ready |
mov edx, VIADEV_PLAYBACK +VIA_REG_OFS_PLAYBACK_VOLUME_L |
mov eax, 7 ;31 |
call [ctrl.ctrl_write8] |
mov edx, VIADEV_PLAYBACK +VIA_REG_OFS_PLAYBACK_VOLUME_R |
mov eax, 7 ;31 |
call [ctrl.ctrl_write8] |
mov edx, VIADEV_PLAYBACK +VIA_REG_OFFSET_STOP_IDX |
mov eax, VIA8233_REG_TYPE_16BIT or VIA8233_REG_TYPE_STEREO or 0xfffff or 0xff000000 |
mov [ctrl.lvi_reg], 16 ;0xF;eax |
call [ctrl.ctrl_write32] |
stdcall codec_check_ready |
ret |
endp |
proc channel_reset channel:dword |
mov esi, dword [channel] |
mov edx, esi |
add edx, VIA_REG_OFFSET_CONTROL |
mov eax, VIA_REG_CTRL_PAUSE or VIA_REG_CTRL_TERMINATE or VIA_REG_CTRL_RESET |
call [ctrl.ctrl_write8] |
mov edx, esi |
add edx, VIA_REG_OFFSET_CONTROL |
call [ctrl.ctrl_read8] |
mov eax, 50000 ; wait 50 ms |
call StallExec |
; disable interrupts |
mov edx, esi |
add edx, VIA_REG_OFFSET_CONTROL |
xor eax, eax |
call [ctrl.ctrl_write8] |
; clear interrupts |
mov edx, esi |
add edx, VIA_REG_OFFSET_STATUS |
mov eax, 0x03 |
call [ctrl.ctrl_write8] |
;outb(0x00, VIADEV_REG(viadev, OFFSET_TYPE)); /* for via686 */ |
; mov edx, esi ;; for via686 |
; add edx, VIA_REG_OFFSET_TYPE |
; mov eax, 0x03 |
; call [ctrl.ctrl_write8] |
;; outl(0, VIADEV_REG(viadev, OFFSET_CURR_PTR)); |
;mov edx, esi |
;add edx, VIA_REG_OFFSET_CURR_PTR |
;xor eax, eax |
;call [ctrl.ctrl_write8] |
ret |
endp |
align 4 |
proc detect_controller |
locals |
last_bus dd ? |
bus dd ? |
devfn dd ? |
endl |
xor eax, eax |
mov [bus], eax |
inc eax |
call PciApi |
cmp eax, -1 |
je .err |
mov [last_bus], eax |
.next_bus: |
and [devfn], 0 |
.next_dev: |
stdcall PciRead32, [bus], [devfn], dword 0 |
test eax, eax |
jz .next |
cmp eax, -1 |
je .next |
mov edi, devices |
@@: |
mov ebx, [edi] |
test ebx, ebx |
jz .next |
cmp eax, ebx |
je .found |
add edi, 12 |
jmp @B |
.next: |
inc [devfn] |
cmp [devfn], 256 |
jb .next_dev |
mov eax, [bus] |
inc eax |
mov [bus], eax |
cmp eax, [last_bus] |
jna .next_bus |
xor eax, eax |
ret |
.found: |
mov ebx, [bus] |
mov [ctrl.bus], ebx |
mov ecx, [devfn] |
mov [ctrl.devfn], ecx |
mov edx, eax |
and edx, 0xFFFF |
mov [ctrl.vendor], edx |
shr eax, 16 |
mov [ctrl.dev_id], eax |
mov ebx, [edi+4] |
mov [ctrl.ctrl_ids], ebx |
mov esi, [edi+8] |
mov [ctrl.ctrl_setup], esi |
cmp edx, VID_VIA |
jne @F |
mov [ctrl.vendor_ids], msg_VIA |
ret |
@@: |
.err: |
xor eax, eax |
mov [ctrl.vendor_ids], eax ;something wrong ? |
ret |
endp |
align 4 |
proc init_controller |
stdcall PciRead32, [ctrl.bus], [ctrl.devfn], dword 4 |
mov ebx, eax |
and eax, 0xFFFF |
mov [ctrl.pci_cmd], eax |
shr ebx, 16 |
mov [ctrl.pci_stat], ebx |
mov esi, msgPciCmd |
call SysMsgBoardStr |
call dword2str |
call SysMsgBoardStr |
mov esi, msgPciStat |
call SysMsgBoardStr |
mov eax, [ctrl.pci_stat] |
call dword2str |
call SysMsgBoardStr |
mov esi, msgCtrlIsaIo |
call SysMsgBoardStr |
stdcall PciRead32, [ctrl.bus], [ctrl.devfn], dword 0x10 |
call dword2str |
call SysMsgBoardStr |
and eax, 0xFFC0 |
mov [ctrl.ctrl_io_base], eax |
.default: |
stdcall PciRead32, [ctrl.bus], [ctrl.devfn], dword 0x3C |
and eax, 0xFF |
@@: |
mov [ctrl.int_line], eax |
;stdcall PciRead8, [ctrl.bus], [ctrl.devfn], dword VIA_FUNC_ENABLE ;0x42 |
;mov byte [old_legacy], al |
;stdcall PciRead8, [ctrl.bus], [ctrl.devfn], dword VIA_PNP_CONTROL ;0x43 |
;mov byte [old_legacy_cfg], al |
;mov al, VIA_FUNC_ENABLE_SB or VIA_FUNC_ENABLE_FM |
;xor al, 0xFF |
;and al, byte [old_legacy] |
;and eax, 0xFF |
;stdcall PciWrite8, [ctrl.bus], [ctrl.devfn], dword VIA_FUNC_ENABLE, eax ;0x42 |
;mov byte [old_legacy], al |
call [ctrl.ctrl_setup] |
xor eax, eax |
inc eax |
ret |
endp |
align 4 |
proc set_VIA |
mov [ctrl.codec_read16], codec_io_r16 ;virtual |
mov [ctrl.codec_write16], codec_io_w16 ;virtual |
mov [ctrl.ctrl_read8 ], ctrl_io_r8 ;virtual |
mov [ctrl.ctrl_read16], ctrl_io_r16 ;virtual |
mov [ctrl.ctrl_read32], ctrl_io_r32 ;virtual |
mov [ctrl.ctrl_write8 ], ctrl_io_w8 ;virtual |
mov [ctrl.ctrl_write16], ctrl_io_w16 ;virtual |
mov [ctrl.ctrl_write32], ctrl_io_w32 ;virtual |
ret |
endp |
align 4 |
proc init_codec |
locals |
counter dd ? |
endl |
mov esi, msgControl |
call SysMsgBoardStr |
stdcall PciRead8, [ctrl.bus], [ctrl.devfn], dword VIA_ACLINK_CTRL |
and eax, 0xFF |
call dword2str |
call SysMsgBoardStr |
mov esi, msgStatus |
call SysMsgBoardStr |
stdcall PciRead8, [ctrl.bus], [ctrl.devfn], dword VIA_ACLINK_STAT |
and eax, 0xFF |
push eax |
call dword2str |
call SysMsgBoardStr |
pop eax |
test eax, VIA_ACLINK_C00_READY |
jz .ready |
call reset_codec |
test eax, eax |
jz .err |
.ready: |
xor edx, edx ; ac_reg_0 |
call [ctrl.codec_write16] |
jmp .done |
.err: |
xor eax, eax ; timeout error |
ret |
.done: |
call detect_codec |
xor eax, eax |
inc eax |
ret |
endp |
align 4 |
proc reset_codec |
stdcall PciWrite8, [ctrl.bus], [ctrl.devfn], dword VIA_ACLINK_CTRL, \ |
VIA_ACLINK_CTRL_ENABLE or VIA_ACLINK_CTRL_RESET or VIA_ACLINK_CTRL_SYNC |
mov eax, 100000 ; wait 100 ms |
call StallExec |
.cold: |
call cold_reset |
jnc .ok |
if DEBUG |
mov esi, msgCFail |
call SysMsgBoardStr |
end if |
xor eax, eax ; timeout error |
ret |
.ok: |
if DEBUG |
mov esi, msgResetOk |
call SysMsgBoardStr |
end if |
xor eax, eax |
inc eax |
ret |
endp |
align 4 |
proc cold_reset |
locals |
counter dd ? |
endl |
stdcall PciWrite8, [ctrl.bus], [ctrl.devfn], dword VIA_ACLINK_CTRL, dword 0 |
if DEBUG |
mov esi, msgCold |
call SysMsgBoardStr |
end if |
mov eax, 100000 ; wait 100 ms ;400000 ; wait 400 ms |
call StallExec |
;; ACLink on, deassert ACLink reset, VSR, SGD data out |
;; note - FM data out has trouble with non VRA codecs !! |
stdcall PciWrite8, [ctrl.bus], [ctrl.devfn], dword VIA_ACLINK_CTRL, dword VIA_ACLINK_CTRL_INIT |
mov [counter], 16 ; total 20*100 ms = 2s |
.wait: |
stdcall PciRead8, [ctrl.bus], [ctrl.devfn], dword VIA_ACLINK_STAT |
test eax, VIA_ACLINK_C00_READY |
jnz .ok |
mov eax, 100000 ; wait 100 ms |
call StallExec |
dec [counter] |
jnz .wait |
if DEBUG |
mov esi, msgCRFail |
call SysMsgBoardStr |
end if |
.fail: |
stc |
ret |
.ok: |
mov esi, msgControl |
call SysMsgBoardStr |
stdcall PciRead8, [ctrl.bus], [ctrl.devfn], dword VIA_ACLINK_CTRL |
call dword2str |
call SysMsgBoardStr |
mov esi, msgStatus |
call SysMsgBoardStr |
stdcall PciRead8, [ctrl.bus], [ctrl.devfn], dword VIA_ACLINK_STAT |
and eax, 0xFF |
push eax |
call dword2str |
call SysMsgBoardStr |
pop eax |
test eax, VIA_ACLINK_C00_READY ;CTRL_ST_CREADY |
jz .fail |
clc |
ret |
endp |
align 4 |
play: |
mov edx, VIADEV_PLAYBACK +VIA_REG_OFFSET_STOP_IDX |
mov eax, VIA8233_REG_TYPE_16BIT or VIA8233_REG_TYPE_STEREO or 0xfffff or 0xff000000 |
mov [ctrl.lvi_reg], 16 |
call [ctrl.ctrl_write32] |
mov eax, VIA_REG_CTRL_INT |
or eax, VIA_REG_CTRL_START |
mov edx, VIADEV_PLAYBACK +VIA_REG_OFFSET_CONTROL |
call [ctrl.ctrl_write8] |
xor eax, eax |
ret |
align 4 |
stop: |
mov eax, VIA_REG_CTRL_INT |
or eax, VIA_REG_CTRL_TERMINATE |
mov edx, VIADEV_PLAYBACK +VIA_REG_OFFSET_CONTROL |
call [ctrl.ctrl_write8] |
stdcall channel_reset, VIADEV_PLAYBACK |
xor eax, eax |
ret |
align 4 |
proc get_dev_info stdcall, p_info:dword |
virtual at esi |
CTRL_INFO CTRL_INFO |
end virtual |
mov esi, [p_info] |
mov eax, [ctrl.int_line] |
mov ecx, [ctrl.ctrl_io_base] |
mov [CTRL_INFO.irq], eax |
mov [CTRL_INFO.ctrl_io_base], ecx |
xor eax, eax |
;mov edx, VIADEV_PLAYBACK +VIA_REG_OFFSET_TABLE_PTR |
;call [ctrl.ctrl_read32] |
mov [CTRL_INFO.codec_io_base], eax |
;mov edx, VIADEV_PLAYBACK +VIA_REG_OFFSET_STOP_IDX |
;call [ctrl.ctrl_read32] |
mov [CTRL_INFO.codec_mem_base], eax |
;mov edx, VIADEV_PLAYBACK +VIA_REG_OFFSET_CURR_COUNT |
;call [ctrl.ctrl_read32] |
mov [CTRL_INFO.ctrl_mem_base], eax |
mov eax, [codec.chip_id] |
mov [CTRL_INFO.codec_id], eax |
mov edx, VIADEV_PLAYBACK +VIA_REG_OFFSET_CONTROL |
call [ctrl.ctrl_read8] |
and eax, 0xFF |
mov [CTRL_INFO.glob_cntrl], eax |
mov edx, VIADEV_PLAYBACK +VIA_REG_OFFSET_STATUS |
call [ctrl.ctrl_read8] |
and eax, 0xFF |
mov [CTRL_INFO.glob_sta], eax |
mov ebx, [ctrl.pci_cmd] |
mov [CTRL_INFO.pci_cmd], ebx |
ret |
endp |
align 4 |
proc set_callback stdcall, handler:dword |
mov eax, [handler] |
mov [ctrl.user_callback], eax |
ret |
endp |
align 4 |
proc codec_check_ready stdcall |
locals |
counter dd ? |
endl |
mov [counter], 1000 ; total 1000*1 ms = 1s |
.wait: |
call [ctrl.codec_read16] |
test eax, VIA_REG_AC97_BUSY |
jz .ok |
mov eax, 1000 ; wait 1 ms |
call StallExec |
sub [counter] , 1 |
jnz .wait |
.err: |
mov eax, -1 |
ret |
.ok: |
and eax, 0xFFFF |
ret |
endp |
align 4 |
proc codec_valid stdcall |
stdcall codec_check_ready |
ret |
endp |
align 4 |
proc codec_read stdcall, ac_reg:dword ; reg = edx, reval = eax |
locals |
counter dd ? |
endl |
;Use only primary codec. |
mov eax, [ac_reg] |
and eax, 0x7F |
shl eax, VIA_REG_AC97_CMD_SHIFT |
or eax, VIA_REG_AC97_PRIMARY_VALID or VIA_REG_AC97_READ |
mov [counter], 3 ; total 3*20 ms = 60ms |
.wait: |
push eax |
call [ctrl.codec_write16] |
mov eax, 20000 ; wait 20 ms |
call StallExec |
stdcall codec_valid |
cmp eax, 0 |
pop eax |
jge .ok |
sub [counter] , 1 |
jnz .wait |
jmp .err |
.ok: |
mov eax, 25000 ; wait 25 ms |
call StallExec |
call [ctrl.codec_read16] ;change edx !!! |
and eax, 0xFFFF |
ret |
.err: |
if DEBUG |
mov esi, msgCInvalid |
call SysMsgBoardStr |
end if |
mov eax, -1 ; invalid codec error |
ret |
endp |
align 4 |
proc codec_write stdcall, ac_reg:dword |
;Use only primary codec. |
mov esi, [ac_reg] |
mov edx, esi |
shl edx, VIA_REG_AC97_CMD_SHIFT |
shl eax, VIA_REG_AC97_DATA_SHIFT |
or edx, eax |
mov eax, VIA_REG_AC97_CODEC_ID_PRIMARY ;not VIA_REG_AC97_CODEC_ID_PRIMARY |
shl eax, VIA_REG_AC97_CODEC_ID_SHIFT |
or edx, eax |
mov eax, edx |
mov edx, esi |
call [ctrl.codec_write16] |
mov [codec.regs+esi], ax |
stdcall codec_check_ready |
cmp eax, 0 |
jl .err |
.ok: |
ret |
.err: |
if DEBUG |
mov esi, msgCFail |
call SysMsgBoardStr |
end if |
;mov eax, -1 ; codec not ready error |
ret |
endp |
align 4 |
proc StallExec |
push ecx |
push edx |
push ebx |
push eax |
mov ecx, CPU_FREQ |
mul ecx |
mov ebx, eax ;low |
mov ecx, edx ;high |
rdtsc |
add ebx, eax |
adc ecx, edx |
@@: |
rdtsc |
sub eax, ebx |
sbb edx, ecx |
js @B |
pop eax |
pop ebx |
pop edx |
pop ecx |
ret |
endp |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
; CONTROLLER IO functions |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
proc codec_io_r16 ;r32 |
mov edx, [ctrl.ctrl_io_base] |
add edx, VIA_REG_AC97 |
in eax, dx |
ret |
endp |
align 4 |
proc codec_io_w16 ;w32 |
mov edx, [ctrl.ctrl_io_base] |
add edx, VIA_REG_AC97 |
out dx, eax |
ret |
endp |
align 4 |
proc ctrl_io_r8 |
add edx, [ctrl.ctrl_io_base] |
in al, dx |
ret |
endp |
align 4 |
proc ctrl_io_r16 |
add edx, [ctrl.ctrl_io_base] |
in ax, dx |
ret |
endp |
align 4 |
proc ctrl_io_r32 |
add edx, [ctrl.ctrl_io_base] |
in eax, dx |
ret |
endp |
align 4 |
proc ctrl_io_w8 |
add edx, [ctrl.ctrl_io_base] |
out dx, al |
ret |
endp |
align 4 |
proc ctrl_io_w16 |
add edx, [ctrl.ctrl_io_base] |
out dx, ax |
ret |
endp |
align 4 |
proc ctrl_io_w32 |
add edx, [ctrl.ctrl_io_base] |
out dx, eax |
ret |
endp |
align 4 |
dword2str: |
push eax ebx ecx |
mov esi, hex_buff |
mov ecx, -8 |
@@: |
rol eax, 4 |
mov ebx, eax |
and ebx, 0x0F |
mov bl, [ebx+hexletters] |
mov [8+esi+ecx], bl |
inc ecx |
jnz @B |
pop ecx ebx eax |
ret |
hexletters db '0123456789ABCDEF' |
hex_buff db 8 dup(0),13,10,0 |
include "codec.inc" |
align 4 |
devices dd (CTRL_VT82C686 shl 16)+VID_VIA,msg_VT82C686,set_VIA |
dd (CTRL_VT8233_5 shl 16)+VID_VIA,msg_VT8233,set_VIA |
dd 0 ;terminator |
version dd (5 shl 16) or (API_VERSION and 0xFFFF) |
msg_VT82C686 db 'VT82C686', 13,10, 0 |
msg_VT8233 db 'VT8233', 13,10, 0 |
msg_VIA db 'VIA' , 13,10, 0 |
szKernel db 'KERNEL', 0 |
sz_sound_srv db 'SOUND',0 |
msgInit db 'detect hardware...',13,10,0 |
msgFail db 'device not found',13,10,0 |
msgAttchIRQ db 'IRQ line not supported', 13,10, 0 |
msgInvIRQ db 'IRQ line not assigned or invalid', 13,10, 0 |
msgPlay db 'start play', 13,10,0 |
msgStop db 'stop play', 13,10,0 |
;msgIRQ db 'AC97 IRQ', 13,10,0 |
;msgInitCtrl db 'init controller',13,10,0 |
;msgInitCodec db 'init codec',13,10,0 |
msgPrimBuff db 'create primary buffer ...',0 |
msgDone db 'done',13,10,0 |
msgRemap db 'Remap IRQ',13,10,0 |
;msgReg db 'set service handler',13,10,0 |
;msgOk db 'service installed',13,10,0 |
msgCold db 'cold reset',13,10,0 |
;msgWarm db 'warm reset',13,10,0 |
;msgWRFail db 'warm reset failed',13,10,0 |
msgCRFail db 'cold reset failed',13,10,0 |
msgCFail db 'codec not ready',13,10,0 |
msgCInvalid db 'codec is not valid',13,10,0 ;Asper |
msgResetOk db 'reset complete',13,10,0 |
msgStatus db 'global status ',0 |
msgControl db 'global control ',0 |
msgPciCmd db 'PCI command ',0 |
msgPciStat db 'PCI status ',0 |
msgCtrlIsaIo db 'controller io base ',0 |
;msgMixIsaIo db 'codec io base ',0 |
;msgCtrlMMIo db 'controller mmio base ',0 |
;msgMixMMIo db 'codec mmio base ',0 |
;msgIrqMap db 'AC97 irq map as ',0 |
section '.data' data readable writable align 16 |
pcmout_bdl rq 32 |
buff_list rd 32 |
codec CODEC |
ctrl AC_CNTRL |
chip_type rb 1 |
/kernel/branches/Kolibri-acpi/drivers/infinity.asm |
---|
0,0 → 1,1474 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2006-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
; Serge 2006-2008 |
; email: infinity_sound@mail.ru |
format MS COFF |
DEBUG equ 1 |
include 'proc32.inc' |
include 'main.inc' |
include 'imports.inc' |
CURRENT_API equ 0x0101 ;1.01 |
COMPATIBLE_API equ 0x0100 ;1.00 |
API_VERSION equ (COMPATIBLE_API shl 16) or CURRENT_API |
SOUND_VERSION equ CURRENT_API |
FORCE_MMX equ 0 ;set to 1 to force use mmx or |
FORCE_MMX_128 equ 0 ;integer sse2 extensions |
;and reduce driver size |
;USE_SSE equ 0 |
USE_SSE2_MIXER equ 0 ;floating point mixer. Disabled by default |
OS_BASE equ 0x80000000 |
CAPS_SSE2 equ 26 |
PG_SW equ 0x003 |
public START |
public service_proc |
public version |
RT_INP_EMPTY equ 0xFF000001 |
RT_OUT_EMPTY equ 0xFF000002 |
RT_INP_FULL equ 0xFF000003 |
RT_OUT_FULL equ 0xFF000004 |
EVENT_WATCHED equ 0x10000000 |
EVENT_SIGNALED equ 0x20000000 |
MANUAL_RESET equ 0x40000000 |
MANUAL_DESTROY equ 0x80000000 |
DEV_PLAY equ 1 |
DEV_STOP equ 2 |
DEV_CALLBACK equ 3 |
DEV_GET_POS equ 9 |
struc IOCTL |
{ .handle dd ? |
.io_code dd ? |
.input dd ? |
.inp_size dd ? |
.output dd ? |
.out_size dd ? |
} |
virtual at 0 |
IOCTL IOCTL |
end virtual |
section '.flat' code readable align 16 |
proc START stdcall, state:dword |
cmp [state], 1 |
jne .exit |
stdcall GetService, szSound |
test eax, eax |
jz .fail |
mov [hSound], eax |
stdcall KernelAlloc, 16*512 |
test eax, eax |
jz .out_of_mem |
mov [mix_buff], eax |
mov eax, str.fd-FD_OFFSET |
mov [str.fd], eax |
mov [str.bk], eax |
if FORCE_MMX |
if FORCE_MMX_128 |
display 'Use only FORCE_MMX or FORCE_MMX_128 not both together',13,10 |
stop |
end if |
mov [mix_2_core], mmx_mix_2 |
mov [mix_3_core], mmx_mix_3 |
mov [mix_4_core], mmx_mix_4 |
end if |
if FORCE_MMX_128 |
if FORCE_MMX |
display 'Use only FORCE_MMX or FORCE_MMX_128 not both together',13,10 |
stop |
end if |
mov [mix_2_core], mmx128_mix_2 |
mov [mix_3_core], mmx128_mix_3 |
mov [mix_4_core], mmx128_mix_4 |
end if |
if 0 |
if ~(FORCE_MMX or FORCE_MMX_128) ;autodetect |
mov eax, 1 |
cpuid |
bt edx, CAPS_SSE2 |
jc .mmx128 |
;old 64-bit mmx |
mov [mix_2_core], mmx_mix_2 |
mov [mix_3_core], mmx_mix_3 |
mov [mix_4_core], mmx_mix_4 |
jmp @F |
.mmx128: ;128-bit integer sse2 extensions |
mov [mix_2_core], mmx128_mix_2 |
mov [mix_3_core], mmx128_mix_3 |
mov [mix_4_core], mmx128_mix_4 |
@@: |
end if |
end if |
stdcall set_handler, [hSound], new_mix |
mov [eng_state], SND_STOP |
stdcall RegService, szInfinity, service_proc |
ret |
.fail: |
if DEBUG |
mov esi, msgFail |
call SysMsgBoardStr |
end if |
.exit: |
xor eax, eax |
ret |
.out_of_mem: |
if DEBUG |
mov esi, msgMem |
call SysMsgBoardStr |
end if |
xor eax, eax |
ret |
endp |
handle equ IOCTL.handle |
io_code equ IOCTL.io_code |
input equ IOCTL.input |
inp_size equ IOCTL.inp_size |
output equ IOCTL.output |
out_size equ IOCTL.out_size |
align 4 |
srv_calls dd service_proc.srv_getversion ; 0 |
dd service_proc.snd_create_buff ; 1 |
dd service_proc.snd_destroy_buff ; 2 |
dd service_proc.snd_setformat ; 3 |
dd service_proc.snd_getformat ; 4 |
dd service_proc.snd_reset ; 5 |
dd service_proc.snd_setpos ; 6 |
dd service_proc.snd_getpos ; 7 |
dd service_proc.snd_setbuff ; 8 |
dd service_proc.snd_out ; 9 |
dd service_proc.snd_play ; 10 |
dd service_proc.snd_stop ; 11 |
dd service_proc.snd_setvolume ; 12 |
dd service_proc.snd_getvolume ; 13 |
dd service_proc.snd_setpan ; 14 |
dd service_proc.snd_getpan ; 15 |
dd service_proc.snd_getbuffsize ; 16 |
dd service_proc.snd_getfreespace ; 17 |
dd service_proc.snd_settimebase ; 18 |
dd service_proc.snd_gettimestamp ; 19 |
srv_calls_end: |
proc service_proc stdcall, ioctl:dword |
mov edi, [ioctl] |
mov eax, [edi+io_code] |
cmp eax, (srv_calls_end-srv_calls)/4 |
ja .fail |
cmp eax, SND_DESTROY_BUFF |
jb @F |
; cmp [edi+inp_size], 4 |
; jb .fali |
mov ebx, [edi+input] |
mov edx, [ebx] |
cmp [edx+STREAM.magic], 'WAVE' |
jne .fail |
cmp [edx+STREAM.size], STREAM.sizeof |
jne .fail |
@@: |
jmp [srv_calls+eax*4] |
.fail: |
mov eax, -1 |
ret |
align 4 |
.srv_getversion: |
mov eax, [edi+output] |
cmp [edi+out_size], 4 |
jne .fail |
mov eax, [eax] |
mov [eax], dword API_VERSION |
xor eax, eax |
ret |
align 4 |
.snd_create_buff: |
mov ebx, [edi+input] |
stdcall CreateBuffer, [ebx], [ebx+4] |
mov edi, [ioctl] |
mov ecx, [edi+output] |
mov ecx, [ecx] |
mov [ecx], ebx |
ret |
align 4 |
.snd_destroy_buff: |
mov eax, edx |
call DestroyBuffer |
ret |
align 4 |
.snd_setformat: |
stdcall SetFormat, edx, [ebx+4] |
ret |
align 4 |
.snd_getformat: |
movzx eax, word [edx+STREAM.format] |
mov ecx, [edi+output] |
mov ecx, [ecx] |
mov [ecx], eax |
xor eax, eax |
ret |
align 4 |
.snd_reset: |
stdcall ResetBuffer, edx, [ebx+4] |
ret |
align 4 |
.snd_setpos: |
stdcall SetBufferPos, edx, [ebx+4] |
ret |
align 4 |
.snd_getpos: |
stdcall GetBufferPos, edx |
mov edi, [ioctl] |
mov ecx, [edi+output] |
mov ecx, [ecx] |
mov [ecx], ebx |
ret |
align 4 |
.snd_setbuff: |
mov eax, [ebx+4] |
stdcall set_buffer, edx, eax, [ebx+8], [ebx+12] |
ret |
align 4 |
.snd_out: |
mov eax, [ebx+4] |
stdcall wave_out, edx, eax, [ebx+8] |
ret |
align 4 |
.snd_play: |
stdcall play_buffer, edx, [ebx+4] |
ret |
align 4 |
.snd_stop: |
stdcall stop_buffer, edx |
ret |
align 4 |
.snd_setvolume: |
stdcall SetBufferVol, edx, [ebx+4], [ebx+8] |
ret |
align 4 |
.snd_getvolume: |
mov eax, [edi+output] |
mov ecx, [eax] |
mov eax, [eax+4] |
stdcall GetBufferVol, edx, ecx, eax |
ret |
align 4 |
.snd_setpan: |
stdcall SetBufferPan, edx, [ebx+4] |
ret |
align 4 |
.snd_getpan: |
mov eax, [edx+STREAM.pan] |
mov ebx, [edi+output] |
mov ebx, [ebx] |
mov [ebx], eax |
xor eax, eax |
ret |
align 4 |
.snd_getbuffsize: |
mov eax, [edx+STREAM.in_size] |
mov ecx, [edi+output] |
mov ecx, [ecx] |
mov [ecx], eax |
xor eax, eax |
ret |
align 4 |
.snd_getfreespace: |
test [edx+STREAM.format], PCM_OUT |
jz .fail |
mov ebx, [edx+STREAM.in_free] |
mov ecx, [edi+output] |
mov [ecx], ebx |
xor eax, eax |
ret |
align 4 |
.snd_settimebase: |
cmp [edi+inp_size], 12 |
jne .fail |
mov eax, [ebx+4] |
mov ebx, [ebx+8] |
pushfd |
cli |
mov dword [edx+STREAM.time_base], eax |
mov dword [edx+STREAM.time_base+4], ebx |
xor eax, eax |
mov dword [edx+STREAM.time_stamp], eax |
mov dword [edx+STREAM.time_stamp+4], eax |
popfd |
ret |
align 4 |
.snd_gettimestamp: |
cmp [edi+out_size], 8 |
jne .fail |
pushfd |
cli |
xor ebx, ebx |
push 48 |
push ebx ; local storage |
cmp [edx+STREAM.flags], SND_STOP |
je @F |
mov eax, esp |
push ebx |
push ecx |
push edx |
push esi |
push edi |
push 4 ;.out_size |
push eax ;.output |
push ebx ;.inp_size |
push ebx ;.input |
push DEV_GET_POS ;.code |
push dword [hSound] ;.handle |
mov eax, esp |
stdcall ServiceHandler, eax |
add esp, 6*4 |
pop edi |
pop esi |
pop edx |
pop ecx |
pop ebx |
test eax, eax |
jz @F |
mov dword [esp], 0 ; clear offset |
@@: |
mov edi, [edi+output] |
emms |
fild qword [edx+STREAM.time_stamp] |
fiadd dword [esp] ; primary buffer offset |
fidiv dword [esp+4] ; total_samples / frequency |
fadd qword [edx+STREAM.time_base] |
fstp qword [edi] |
add esp, 8 |
popfd |
xor eax, eax |
ret |
endp |
restore handle |
restore io_code |
restore input |
restore inp_size |
restore output |
restore out_size |
align 4 |
proc CreateBuffer stdcall, format:dword, size:dword |
locals |
str dd ? |
ring_size dd ? |
ring_pages dd ? |
endl |
mov eax, [format] |
cmp ax, PCM_1_8_8 |
ja .fail |
test eax, PCM_OUT |
jnz .test_out |
test eax, PCM_RING |
jnz .test_ring |
;staic |
test eax, PCM_STATIC |
jz .test_out ;use PCM_OUT as default format |
jmp .test_ok |
.test_out: |
test eax, PCM_RING+PCM_STATIC |
jnz .fail |
or [format], PCM_OUT ;force set |
jmp .test_ok |
.test_ring: |
test eax, PCM_OUT+PCM_STATIC |
jnz .fail |
.test_ok: |
call GetPid |
mov ebx, eax |
mov eax, STREAM.sizeof |
call CreateObject |
test eax, eax |
jz .fail |
mov [str], eax |
mov ebx, [format] |
mov [eax+STREAM.format], ebx |
xor ecx, ecx |
movzx ebx, bx |
cmp ebx, 19 |
jb @f |
mov ecx, 0x80808080 |
@@: |
mov [eax+STREAM.r_silence], ecx |
shl ebx, 2 |
lea ebx, [ebx+ebx*2] ;ebx*=12 |
mov ecx, [resampler_params+ebx] |
mov edx, [resampler_params+ebx+4] |
mov esi, [resampler_params+ebx+8] |
mov [eax+STREAM.r_size], ecx |
mov [eax+STREAM.r_dt], edx |
mov [eax+STREAM.resample], esi |
xor ecx, ecx |
mov [eax+STREAM.l_vol], ecx |
mov [eax+STREAM.r_vol], ecx |
mov dword [eax+STREAM.l_amp], 0x7FFF7FFF |
mov [eax+STREAM.pan], ecx |
test [format], PCM_STATIC |
jnz .static |
; ring and waveout |
mov ebx, 0x10000 |
test [format], PCM_RING |
jz .waveout |
mov ebx, [eax+STREAM.r_size] |
add ebx, 4095 |
and ebx, -4096 |
add ebx, ebx |
.waveout: |
mov [ring_size], ebx |
mov eax, ebx |
shr ebx, 12 |
mov [ring_pages], ebx |
stdcall CreateRingBuffer, eax, PG_SW |
mov edi, [str] |
mov ecx, [ring_size] |
mov [edi+STREAM.in_base], eax |
mov [edi+STREAM.in_size], ecx |
add eax, 128 |
mov [edi+STREAM.in_wp], eax |
mov [edi+STREAM.in_rp], eax |
mov [edi+STREAM.in_count], 0 |
mov [edi+STREAM.in_free], ecx |
add eax, ecx |
mov [edi+STREAM.in_top], eax |
jmp .out_buff |
.static: |
mov ecx, [size] |
add ecx, 128 ;resampler required |
mov [eax+STREAM.in_size], ecx |
stdcall KernelAlloc, ecx |
mov edi, [str] |
mov [edi+STREAM.in_base], eax |
add eax, 128 |
mov [edi+STREAM.in_wp], eax |
mov [edi+STREAM.in_rp], eax |
mov ebx, [size] |
mov [edi+STREAM.in_count], ebx |
mov [edi+STREAM.in_free], ebx |
add eax, ebx |
mov [edi+STREAM.in_top], eax |
.out_buff: |
stdcall AllocKernelSpace, dword 128*1024 |
mov edi, [str] |
xor ebx, ebx |
mov [edi+STREAM.out_base], eax |
mov [edi+STREAM.out_wp], eax |
mov [edi+STREAM.out_rp], eax |
mov [edi+STREAM.out_count], ebx |
add eax, 64*1024 |
mov [edi+STREAM.out_top], eax |
mov dword [edi+STREAM.time_base], ebx |
mov dword [edi+STREAM.time_base+4], ebx |
mov dword [edi+STREAM.time_stamp], ebx |
mov dword [edi+STREAM.time_stamp+4], ebx |
mov dword [edi+STREAM.last_ts], ebx |
stdcall AllocPages, dword 64/4 |
mov edi, [str] |
mov ebx, [edi+STREAM.out_base] |
mov ecx, 16 |
or eax, PG_SW |
push eax |
push ebx |
call CommitPages ;eax, ebx, ecx |
mov ecx, 16 |
pop ebx |
pop eax |
add ebx, 64*1024 |
call CommitPages ;double mapped |
mov edi, [str] |
mov ecx, [edi+STREAM.in_top] |
mov edi, [edi+STREAM.in_base] |
sub ecx, edi |
xor eax, eax |
shr ecx, 2 |
cld |
rep stosd |
mov edi, [str] |
mov edi, [edi+STREAM.out_base] |
mov ecx, (64*1024)/4 |
rep stosd |
xor esi, esi |
mov ecx, MANUAL_DESTROY |
call CreateEvent |
mov ebx, [str] |
mov [ebx+STREAM.notify_event], eax |
mov [ebx+STREAM.notify_id], edx |
mov [ebx+STREAM.magic], 'WAVE' |
mov [ebx+STREAM.destroy], DestroyBuffer.destroy |
mov [ebx+STREAM.size], STREAM.sizeof |
mov [ebx+STREAM.flags], SND_STOP |
pushf |
cli |
mov eax, str.fd-FD_OFFSET |
mov edx, [eax+STREAM.str_fd] |
mov [ebx+STREAM.str_fd], edx |
mov [ebx+STREAM.str_bk], eax |
mov [eax+STREAM.str_fd], ebx |
mov [edx+STREAM.str_bk], ebx |
popf |
xor eax, eax |
ret |
.fail: |
xor ebx, ebx |
or eax, -1 |
ret |
endp |
;param |
; eax= buffer handle |
align 4 |
DestroyBuffer: |
.handle equ esp ;local |
mov [eax+STREAM.flags], SND_STOP |
.destroy: |
push eax |
pushfd |
cli |
mov ebx, [eax+STREAM.str_fd] |
mov ecx, [eax+STREAM.str_bk] |
mov [ebx+STREAM.str_bk], ecx |
mov [ecx+STREAM.str_fd], ebx |
popf |
stdcall KernelFree, [eax+STREAM.in_base] |
mov eax, [.handle] |
stdcall KernelFree, [eax+STREAM.out_base] |
pop eax ;restore stack |
call DestroyObject ;eax= stream |
xor eax, eax |
ret |
.fail: |
or eax, -1 |
ret |
restore .handle |
align 4 |
proc SetFormat stdcall, str:dword, format:dword |
cmp word [format], PCM_1_8_8 |
ja .fail |
mov edx, [str] |
mov [edx+STREAM.flags], SND_STOP |
test [edx+STREAM.format], PCM_RING |
jnz .fail |
; mov eax,[edx+STREAM.out_base] |
; mov [edx+STREAM.out_wp], eax |
; mov [edx+STREAM.out_rp], eax |
; mov [edx+STREAM.out_count], 0 |
movzx eax, word [format] |
mov word [edx+STREAM.format], ax |
xor ebx, ebx |
cmp eax, 19 |
jb @f |
mov ebx, 0x80808080 |
@@: |
mov [edx+STREAM.r_silence], ebx |
shl eax, 2 |
lea eax, [eax+eax*2] ;eax*=12 |
mov edi, [resampler_params+eax] |
mov ecx, [resampler_params+eax+4] |
mov ebx, [resampler_params+eax+8] |
mov [edx+STREAM.r_size], edi |
mov [edx+STREAM.r_dt], ecx |
mov [edx+STREAM.resample], ebx |
mov edi, [edx+STREAM.in_base] |
mov ecx, 128/4 |
mov eax, [edx+STREAM.r_silence] |
cld |
rep stosd |
xor eax, eax |
ret |
.fail: |
or eax, -1 |
ret |
endp |
; for static buffers only |
; use waveout for streams |
align 4 |
proc set_buffer stdcall, str:dword,src:dword,offs:dword,size:dword |
mov edx, [str] |
test [edx+STREAM.format], PCM_OUT |
jnz .fail |
mov esi, [src] |
mov edi, [offs] |
add edi, [edx+STREAM.in_base] |
add edi, 128 |
cmp edi, [edx+STREAM.in_top] |
jae .fail |
mov ecx, [size] |
lea ebx, [ecx+edi] |
sub ebx, [edx+STREAM.in_top] |
jb @F |
sub ecx, ebx |
@@: |
shr ecx, 2 |
cld |
rep movsd |
xor eax, eax |
ret |
.fail: |
or eax, -1 |
ret |
endp |
; for stream buffers only |
align 4 |
proc wave_out stdcall, str:dword,src:dword,size:dword |
locals |
state_saved dd ? |
fpu_state rb 528 |
endl |
mov edx, [str] |
mov eax, [edx+STREAM.format] |
test eax, PCM_OUT |
jz .fail |
cmp ax, PCM_ALL |
je .fail |
mov esi, [src] |
test esi, esi |
jz .fail |
cmp esi, OS_BASE |
jae .fail |
mov [state_saved], 0 |
.main_loop: |
mov edx, [str] |
mov ebx, [size] |
test ebx, ebx |
jz .done |
cmp [edx+STREAM.flags], SND_STOP |
jne .fill |
mov edi, [edx+STREAM.in_base] |
mov ecx, 128/4 |
mov eax, [edx+STREAM.r_silence] |
cld |
rep stosd |
mov ecx, [edx+STREAM.in_size] |
sub ecx, 128 |
mov [edx+STREAM.in_wp], edi |
mov [edx+STREAM.in_rp], edi |
mov [edx+STREAM.in_count], 0 |
mov [edx+STREAM.in_free], ecx |
mov eax, [edx+STREAM.out_base] |
mov [edx+STREAM.out_wp], eax |
mov [edx+STREAM.out_rp], eax |
mov [edx+STREAM.out_count], 0 |
.fill: |
cli |
mov ecx, [edx+STREAM.in_free] |
test ecx, ecx |
jz .wait |
cmp ecx, ebx |
jbe @F |
mov ecx, ebx |
@@: |
sub [size], ecx |
add [edx+STREAM.in_count], ecx |
sub [edx+STREAM.in_free], ecx |
shr ecx, 2 |
mov edi, [edx+STREAM.in_wp] |
mov esi, [src] |
cld |
rep movsd |
mov [src], esi |
cmp edi, [edx+STREAM.in_top] |
jb @F |
sub edi, [edx+STREAM.in_size] |
@@: |
mov [edx+STREAM.in_wp], edi |
cmp [edx+STREAM.out_count], 32768 |
jae .skip |
cmp [state_saved], 0 |
jne @F |
lea eax, [fpu_state+15] |
and eax, -16 |
call FpuSave |
mov [state_saved], 1 |
@@: |
stdcall refill, edx |
.skip: |
sti |
mov edx, [str] |
mov [edx+STREAM.flags], SND_PLAY |
cmp [eng_state], SND_PLAY |
je .main_loop |
stdcall dev_play, [hSound] |
mov [eng_state], SND_PLAY |
jmp .main_loop |
.wait: |
sti |
mov edx, [str] |
mov eax, [edx+STREAM.notify_event] |
mov ebx, [edx+STREAM.notify_id] |
call WaitEvent ;eax ebx |
jmp .main_loop |
.done: |
cmp [state_saved], 1 |
jne @F |
lea eax, [fpu_state+15] |
and eax, -16 |
call FpuRestore |
@@: |
xor eax, eax |
ret |
.fail: |
or eax, -1 |
ret |
endp |
; both static and stream |
; reset all but not clear buffers |
; flags reserved |
; RESET_INPUT equ 1 ;reset and clear input buffer |
; RESET_OUTPUT equ 2 ;reset and clear output buffer |
; RESET_ALL equ 3 |
align 4 |
proc ResetBuffer stdcall, str:dword, flags:dword |
mov edx, [str] |
mov [edx+STREAM.flags], SND_STOP |
mov edi, [edx+STREAM.in_base] |
mov ecx, 128/4 |
mov eax, [edx+STREAM.r_silence] |
cld |
rep stosd |
mov [edx+STREAM.in_wp], edi |
mov [edx+STREAM.in_rp], edi |
test [edx+STREAM.flags], PCM_STATIC |
jnz .static |
mov [edx+STREAM.in_count], 0 |
jmp @F |
.static: |
mov eax, [edx+STREAM.in_size] |
mov [edx+STREAM.in_count], eax |
@@: |
mov eax, [edx+STREAM.in_size] |
sub eax, 128 |
mov [edx+STREAM.in_free], eax |
xor eax, eax |
mov ebx, [edx+STREAM.out_base] |
mov [edx+STREAM.out_wp], ebx |
mov [edx+STREAM.out_rp], ebx |
mov [edx+STREAM.out_count], eax |
mov dword [edx+STREAM.time_base], eax |
mov dword [edx+STREAM.time_base+4], eax |
mov dword [edx+STREAM.time_stamp], eax |
mov dword [edx+STREAM.time_stamp+4], eax |
mov dword [edx+STREAM.last_ts], eax |
mov eax, [edx+STREAM.r_silence] |
test [flags], 1 |
jz @F |
mov ecx, [edx+STREAM.in_top] |
mov edi, [edx+STREAM.in_base] |
sub ecx, edi |
shr ecx, 2 |
cld |
rep stosd |
@@: |
test [flags], 2 |
jz @F |
mov edi, [edx+STREAM.out_base] |
mov ecx, (64*1024)/4 |
rep stosd |
@@: |
ret |
.fail: |
or eax, -1 |
ret |
endp |
; for static buffers only |
align 4 |
proc SetBufferPos stdcall, str:dword, pos:dword |
mov edx, [str] |
test [edx+STREAM.format], PCM_STATIC |
jz .fail |
mov [edx+STREAM.flags], SND_STOP |
mov eax, [pos] |
add eax, [edx+STREAM.in_base] |
mov ebx, [edx+STREAM.in_top] |
add eax, 128 |
cmp eax, ebx |
jae .fail |
mov [edx+STREAM.in_rp], eax |
sub ebx, eax |
mov [edx+STREAM.in_count], ebx |
xor eax, eax |
ret |
.fail: |
or eax, -1 |
ret |
endp |
align 4 |
proc GetBufferPos stdcall, str:dword |
mov edx, [str] |
test [edx+STREAM.format], PCM_STATIC |
jz .fail |
mov ebx, [edx+STREAM.in_rp] |
sub ebx, [edx+STREAM.in_base] |
sub ebx, 128 |
xor eax, eax |
ret |
.fail: |
xor ebx, ebx |
or eax, -1 |
ret |
endp |
; both |
align 4 |
proc SetBufferVol stdcall, str:dword,l_vol:dword,r_vol:dword |
mov edx, [str] |
stdcall set_vol_param, [l_vol], [r_vol], [edx+STREAM.pan] |
ret |
endp |
proc minw stdcall, arg1:dword, arg2:dword |
mov ax, word [arg1] |
cmp ax, word [arg2] |
jle @f |
mov eax, [arg2] |
@@: |
ret |
endp |
proc maxw stdcall, arg1:dword, arg2:dword |
mov ax, word [arg1] |
cmp ax, word [arg2] |
jge @f |
mov eax, [arg2] |
@@: |
ret |
endp |
proc set_vol_param stdcall, l_vol:dword,r_vol:dword,pan:dword |
locals |
_600 dd ? |
_32767 dd ? |
state rb 108 |
endl |
mov [_600], 0x44160000 ;600.0 |
mov [_32767], 32767 |
lea ebx, [state] |
fnsave [ebx] |
stdcall minw, [l_vol], [vol_max] |
stdcall maxw, eax, [vol_min] |
mov [l_vol], eax |
mov [edx+STREAM.l_vol], eax |
stdcall minw, [r_vol], [vol_max+4] |
stdcall maxw, eax, [vol_min+4] |
mov [r_vol], eax |
mov [edx+STREAM.r_vol], eax |
stdcall minw, [pan], [pan_max] |
stdcall maxw, eax, [vol_min] |
mov [edx+STREAM.pan], eax |
cmp word [edx+STREAM.pan], 0 |
jl @f |
mov ebx, [l_vol] |
sub ebx, eax |
stdcall minw, ebx, [vol_max] |
stdcall maxw, eax, [vol_min] |
mov [l_vol], eax |
jmp .calc_amp |
@@: |
mov ebx, [r_vol] |
add ebx, [pan] |
stdcall minw, ebx, [vol_max+4] |
stdcall maxw, eax, [vol_min+4] |
mov [r_vol], eax |
.calc_amp: |
emms |
fild word [l_vol] |
call .calc |
fistp word [edx+STREAM.l_amp] |
fstp dword [edx+STREAM.l_amp_f] |
fstp st0 |
fild word [r_vol] |
call .calc |
fistp word [edx+STREAM.r_amp] |
fstp dword [edx+STREAM.r_amp_f] |
fstp st0 |
fnclex |
lea ebx, [state] |
frstor [ebx] |
xor eax, eax |
inc eax |
ret |
.calc: |
fdiv dword [_600] |
fld st0 |
frndint |
fxch st1 |
fsub st, st1 |
f2xm1 |
fld1 |
faddp st1, st0 |
fscale |
fld st0 |
fimul dword [_32767] |
ret 0 |
endp |
align 4 |
proc GetBufferVol stdcall, str:dword,p_lvol:dword,p_rvol:dword |
mov edx, [str] |
mov eax, [p_lvol] |
movsx ecx, word [edx+STREAM.l_vol] |
mov [eax], ecx |
mov eax, [p_rvol] |
movsx ecx, word [edx+STREAM.r_vol] |
mov [eax], ecx |
xor eax, eax |
ret |
endp |
align 4 |
proc SetBufferPan stdcall, str:dword,pan:dword |
mov edx, [str] |
stdcall set_vol_param, [edx+STREAM.l_vol], \ |
[edx+STREAM.r_vol],[pan] |
ret |
endp |
; for static and ring buffers only |
align 4 |
proc play_buffer stdcall, str:dword, flags:dword |
mov ebx, [str] |
mov eax, [ebx+STREAM.format] |
test eax, PCM_OUT |
jnz .fail |
cmp ax, PCM_ALL |
je .fail |
mov [ebx+STREAM.flags], SND_PLAY |
cmp [eng_state], SND_PLAY |
je .done |
stdcall dev_play, [hSound] |
mov [eng_state], SND_PLAY |
.done: |
test [flags], PLAY_SYNC |
jz @F |
mov edx, [str] |
.wait: |
mov eax, [edx+STREAM.notify_event] |
mov ebx, [edx+STREAM.notify_id] |
call WaitEvent ;eax ebx |
mov edx, [str] |
cmp [edx+STREAM.flags], SND_STOP |
jne .wait |
@@: |
xor eax, eax |
ret |
.fail: |
or eax, -1 |
ret |
endp |
; for static and ring buffers only |
align 4 |
proc stop_buffer stdcall, str:dword |
mov edx, [str] |
test [edx+STREAM.format], PCM_STATIC+PCM_RING |
jz .fail |
mov [edx+STREAM.flags], SND_STOP |
mov eax, [edx+STREAM.notify_event] |
mov ebx, [edx+STREAM.notify_id] |
call ClearEvent ;eax ebx |
xor eax, eax |
ret |
.fail: |
or eax, -1 |
ret |
endp |
; param |
; eax= mix_list |
align 4 |
do_mix_list: |
xor edx, edx |
mov esi, str.fd-FD_OFFSET |
mov ebx, [esi+STREAM.str_fd] |
@@: |
cmp ebx, esi |
je .done |
cmp [ebx+STREAM.magic], 'WAVE' |
jne .next |
cmp [ebx+STREAM.size], STREAM.sizeof |
jne .next |
cmp [ebx+STREAM.flags], SND_PLAY; |
jne .next |
mov ecx, [ebx+STREAM.out_count] |
test ecx, ecx |
jnz .l1 |
test [ebx+STREAM.format], PCM_RING |
jnz .next |
mov [ebx+STREAM.flags], SND_STOP |
jmp .next |
.l1: |
cmp ecx, 512 |
jae .add_buff |
mov edi, [ebx+STREAM.out_rp] |
add edi, ecx |
sub ecx, 512 |
neg ecx |
push eax |
xor eax, eax |
cld |
rep stosb |
pop eax |
mov [ebx+STREAM.out_count], 512 |
.add_buff: |
mov ecx, [ebx+STREAM.out_rp] |
mov [eax], ecx |
if USE_SSE2_MIXER |
mov edi, dword [ebx+STREAM.l_amp_f] |
mov [eax+4], edi |
mov edi, dword [ebx+STREAM.r_amp_f] |
mov [eax+8], edi |
else |
mov edi, dword [ebx+STREAM.l_amp] |
mov [eax+4], edi |
end if |
add [ebx+STREAM.out_rp], 512 |
sub [ebx+STREAM.out_count], 512 |
add eax, 12 |
inc edx |
.next: |
mov ebx, [ebx+STREAM.str_fd] |
jmp @B |
.done: |
mov eax, edx |
ret |
align 4 |
prepare_playlist: |
xor edx, edx |
mov [play_count], edx |
mov esi, str.fd-FD_OFFSET |
mov edi, [esi+STREAM.str_fd] |
@@: |
cmp edi, esi |
je .done |
cmp [edi+STREAM.magic], 'WAVE' |
jne .next |
cmp [edi+STREAM.size], STREAM.sizeof |
jne .next |
cmp [edi+STREAM.flags], SND_PLAY; |
jne .next |
mov [play_list+edx], edi |
inc [play_count] |
add edx, 4 |
.next: |
mov edi, [edi+STREAM.str_fd] |
jmp @B |
.done: |
ret |
align 4 |
proc set_handler stdcall, hsrv:dword, handler_proc:dword |
locals |
handler dd ? |
io_code dd ? |
input dd ? |
inp_size dd ? |
output dd ? |
out_size dd ? |
val dd ? |
endl |
mov eax, [hsrv] |
lea ecx, [handler_proc] |
xor ebx, ebx |
mov [handler], eax |
mov [io_code], DEV_CALLBACK |
mov [input], ecx |
mov [inp_size], 4 |
mov [output], ebx |
mov [out_size], 0 |
lea eax, [handler] |
stdcall ServiceHandler, eax |
ret |
endp |
align 4 |
proc dev_play stdcall, hsrv:dword |
locals |
handle dd ? |
io_code dd ? |
input dd ? |
inp_size dd ? |
output dd ? |
out_size dd ? |
val dd ? |
endl |
mov eax, [hsrv] |
xor ebx, ebx |
mov [handle], eax |
mov [io_code], DEV_PLAY |
mov [input], ebx |
mov [inp_size], ebx |
mov [output], ebx |
mov [out_size], ebx |
lea eax, [handle] |
stdcall ServiceHandler, eax |
ret |
endp |
if 0 |
align 4 |
dword2str: |
mov esi, hex_buff |
mov ecx, -8 |
@@: |
rol eax, 4 |
mov ebx, eax |
and ebx, 0x0F |
mov bl, [ebx+hexletters] |
mov [8+esi+ecx], bl |
inc ecx |
jnz @B |
ret |
hexletters db '0123456789ABCDEF' |
hex_buff db 8 dup(0),13,10,0 |
end if |
include 'mixer.asm' |
include 'mix_mmx.inc' |
include 'mix_sse2.inc' |
;if USE_SSE |
; include 'mix_sse.inc' |
;end if |
align 16 |
resampler_params: |
;r_size r_dt resampler_func |
dd 0,0,0 ; 0 PCM_ALL |
dd 16384, 0, copy_stream ; 1 PCM_2_16_48 |
dd 8192, 0, m16_stereo ; 2 PCM_1_16_48 |
dd 16384, 30109, resample_2 ; 3 PCM_2_16_44 |
dd 8192, 30109, resample_1 ; 4 PCM_1_16_44 |
dd 16384, 21846, resample_2 ; 5 PCM_2_16_32 |
dd 8192, 21846, resample_1 ; 6 PCM_1_16_32 |
dd 16384, 16384, resample_2 ; 7 PCM_2_16_24 |
dd 8192, 16384, resample_1 ; 8 PCM_1_16_24 |
dd 8192, 15052, resample_2 ; 9 PCM_2_16_22 |
dd 4096, 15052, resample_1 ;10 PCM_1_16_22 |
dd 8192, 10923, resample_2 ;11 PCM_2_16_16 |
dd 4096, 10923, resample_1 ;12 PCM_1_16_16 |
dd 8192, 8192, resample_2 ;13 PCM_2_16_12 |
dd 4096, 8192, resample_1 ;14 PCM_1_16_12 |
dd 4096, 7527, resample_2 ;15 PCM_2_16_11 |
dd 2048, 7527, resample_1 ;16 PCM_1_16_11 |
dd 4096, 5462, resample_2 ;17 PCM_2_16_8 |
dd 2048, 5462, resample_1 ;18 PCM_1_16_8 |
dd 16384, 0, s8_stereo ;19 PCM_2_8_48 |
dd 8192, 0, m8_stereo ;20 PCM_1_8_48 |
dd 8192, 30109, resample_28 ;21 PCM_2_8_44 |
dd 4096, 30109, resample_18 ;22 PCM_1_8_44 |
dd 8192, 21846, resample_28 ;23 PCM_2_8_32 |
dd 4096, 21846, resample_18 ;24 PCM_1_8_32 |
dd 8192, 16384, resample_28 ;25 PCM_2_8_24 |
dd 4096, 16384, resample_18 ;26 PCM_1_8_24 |
dd 4096, 15052, resample_28 ;27 PCM_2_8_22 |
dd 2048, 15052, resample_18 ;28 PCM_1_8_22 |
dd 4096, 10923, resample_28 ;29 PCM_2_8_16 |
dd 2048, 10923, resample_18 ;30 PCM_1_8_16 |
dd 4096, 8192, resample_28 ;31 PCM_2_8_12 |
dd 2048, 8192, resample_18 ;32 PCM_1_8_12 |
dd 2048, 7527, resample_28 ;33 PCM_2_8_11 |
dd 1024, 7527, resample_18 ;34 PCM_1_8_11 |
dd 2048, 5462, resample_28 ;35 PCM_2_8_8 |
dd 1024, 5462, resample_18 ;36 PCM_1_8_8 |
m7 dw 0x8000,0x8000,0x8000,0x8000 |
mm80 dq 0x8080808080808080 |
mm_mask dq 0xFF00FF00FF00FF00 |
vol_max dd 0x00000000,0x00000000 |
vol_min dd 0x0000D8F0,0x0000D8F0 |
pan_max dd 0x00002710,0x00002710 |
;stream_map dd 0xFFFF ; 16 |
version dd (5 shl 16) or SOUND_VERSION |
szInfinity db 'INFINITY',0 |
szSound db 'SOUND',0 |
if DEBUG |
msgFail db 'Sound service not loaded',13,10,0 |
msgPlay db 'Play buffer',13,10,0 |
msgStop db 'Stop',13,10,0 |
msgUser db 'User callback',13,10,0 |
msgMem db 'Not enough memory',13,10,0 |
msgDestroy db 'Destroy sound buffer', 13,10,0 |
msgWaveout db 'Play waveout', 13,10,0 |
msgSetVolume db 'Set volume',13,10,0 |
end if |
section '.data' data readable writable align 16 |
play_list rd 16 |
mix_input rd 16 |
play_count rd 1 |
hSound rd 1 |
eng_state rd 1 |
mix_buff rd 1 |
mix_buff_map rd 1 |
str.fd rd 1 |
str.bk rd 1 |
mix_2_core rd 1 |
mix_3_core rd 1 |
mix_4_core rd 1 |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
/kernel/branches/Kolibri-acpi/drivers/sb16/CONFIG.INC |
---|
0,0 → 1,57 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;flags------------------------------------------------------------ |
DEBUG equ 1 ;show messages at debug board |
use_cli_sti equ 1 ;driver become more stable (theoretically) |
;constants-------------------------------------------------------- |
API_VERSION equ 0 ;debug |
OS_BASE equ 0x80000000 |
new_app_base equ 0x0 |
PROC_BASE equ (OS_BASE+0x080000) |
SB16Buffer equ (OS_BASE+0x2A0000) |
SB16_Status equ (OS_BASE+0x2B0000) |
DMAPage equ ((SB16Buffer-OS_BASE) shr 16) |
SB16Buffer0 equ SB16Buffer |
SB16Buffer1 equ (SB16Buffer+16384) |
SB16Buffer2 equ (SB16Buffer+(2*16384)) |
SB16Buffer3 equ (SB16Buffer+(3*16384)) |
sb_irq_num equ 5 ;default values for SB16, may be overrided by autodetect |
sb_dma_num equ 5 ;default values for SB16, may be overrided by autodetect |
small_buffer equ 32768 |
full_buffer equ 65536 |
sb_buffer_size equ small_buffer ; FIX ring buffer overlapped events issue; full_buffer |
__supported_buffer_sizes fix <small_buffer, full_buffer> |
if ~(sb_buffer_size in __supported_buffer_sizes) |
display 13,10,'unsupported buffer size was selected, check config.inc',13,10 |
stop |
end if |
sb_out_rate equ 48000 |
;time constant for cards older than SB16 |
sb_tc equ (256-(1000000/(sb_out_rate*2))) |
SRV_GETVERSION equ 0 |
DEV_PLAY equ 1 |
DEV_STOP equ 2 |
DEV_CALLBACK equ 3 |
DEV_SET_BUFF equ 4 |
DEV_NOTIFY equ 5 |
DEV_SET_MASTERVOL equ 6 |
DEV_GET_MASTERVOL equ 7 |
DEV_GET_INFO equ 8 |
DRV_ENTRY equ 1 |
DRV_EXIT equ -1 |
/kernel/branches/Kolibri-acpi/drivers/sb16/sb16.asm |
---|
0,0 → 1,398 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
format MS COFF |
include 'CONFIG.INC' |
;structs---------------------------------------------------------- |
struc IOCTL |
{ .handle dd ? |
.io_code dd ? |
.input dd ? |
.inp_size dd ? |
.output dd ? |
.out_size dd ? |
} |
virtual at 0 |
IOCTL IOCTL |
end virtual |
;something-------------------------------------------------------- |
public START |
public service_proc |
public version |
include '..\proc32.inc' |
include '..\imports.inc' |
section '.flat' code readable align 16 |
include 'SB16.INC' |
;------------------------------------------------------------------------------- |
proc START stdcall, state:dword |
cmp [state], 1 |
jne .stop |
.entry: |
if DEBUG |
mov esi, msgInit |
call SysMsgBoardStr |
end if |
call detect ;returns DSP version or zero if |
test eax, eax ;SB card not found |
jz .exit |
if DEBUG |
movzx eax, al ;major version |
mov esi, sb_DSP_description |
dec eax |
jz .sb_say_about_found_dsp |
mov dword[esi], '2.x ' |
dec eax |
jz .sb_say_about_found_dsp |
mov dword[esi], 'Pro ' |
dec eax |
jz .sb_say_about_found_dsp |
mov dword[esi], '16 ' |
.sb_say_about_found_dsp: |
mov esi, msgDSPFound |
call SysMsgBoardStr |
end if |
; xor eax,eax |
; mov ebx,[sb_base_port] |
; lea ecx,[ebx+0xF] |
xor ebx, ebx |
mov ecx, [sb_base_port] |
lea edx, [ebx+0xF] |
call ReservePortArea ;these ports must be my! |
if DEBUG |
dec eax |
jnz @f |
mov esi, msgErrRsrvPorts |
call SysMsgBoardStr |
@@: |
end if |
call sb_setup ;clock it, etc |
stdcall AttachIntHandler, sb_irq_num, sb_irq, 0 |
if DEBUG |
test eax, eax |
jnz @f |
mov esi, msgErrAtchIRQ |
call SysMsgBoardStr |
; stdcall GetIntHandler, sb_irq_num |
; call SysMsgBoardNum |
jmp .stop |
@@: |
mov esi, msgSucAtchIRQ |
call SysMsgBoardStr |
end if |
stdcall RegService, my_service, service_proc |
ret |
.stop: |
call sb_reset |
.exit: |
if DEBUG |
mov esi, msgExit |
call SysMsgBoardStr |
end if |
xor eax, eax |
ret |
endp |
;------------------------------------------------------------------------------- |
handle equ IOCTL.handle |
io_code equ IOCTL.io_code |
input equ IOCTL.input |
inp_size equ IOCTL.inp_size |
output equ IOCTL.output |
out_size equ IOCTL.out_size |
align 4 |
proc service_proc stdcall, ioctl:dword |
mov edi, [ioctl] |
mov eax, [edi+io_code] |
cmp eax, SRV_GETVERSION |
jne @F |
mov eax, [edi+output] |
cmp [edi+out_size], 4 |
jne .fail |
mov [eax], dword API_VERSION |
xor eax, eax |
ret |
@@: |
cmp eax, DEV_PLAY |
jne @f |
if DEBUG |
mov esi, msgPlay |
call SysMsgBoardStr |
end if |
call sb_stop ;to play smth new we must stop smth old |
call pre_fill_data ;fill first and second half of the buffer |
call pre_fill_data ; |
call sb_set_dma ;is it really needed here? Paranoia. |
call sb_play |
xor eax, eax ;set maximum volume |
call sb_set_master_vol |
xor eax, eax |
ret |
;@@: ;all this commented stuff in service proc |
; cmp eax,DEV_STOP ;is never used. Mixer do this virtually, |
; jne @f ;e.g. instead of stopping driver it |
;if DEBUG ;outputs silence |
; mov esi,msgStop |
; call SysMsgBoardStr |
;end if |
; call sb_stop |
; xor eax,eax |
; ret |
@@: |
cmp eax, DEV_CALLBACK |
jne @f |
if DEBUG |
mov esi, msgCallback |
call SysMsgBoardStr |
end if |
mov edi, [edi+input] |
mov eax, [edi] |
mov [callback], eax |
if DEBUG |
call SysMsgBoardNum |
end if |
xor eax, eax |
ret |
@@: |
cmp eax, DEV_SET_MASTERVOL;Serge asked me to unlock |
jne @F ;DEV_SET(GET)_MASTERVOL, although mixer doesn't use it. |
;It doesn't use it _in current version_ - but in the future... |
if DEBUG |
mov esi, msgSetVol |
call SysMsgBoardStr |
end if |
mov eax, [edi+input] |
mov eax, [eax] |
call sb_set_master_vol |
xor eax, eax |
ret |
@@: |
cmp eax, DEV_GET_MASTERVOL |
jne @F |
if DEBUG |
mov esi, msgGetVol |
call SysMsgBoardStr |
end if |
mov eax, [edi+output] |
mov edx, [sb_master_vol] |
mov [eax], edx |
xor eax, eax |
ret |
.fail: |
or eax, -1 |
ret |
endp |
restore handle |
restore io_code |
restore input |
restore inp_size |
restore output |
restore out_size |
;------------------------------------------------------------------------------- |
align 4 |
proc sb_irq |
mov edx, [sb_base_port];tell the DSP that we have processed IRQ |
add dl, 0xF ;0xF for 16 bit sound, 0xE for 8 bit sound |
in al, dx ;for non-stop sound |
pre_fill_data: |
mov eax, int_flip_flop |
not dword[eax] |
mov eax, [eax] |
test eax, eax |
jns .fill_second_half |
if sb_buffer_size eq small_buffer |
stdcall [callback], SB16Buffer0 ;for 32k buffer |
else if sb_buffer_size eq full_buffer |
stdcall [callback], SB16Buffer0 ;for 64k buffer |
stdcall [callback], SB16Buffer1 ;for 64k buffer |
end if |
xor eax, eax |
not eax |
ret |
.fill_second_half: |
if sb_buffer_size eq small_buffer |
stdcall [callback], SB16Buffer1 ;for 32k buffer |
else if sb_buffer_size eq full_buffer |
stdcall [callback], SB16Buffer2 ;for 64k buffer |
stdcall [callback], SB16Buffer3 ;for 64k buffer |
end if |
xor eax, eax |
not eax |
ret |
endp |
;------------------------------------------------------------------------------- |
align 4 |
proc detect |
.sb_detect_next_port: |
if DEBUG |
inc dword[port_second_digit_num] |
end if |
mov edx, sb_base_port |
add byte[edx], 10h |
cmp byte[edx], 80h |
jbe .sb_try_to_detect_at_specified_port |
;error - no SB card detected |
.sb_not_found_err: |
xor eax, eax |
ret |
.sb_try_to_detect_at_specified_port: |
call sb_reset |
add dl, 8 |
mov ecx, 100 |
.sb_check_port: |
in al, dx |
test al, al ;is DSP port ready to be read? |
jns .sb_port_not_ready |
sub dl, 4 |
in al, dx ;check for AAh response |
add dl, 4 |
cmp al, 0xAA |
jne .sb_port_not_ready |
.sb_card_found: |
and dl, 0xF0 |
add dl, 0xC |
sb_out 0xE1 ;get DSP version |
add dl, 2 |
@@: |
in al, dx |
test al, al ;is DSP port ready to be read? |
jns @b |
sub dl, 4 |
in al, dx ;get major version |
ror eax, 16 |
add dl, 4 |
@@: |
in al, dx |
test al, al ;is DSP port ready to be read? |
jns @b |
sub dl, 4 |
in al, dx ;get minor version |
xor edx, edx |
mov dl, 10 |
div dl |
ror eax, 16 |
xor ah, ah |
mov [sb_DSP_version_int], eax;for internal usage |
if DEBUG |
add [sb_DSP_version], eax |
end if |
ret |
.sb_port_not_ready: |
loop .sb_check_port ;100 retries (~100 microsec.) |
jmp .sb_detect_next_port |
endp |
;------------------------------------------------------------------------------- |
if DEBUG |
proc SysMsgBoardNum ;warning: destroys eax,ebx,ecx,esi |
mov ebx, eax |
mov ecx, 8 |
mov esi, (number_to_out+1) |
.1: |
mov eax, ebx |
and eax, 0xF |
add al, '0' |
cmp al, (10+'0') |
jb @f |
add al, ('A'-'0'-10) |
@@: |
mov [esi+ecx], al |
shr ebx, 4 |
loop .1 |
dec esi |
call SysMsgBoardStr |
ret |
endp |
end if |
;all initialized data place here |
align 4 |
version dd (5 shl 16) or (API_VERSION and 0xFFFF) |
sb_base_port: |
dd 200h ;don't ask me why - see the code&docs |
sound_dma dd sb_dma_num |
;note that 4th DMA channel doesn't exist, it is used for cascade |
;plugging the first DMA controler to the second |
dma_table db 0x87,0x83,0x81,0x82,0xFF,0x8B,0x89,0x8A |
my_service db 'SOUND',0 ;max 16 chars include zero |
if DEBUG |
number_to_out db '0x00000000',13,10,0 |
msgInit db 'detecting hardware...',13,10,0 |
msgExit db 'exiting... May be some problems found?',13,10,0 |
msgPlay db 'start play',13,10,0 |
;msgStop db 'stop play',13,10,0 |
msgCallback db 'set_callback received from the mixer!',13,10 |
db 'callback handler is: ',0 |
msgErrAtchIRQ db 'failed to attach IRQ',(sb_irq_num+'0'),13,10 |
db 'owner',39,'s handler: ',0 |
msgSucAtchIRQ db 'succesfully attached IRQ',(sb_irq_num+'0') |
db ' as hardcoded',13,10,0 |
msgErrRsrvPorts db 'failed to reserve needed ports.',13,10 |
db 'Driver may work unstable',13,10,0 |
msgSetVol db 'DEV_SET_MASTERVOL call came',13,10,0 |
msgGetVol db 'DEV_GET_MASTERVOL call came',13,10,0 |
msgErrDMAsetup db 'failed to setup DMA - bad channel',13,10,0 |
;------------------------------------------------------------------------------- |
msgDSPFound db 'DSP found at port 2' |
label port_second_digit_num dword at $ |
db '00h',13,10,'DSP version ' |
sb_DSP_version: |
db '0.00 - SB' |
sb_DSP_description: |
db 32,32,32,32,13,10,0 |
;------------------------------------------------------------------------------- |
end if |
section '.data' data readable writable align 16 |
;all uninitialized data place here |
;pTempBuf rd 1 |
callback rd 1 |
int_flip_flop rd 1 |
sb_master_vol rd 1 |
sb_DSP_version_int rd 1 |
/kernel/branches/Kolibri-acpi/drivers/sb16/SB16.INC |
---|
0,0 → 1,304 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;-------------------------------- |
; program dma |
;-------------------------------- |
sb_set_dma: |
mov ebx, [sound_dma] |
lea eax, [ebx+4];mask required channel |
cmp bl, 4 |
ja .use_second_dma_controller |
jb @f |
.dma_setup_error: |
if DEBUG |
mov esi, msgErrDMAsetup |
call SysMsgBoardStr |
end if |
mov dword[esp], START.stop |
ret |
@@: |
if use_cli_sti |
cli ;here to minimize time with disabled ints |
end if |
out 0xA, al;mask required channel |
xor eax, eax |
out 0xC, al;clear byte pointer flip-flop register |
lea eax, [ebx+0x58];auto-init mode for channel (ebx) |
out 0xB, al;DMA channel 0-3 mode register |
movzx edx, byte[ebx+dma_table];page register |
mov al, DMAPage |
out dx, al |
lea edx, [ebx*2];DMA channel 0-3 base address |
mov al, 0;LSB is 0 |
out dx, al |
; mov al,0 ;MSB is 0 too |
out dx, al |
inc edx ;DMA channel 0-3 byte count |
mov al, ((sb_buffer_size-1) and 0xff) |
out dx, al |
mov al, ((sb_buffer_size-1) shr 8);it is the same |
out dx, al |
mov eax, ebx;unmask DMA channel |
out 0xA, al |
if use_cli_sti |
sti |
end if |
ret |
.use_second_dma_controller: |
cmp bl, 7 |
ja .dma_setup_error |
sub bl, 4 |
sub al, 4 |
if use_cli_sti |
cli ;here to minimize time with disabled ints |
end if |
out 0xD4, al;mask required channel |
xor eax, eax |
out 0xD8, al;clear byte pointer flip-flop register |
lea eax, [ebx+0x58];auto-init mode for channel (ebx+4) |
out 0xD6, al;DMA channel 4-7 mode register |
movzx edx, byte[ebx+dma_table+4];page register |
mov al, DMAPage |
out dx, al |
lea edx, [ebx*4+0xC0];DMA channel 4-7 base address |
mov al, 0;LSB is 0 ;for 16bit DMA this contains |
out dx, al;A1-A8 lines of address bus, A0 is zero |
; mov al,0 ;MSB is 0 too ;for 16bit DMA this contains |
out dx, al;A9-A16 lines of address bus |
inc edx |
inc edx ;DMA channel 4-7 16bit word count |
mov al, (((sb_buffer_size/2)-1) and 0xff) |
out dx, al |
mov al, (((sb_buffer_size/2)-1) shr 8) |
out dx, al |
mov eax, ebx;unmask DMA channel |
out 0xD4, al |
if use_cli_sti |
sti |
end if |
ret |
;------------------------------------------------------------------------------- |
; out byte to SB DSP's write port |
;------------------------------------------------------------------------------- |
macro sb_out data_to_out { |
@@: |
in al, dx |
test al, al;is DSP busy? |
js @b ;it's busy |
mov al, data_to_out;it's free |
out dx, al |
} |
;------------------------------------------------------------------------------- |
; stop playing |
;------------------------------------------------------------------------------- |
proc sb_stop |
mov edx, [sb_base_port] |
add dl, 0xC |
sb_out 0xD3 ;turn the speaker off |
sb_out 0xDA ;exit 8bit DMA |
sb_out 0xD9 ;exit 16bit DMA |
ret |
endp |
;------------------------------------------------------------------------------- |
; start playing |
;------------------------------------------------------------------------------- |
proc sb_play |
and [int_flip_flop], 0 |
mov edx, [sb_base_port] |
add dl, 0xC |
sb_out 0xD1 ;turn speaker on |
; sb_out 0x48 ;set DSP transfer size ;for older cards, not supported |
; ;in this version |
; mov ax,32767 ;(64k)/2-1 |
;@@: ;out the low byte... |
; in al,dx |
; test al,al ;is DSP busy? |
; js @b ;it's busy |
; out dx,al |
; mov al,ah ;...then the high byte |
;@@: |
; in al,dx |
; test al,al ;is DSP busy? |
; js @b ;it's busy |
; out dx,al |
; sb_out 0x1C ;auto-init 8bit playback |
; 0xBXh - 16 bit DMA mode |
; |||| |
sb_out 10110110b ;bCommand |
; |||| |
; |||+-reserved |
; ||+--turn FIFO on (0 for off) |
; |+---auto-init mode on (0 for off) |
; +----A/D: 0-output, 1-input |
; +------stereo on |
; |+-----unsigned (1 for signed) |
; || |
sb_out 00110000b ;bMode |
; || |||| |
; ---------reserved |
;wSize is a number of 16bit samples less 1. For auto-init mode each half |
;buffer is (64k)/2 bytes long and, obviously, contains ((64k)/2)/2 samples |
sb_out (((sb_buffer_size/2/2)-1) and 0xFF) ;wSize.LowByte |
sb_out (((sb_buffer_size/2/2)-1) shr 8) ;wSize.HighByte |
ret |
endp |
;------------------------------------------------------------------------------- |
; reset DSP |
;------------------------------------------------------------------------------- |
proc sb_reset |
and [int_flip_flop], 0 |
mov edx, [sb_base_port] |
add dl, 6 |
mov al, 1;start DSP reset |
if use_cli_sti |
cli ;here to minimize time with disabled ints |
end if |
out dx, al |
mov ecx, 40;wait at least 3 microsec. |
@@: |
in al, dx |
loop @b |
xor eax, eax;stop DSP reset |
if use_cli_sti |
sti |
end if |
out dx, al |
ret |
endp |
;------------------------------------------------------------------------------- |
; set the rate for playing, enable stereo |
;------------------------------------------------------------------------------- |
proc sb_setup |
mov edx, [sb_base_port] |
add dl, 0xC |
sb_out 40h ;set time constant, this is for old cards |
sb_out sb_tc |
sb_out 41h ;set sound rate, this can only SB16 |
sb_out (sb_out_rate shr 8) ;first high byte (MSB) |
sb_out (sb_out_rate and 0xff) ;then low byte (LSB) |
; mov al,0xE ;for older cards, not supported in this version |
; sub dl,(0xC-4) ;talk to SB's mixer |
; out dx,al ;select this register of the mixer |
; mov ecx,6 ;wait for the chip |
;@@: |
; in al,dx |
; loop @b |
; inc edx ;now read the data port |
; in al,dx |
; or al,22h ;turn on stereo |
; mov ah,al |
; mov al,0xE |
; dec edx ;talk to SB's mixer |
; out dx,al ;select this register of the mixer |
; mov ecx,6 ;wait for the chip |
;@@: |
; in al,dx |
; loop @b |
; inc edx ;now send data to the data port |
; mov al,ah |
; out dx,al |
; dec edx |
; mov ecx,35 ;wait for the chip |
;@@: |
; in al,dx |
; loop @b |
ret |
endp |
;------------------------------------------------------------------------------- |
; set master volume of SB mixer, note, not only SB16 but SBPro and older |
; this is the first step to more full support for hardware |
;------------------------------------------------------------------------------- |
;in: eax in range [-10000;0] - master volume for _both_ channels |
;note that x*3*17/2000 and x*3/2000*17 are not the same numbers, |
;because we count in integers |
proc sb_set_master_vol |
mov [sb_master_vol], eax |
add eax, 10000;SB sound level rise from 0 to MAX_LEVEL |
lea eax, [eax+eax*2];*3 |
mov ebx, 2000;divisor |
xor edx, edx |
cmp byte[sb_DSP_version_int], 4 |
jae @f ;SBPro's MAX_LEVEL is 15, but we *11 because |
;volume byte looks like that: 0xLR, where L - left |
;channel volume, R - right, 0<=R,L<=15 |
div ebx |
imul eax, 17 |
mov edx, [sb_base_port] |
push eax ;here for optimisation |
add dl, 4 |
mov al, 0x22;write mixer register 0x22 |
out dx, al |
in al, dx;wait for the chip ;6 |
in al, dx;wait for the chip ;5 |
in al, dx;wait for the chip ;4 |
in al, dx;wait for the chip ;3 |
in al, dx;wait for the chip ;2 |
in al, dx;wait for the chip ;1 |
pop eax ;go! |
inc edx |
out dx, al |
ret |
@@: ;SB16's MAX_LEVEL is 255 |
imul eax, 17 |
div ebx |
mov edx, [sb_base_port] |
push eax ;here for optimisation |
add dl, 4 |
mov al, 0x30;left speaker |
out dx, al |
pop eax ;<--+ |
inc edx ; \/ |
push eax ;here for optimisation |
out dx, al;write |
dec edx |
mov al, 0x31;right speaker |
out dx, al |
pop eax |
inc edx |
out dx, al;write |
ret |
endp |
;------------------------------------------------------------------------------- |
/kernel/branches/Kolibri-acpi/drivers/sb16/README.TXT |
---|
0,0 → 1,72 |
Nable 21.05.2008. |
This driver is my contribution (or donation) to KolibriOS. This is provided |
AS IS in hope it'll be useful, but WITHOUT ANY WARRANTY! No responcibility |
for any hardware damage or data loss. Use at your own risk! |
;------------------------------------------------------------------------------- |
;Changelog: |
;------------------------------------------------------------------------------- |
v0.2 - DEV_SET(GET)_MASTERVOL functions are unlocked and implemented. |
v0.1 - first release. |
;------------------------------------------------------------------------------- |
;Tiny FAQ for sound driver by Nable for SB16 sound card. |
;------------------------------------------------------------------------------- |
;What is it?-------------------------------------------------------------------- |
As you may know there is a sound subsystem ('INFINITY') in KolibriOS. |
This subsystem includes mixer and separate interface for soundplayer |
program and driver, so player application don't need to know what soundcard |
is installed and how to cope with it, all work with card do the driver. |
Before this time there were drivers only for AC97 integrated sound, but I |
don't have such at home and if I would upgrade my computer with a newest |
hardware, with 100% probability integrated sound will be HD Codec, nowadays |
AC97 is not actual (2008 year is at calendar). But I'm not planning to upgrade |
my computer so much now (and in next 5-6 years), writing the driver for my PCI |
ESS Maestro1 card is difficult for me (may be some time later), so I decided |
to write a driver for SB16. At first it is easy, there are many working |
examples for DOS, there are heaps of good documentation and as an ISA device |
SB16 can be programmed through I/O ports (about 5 ports are used), that is |
more easy than PCI access. Now, enough lirics, lets go to physics :-) |
If you still don't understand what stuff is it, I'll tell this in brief: |
with this driver you can play MP3 and WAV music (using AC97SND player) and |
sounds (some games and DOSBOX can produce sound output through sound |
subsystem) in KolibriOS. |
;Yeah! I need sound in Kolibri and I have SB16 card. Whats then?---------------- |
At first copy my SOUND.OBJ to /sys/drivers at your Kolibri system. Note, |
that if you have AC97 card and it's driver started - then new driver won't |
run until reboot. Then run BOARD and go to 'user' tab. Then try to run |
AC97SND player. At BOARD you will see the following (if you had a proper |
card): |
|----------------------------| |
|detecting hardware... | <- detector startup message |
|DSP found at port 220h | <- if you have a proper card, it'll be |
|DSP version 4.13 - SB16 | autodetected. Numbers may be different. |
|failed to attach IRQ5 | <- don't mention. Old kernels reserve IRQ5 |
|owner's handler: 0x80D74284 | see below how to fix it. |
|----------------------------| |
At first, note that DSP version must be 4.xx or higher. Older cards are not |
supported in this first release, maybe some time later. If nothing detected |
but PNP/BIOS or some other OS detects your card - I'm sorry, it's perverted |
PNP card like OPTi16, that is like HD Codec - until you init it through |
PCI->ISA bridge (HD Codec of course through PCI->PCI bridge), map it, etc, |
you can't use it in any way. I'd rather write a PCI device driver, than |
for this extreme perversion. If your card detected and has a proper version |
but you see 'failed to attach IRQ' - delete stroke 'mov [irq_owner+4*5],1' from the |
file kernel.asm of your kernel source, save it, rebuild kernel, copy new |
kernel to /sys/ (did you rename 'kernel' to 'kernel.mnt'? You should do it), |
restart kernel (Ctrl+Alt+F12, Home). THE EASIER WAY IS TO USE A NEWER KERNEL, |
since SVN802 it's fixed. |
Now everything should be OK. |
;It works for a part of the second and then stops, but system doesn't hang------ |
Go to 'config.inc' of my driver and change 'sb_irq_num' value from 5 to 7. |
Then save, rebuild driver (compile 'sound.asm'), put 'sound' to /sys/drivers/ |
(you need to rename file 'sound' to 'sound.obj'), restart kernel and try again |
to produce sound. |
;------------------------------------------------------------------------------- |
Ask your questions at KolibriOS forum: board.kolibrios.org |
I'll try to answer you if possible. |
/kernel/branches/Kolibri-acpi/drivers/sceletone.asm |
---|
0,0 → 1,173 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;driver sceletone |
format MS COFF |
DEBUG equ 1 |
API_VERSION equ 0 ;debug |
include 'proc32.inc' |
include 'imports.inc' |
struc IOCTL |
{ .handle dd ? |
.io_code dd ? |
.input dd ? |
.inp_size dd ? |
.output dd ? |
.out_size dd ? |
} |
virtual at 0 |
IOCTL IOCTL |
end virtual |
public START |
public service_proc |
public version |
DRV_ENTRY equ 1 |
DRV_EXIT equ -1 |
STRIDE equ 4 ;size of row in devices table |
SRV_GETVERSION equ 0 |
section '.flat' code readable align 16 |
proc START stdcall, state:dword |
cmp [state], 1 |
jne .exit |
.entry: |
if DEBUG |
mov esi, msgInit |
call SysMsgBoardStr |
end if |
stdcall RegService, my_service, service_proc |
ret |
.fail: |
.exit: |
xor eax, eax |
ret |
endp |
handle equ IOCTL.handle |
io_code equ IOCTL.io_code |
input equ IOCTL.input |
inp_size equ IOCTL.inp_size |
output equ IOCTL.output |
out_size equ IOCTL.out_size |
align 4 |
proc service_proc stdcall, ioctl:dword |
mov ebx, [ioctl] |
mov eax, [ebx+io_code] |
cmp eax, SRV_GETVERSION |
jne @F |
mov eax, [ebx+output] |
cmp [ebx+out_size], 4 |
jne .fail |
mov [eax], dword API_VERSION |
xor eax, eax |
ret |
@@: |
.fail: |
or eax, -1 |
ret |
endp |
restore handle |
restore io_code |
restore input |
restore inp_size |
restore output |
restore out_size |
align 4 |
proc detect |
locals |
last_bus dd ? |
endl |
xor eax, eax |
mov [bus], eax |
inc eax |
call PciApi |
cmp eax, -1 |
je .err |
mov [last_bus], eax |
.next_bus: |
and [devfn], 0 |
.next_dev: |
stdcall PciRead32, [bus], [devfn], dword 0 |
test eax, eax |
jz .next |
cmp eax, -1 |
je .next |
mov edi, devices |
@@: |
mov ebx, [edi] |
test ebx, ebx |
jz .next |
cmp eax, ebx |
je .found |
add edi, STRIDE |
jmp @B |
.next: |
inc [devfn] |
cmp [devfn], 256 |
jb .next_dev |
mov eax, [bus] |
inc eax |
mov [bus], eax |
cmp eax, [last_bus] |
jna .next_bus |
xor eax, eax |
ret |
.found: |
xor eax, eax |
inc eax |
ret |
.err: |
xor eax, eax |
ret |
endp |
DEVICE_ID equ 1234; pci device id |
VENDOR_ID equ 5678; device vendor id |
;all initialized data place here |
align 4 |
devices dd (DEVICE_ID shl 16)+VENDOR_ID |
dd 0 ;terminator |
version dd (5 shl 16) or (API_VERSION and 0xFFFF) |
my_service db 'MY_SERVICE',0 ;max 16 chars include zero |
msgInit db 'detect hardware...',13,10,0 |
msgPCI db 'PCI accsess not supported',13,10,0 |
msgFail db 'device not found',13,10,0 |
section '.data' data readable writable align 16 |
;all uninitialized data place here |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
/kernel/branches/Kolibri-acpi/drivers/tmpdisk_fat.inc |
---|
0,0 → 1,327 |
; FAT-specific code for tmpdisk.asm. |
; Formats a disk to FAT16 or FAT32, depending on size. |
; Note: formatting is adjusted for memory-based disks. Although the resulting |
; image is a valid FAT32 volume, it has no "spare" sectors, e.g. second copy |
; of FAT or place for second sector of MS FAT32 bootloader. |
; Some constants |
FAT16_ROOTDIR_SECTORS = 16 ; can be changed, but why not? |
; FAT16: |
; 1 bootsector, |
; min 0xFF5 sectors for data, |
; min (0xFF5*2/512) = 16 sectors per FAT, we use only one copy, |
; FAT16_ROOTDIR_SECTORS for root directory |
MIN_FAT16_SIZE = 1 + 16 + FAT16_ROOTDIR_SECTORS + 0xFF5 |
; FAT32: |
; 1 bootsector, |
; 1 sector for fsinfo, |
; min 0xFFF5 sectors for data, |
; min (0xFFF5*4/512) = 512 sectors per FAT, we use only one copy |
MIN_FAT32_SIZE = 1 + 1 + 512 + 0xFFF5 |
MAX_SIZE = 1 shl (30 - 9) ; 1G in 512-byte sectors |
; Initializes FATxx structures on the disk. |
; Called with edi = pointer to disk data, esi = size of disk. |
proc format_disk |
; Determine FAT type and jump to the corresponding handler. |
cmp esi, MIN_FAT32_SIZE |
jae format_disk_fat32 |
; Fall through to format_disk_fat16. |
endp |
; Structure of FAT16 bootsector. Field names are from MS spec. |
struc FAT16BOOT |
{ |
.BS_jmpBoot rb 3 |
.BS_OEMName rb 8 |
.BPB_BytsPerSec dw ? |
.BPB_SecsPerClus db ? |
.BPB_RsvdSecCnt dw ? |
.BPB_NumFATs db ? |
.BPB_RootEntCnt dw ? |
.BPB_TotSec16 dw ? |
.BPB_Media db ? |
.BPB_FATSz16 dw ? |
.BPB_SecPerTrk dw ? |
.BPB_NumHeads dw ? |
.BPB_HiddSec dd ? |
.BPB_TotSec32 dd ? |
.BS_DrvNum db ? |
.BS_Reserved1 db ? |
.BS_BootSig db ? |
.BS_VolID dd ? |
.BS_VolLab rb 11 |
.BS_FilSysType rb 8 |
} |
virtual at 0 |
FAT16BOOT FAT16BOOT |
end virtual |
; Initializes FAT16 structures on the disk. |
; Called with edi = pointer to disk data, esi = size of disk. |
format_disk_fat16: |
; 1. Calculate number of clusters. |
; 1a. There are fixed-sized areas and there are data+FAT; |
; every cluster uses 512 bytes in data area and 2 bytes in FAT area. |
lea eax, [esi-1-FAT16_ROOTDIR_SECTORS] |
; two following lines are equivalent to edx = floor(eax*512/514) |
mov ecx, 0xFF00FF01 |
mul ecx ; edx = number of clusters |
; 1b. Force the number be less than 0xfff5. |
mov eax, 0xFFF4 |
cmp edx, eax |
jb @f |
mov edx, eax |
@@: |
; 2. Zero all system areas on the disk. |
lea ecx, [256*(1+FAT16_ROOTDIR_SECTORS)+edx+255] |
and ecx, not 255 |
shr ecx, 1 |
xor eax, eax |
push edi |
rep stosd |
pop edi |
; 3. Generate the bootsector. |
; 3a. Copy static stub. |
push esi edi |
mov esi, fat16bootsector_stub |
mov ecx, fat16bootsector_stub_size |
rep movsb |
pop edi esi |
mov word [edi+510], 0xAA55 |
; 3b. Set fields which depend on size. |
cmp esi, 0x10000 |
jae .size_is_32bit |
mov [edi+FAT16BOOT.BPB_TotSec16], si |
jmp .size_written |
.size_is_32bit: |
mov [edi+FAT16BOOT.BPB_TotSec32], esi |
.size_written: |
lea eax, [edx+255] |
shr eax, 8 |
mov [edi+FAT16BOOT.BPB_FATSz16], ax |
; 3c. Generate volume ID. |
call generate_volume_id |
mov [edi+FAT16BOOT.BS_VolID], eax |
; 4. Initialize FAT. |
mov dword [edi+512], 0xFFFFFFF8 |
; 5. Return. |
ret |
; Structure of FAT32 bootsector. Field names are from MS spec. |
struc FAT32BOOT |
{ |
.BS_jmpBoot rb 3 |
.BS_OEMName rb 8 |
.BPB_BytsPerSec dw ? |
.BPB_SecsPerClus db ? |
.BPB_RsvdSecCnt dw ? |
.BPB_NumFATs db ? |
.BPB_RootEntCnt dw ? |
.BPB_TotSec16 dw ? |
.BPB_Media db ? |
.BPB_FATSz16 dw ? |
.BPB_SecPerTrk dw ? |
.BPB_NumHeads dw ? |
.BPB_HiddSec dd ? |
.BPB_TotSec32 dd ? |
.BPB_FATSz32 dd ? |
.BPB_ExtFlags dw ? |
.BPB_FSVer dw ? |
.BPB_RootClus dd ? |
.BPB_FSInfo dw ? |
.BPB_BkBootSec dw ? |
.BPB_Reserved rb 12 |
.BS_DrvNum db ? |
.BS_Reserved1 db ? |
.BS_BootSig db ? |
.BS_VolID dd ? |
.BS_VolLab rb 11 |
.BS_FilSysType rb 8 |
} |
virtual at 0 |
FAT32BOOT FAT32BOOT |
end virtual |
; Initializes FAT32 structures on the disk. |
; Called with edi = pointer to disk data, esi = size of disk. |
format_disk_fat32: |
; 1. Calculate number of clusters. |
; 1a. There is fixed-sized area and there are data+FAT; |
; every cluster uses 512 bytes in data area and 4 bytes in FAT area. |
lea eax, [esi-1-1] |
; two following lines are equivalent to edx=floor(eax*512/516) if eax<10000000h |
mov ecx, 0xFE03F810 |
mul ecx ; edx = number of clusters |
; 2. Zero all system areas on the disk and first cluster of data, |
; used for root directory. |
lea ecx, [128*(1+1+1)+edx+127] |
and ecx, not 127 |
xor eax, eax |
push edi |
rep stosd |
pop edi |
; 3. Generate the bootsector. |
; 3a. Copy static stub. |
push esi edi |
mov esi, fat32bootsector_stub |
mov ecx, fat32bootsector_stub_size |
rep movsb |
pop edi esi |
mov word [edi+510], 0xAA55 |
; 3b. Set fields which depend on size. |
mov [edi+FAT32BOOT.BPB_TotSec32], esi |
lea eax, [edx+127] |
shr eax, 7 |
mov [edi+FAT32BOOT.BPB_FATSz32], eax |
; 3c. Generate volume ID. |
call generate_volume_id |
mov [edi+FAT32BOOT.BS_VolID], eax |
; 4. Initialize fsinfo sector. |
mov dword [edi+512], 'RRaA' |
mov dword [edi+512+484], 'rrAa' |
dec edx ; one cluster is occupied by root dir |
mov dword [edi+512+488], edx ; free count |
mov byte [edi+512+492], 3 ; first free cluster |
mov word [edi+512+510], 0xAA55 |
; 5. Initialize FAT. |
mov dword [edi+512*2], 0x0FFFFFF8 |
mov dword [edi+512*2+4], 0x0FFFFFFF |
mov dword [edi+512*2+8], 0x0FFFFFFF |
; 6. Return. |
ret |
; Generate volume serial number, which should try to be unique for each volume. |
; Use CMOS date+time, copy-pasted from fat32.inc. |
generate_volume_id: |
call get_time_for_file |
mov cx, ax |
call get_date_for_file |
shl eax, 16 |
mov ax, cx |
ret |
; Three following procedures are copy-pasted from fat32.inc. |
bcd2bin: |
;---------------------------------- |
; input : AL=BCD number (eg. 0x11) |
; output : AH=0 |
; AL=decimal number (eg. 11) |
;---------------------------------- |
xor ah, ah |
shl ax, 4 |
shr al, 4 |
aad |
ret |
get_date_for_file: |
;----------------------------------------------------- |
; Get date from CMOS and pack day,month,year in AX |
; DATE bits 0..4 : day of month 0..31 |
; 5..8 : month of year 1..12 |
; 9..15 : count of years from 1980 |
;----------------------------------------------------- |
mov al, 0x7 ;day |
out 0x70, al |
in al, 0x71 |
call bcd2bin |
ror eax, 5 |
mov al, 0x8 ;month |
out 0x70, al |
in al, 0x71 |
call bcd2bin |
ror eax, 4 |
mov al, 0x9 ;year |
out 0x70, al |
in al, 0x71 |
call bcd2bin |
add ax, 20 ;because CMOS return only the two last |
;digit (eg. 2000 -> 00 , 2001 -> 01) and we |
rol eax, 9 ;need the difference with 1980 (eg. 2001-1980) |
ret |
get_time_for_file: |
;----------------------------------------------------- |
; Get time from CMOS and pack hour,minute,second in AX |
; TIME bits 0..4 : second (the low bit is lost) |
; 5..10 : minute 0..59 |
; 11..15 : hour 0..23 |
;----------------------------------------------------- |
mov al, 0x0 ;second |
out 0x70, al |
in al, 0x71 |
call bcd2bin |
ror eax, 6 |
mov al, 0x2 ;minute |
out 0x70, al |
in al, 0x71 |
call bcd2bin |
ror eax, 6 |
mov al, 0x4 ;hour |
out 0x70, al |
in al, 0x71 |
call bcd2bin |
rol eax, 11 |
ret |
; some data |
fat16bootsector_stub: |
db 0EBh, 3Ch, 90h ; BS_jmpBoot |
db 'KOLIBRI ' ; BS_OEMName |
dw 512 ; BPB_BytsPerSec |
db 1 ; BPB_SecsPerClus |
dw 1 ; BPB_RsvdSecCnt |
db 1 ; BPB_NumFATs |
dw FAT16_ROOTDIR_SECTORS*16 ; BPB_RootEntCnt |
dw 0 ; BPB_TotSec16, filled in format_disk_fat16 |
db 0F8h ; BPB_Media |
dw 0 ; BPB_FATSz16, filled in format_disk_fat16 |
dw 32 ; BPB_SecPerTrk |
dw 128 ; BPB_NumHeads |
dd 0 ; BPB_HiddSec |
dd 0 ; BPB_TotSec32, filled in format_disk_fat16 |
db 80h ; BS_DrvNum |
db 0 ; BS_Reserved1 |
db 29h ; BS_BootSig |
dd 0 ; BS_VolID, filled in format_disk_fat16 |
db 'NO NAME ' ; BS_VolLab |
db 'FAT16 ' ; BS_FilSysType |
; just in case add some meaningful bytes if someone tries to boot |
db 0CDh, 19h, 0EBh, 0FEh ; int 19h, jmp $ |
fat16bootsector_stub_size = $ - fat16bootsector_stub |
fat32bootsector_stub: |
db 0EBh, 58h, 90h ; BS_jmpBoot |
db 'KOLIBRI ' ; BS_OEMName |
dw 512 ; BPB_BytsPerSec |
db 1 ; BPB_SecsPerClus |
dw 2 ; BPB_RsvdSecCnt |
db 1 ; BPB_NumFATs |
dw 0 ; BPB_RootEntCnt |
dw 0 ; BPB_TotSec16 |
db 0F8h ; BPB_Media |
dw 0 ; BPB_FATSz16 |
dw 32 ; BPB_SecPerTrk |
dw 128 ; BPB_NumHeads |
dd 0 ; BPB_HiddSec |
dd 0 ; BPB_TotSec32, filled in format_disk_fat32 |
dd 0 ; BPB_FATSz32, filled in format_disk_fat32 |
dw 0 ; BPB_ExtFlags |
dw 0 ; BPB_FSVer |
dd 2 ; BPB_RootClus |
dw 1 ; BPB_FSInfo |
dw 0 ; BPB_BkBootSec |
rb 12 ; BPB_Reserved |
db 80h ; BS_DrvNum |
db 0 ; BS_Reserved1 |
db 29h ; BS_BootSig |
dd 0 ; BS_VolID, filled in format_disk_fat32 |
db 'NO NAME ' ; BS_VolLab |
db 'FAT32 ' ; BS_FilSysType |
; same bytes as in fat16bootsector_stub |
db 0CDh, 19h, 0EBh, 0FEh ; int 19h, jmp $ |
fat32bootsector_stub_size = $ - fat32bootsector_stub |
/kernel/branches/Kolibri-acpi/drivers/tmpdisk.asm |
---|
0,0 → 1,295 |
; Disk driver to create FAT16/FAT32 memory-based temporary disk aka RAM disk. |
; (c) CleverMouse |
; Note: in the ideal world, a disk driver should not care about a file system |
; on it. In the current world, however, there is no way to format a disk in |
; FAT, so this part of file-system-specific operations is included in the |
; driver. |
; When this driver is loading, it registers itself in the system and does |
; nothing more. When loaded, this driver controls pseudo-disk devices |
; named /tmp#/, where # is a digit from 0 to 9. The driver does not create |
; any device by itself, waiting for instructions from an application. |
; The driver responds to the following IOCTLs from a control application: |
SRV_GETVERSION equ 0 ; input ignored, |
; output = dword API_VERSION |
DEV_ADD_DISK equ 1 ; input = structure add_disk_struc, |
; no output |
DEV_DEL_DISK equ 2 ; input = structure del_disk_struc, |
; no output |
; For all IOCTLs the driver returns one of the following error codes: |
NO_ERROR equ 0 |
ERROR_INVALID_IOCTL equ 1 ; unknown IOCTL code, wrong input/output size... |
ERROR_INVALID_ID equ 2 ; .DiskId must be from 0 to 9 |
ERROR_SIZE_TOO_LARGE equ 3 ; .DiskSize is too large |
ERROR_SIZE_TOO_SMALL equ 4 ; .DiskSize is too small |
ERROR_NO_MEMORY equ 5 ; memory allocation failed |
API_VERSION equ 1 |
; Input structures: |
struc add_disk_struc |
{ |
.DiskSize dd ? ; disk size in sectors, 1 sector = 512 bytes |
; Note: .DiskSize is the full size, including FAT service data. |
; Size for useful data is slightly less than this number. |
.DiskId db ? ; from 0 to 9 |
.sizeof: |
} |
virtual at 0 |
add_disk_struc add_disk_struc |
end virtual |
struc del_disk_struc |
{ |
.DiskId db ? ; from 0 to 9 |
.sizeof: |
} |
virtual at 0 |
del_disk_struc del_disk_struc |
end virtual |
max_num_disks equ 10 |
; standard driver stuff |
format MS COFF |
DEBUG equ 0 |
include 'proc32.inc' |
include 'imports.inc' |
public START |
public version |
struc IOCTL |
{ |
.handle dd ? |
.io_code dd ? |
.input dd ? |
.inp_size dd ? |
.output dd ? |
.out_size dd ? |
} |
virtual at 0 |
IOCTL IOCTL |
end virtual |
section '.flat' code readable align 16 |
; the start procedure (see the description above) |
proc START |
; This procedure is called in two situations: |
; when the driver is loading and when the system is shutting down. |
; 1. Check that the driver is loading; do nothing unless so. |
xor eax, eax ; set return value in case we will do nothing |
cmp dword [esp+4], 1 |
jne .nothing |
; 2. Register the driver in the system. |
stdcall RegService, my_service, service_proc |
; 3. Return the value returned by RegService back to the system. |
.nothing: |
retn 4 |
endp |
; Service procedure for the driver - handle all IOCTL requests for the driver. |
; The description of handled IOCTLs is located in the start of this file. |
proc service_proc |
; 1. Save used registers to be stdcall. |
; Note: this shifts esp, so the first parameter [esp+4] becomes [esp+16]. |
; Note: edi is used not by this procedure itself, but by worker procedures. |
push ebx esi edi |
; 2. Get parameter from the stack: [esp+16] is the first parameter, |
; pointer to IOCTL structure. |
mov edx, [esp+16] ; edx -> IOCTL |
; 3. Set the return value to 'invalid IOCTL'. |
; Now, if one of conditions for IOCTL does not met, the code |
; can simply return the value already loaded. |
mov al, ERROR_INVALID_IOCTL |
; 4. Get request code and select a handler for the code. |
mov ecx, [edx+IOCTL.io_code] |
test ecx, ecx ; check for SRV_GETVERSION |
jnz .no.srv_getversion |
; 4. This is SRV_GETVERSION request, no input, 4 bytes output, API_VERSION. |
; 4a. Output size must be at least 4 bytes. |
cmp [edx+IOCTL.out_size], 4 |
jl .return |
; 4b. Write result to the output buffer. |
mov eax, [edx+IOCTL.output] |
mov dword [eax], API_VERSION |
; 4c. Return success. |
xor eax, eax |
jmp .return |
.no.srv_getversion: |
dec ecx ; check for DEV_ADD_DISK |
jnz .no.dev_add_disk |
; 5. This is DEV_ADD_DISK request, input is add_disk_struc, output is 1 byte |
; 5a. Input size must be exactly add_disk_struc.sizeof bytes. |
cmp [edx+IOCTL.inp_size], add_disk_struc.sizeof |
jnz .return |
; 5b. Load input parameters and call the worker procedure. |
mov eax, [edx+IOCTL.input] |
movzx ebx, [eax+add_disk_struc.DiskId] |
mov esi, [eax+add_disk_struc.DiskSize] |
call add_disk |
; 5c. Return back to the caller the value from the worker procedure. |
jmp .return |
.no.dev_add_disk: |
dec ecx ; check for DEV_DEL_DISK |
jnz .return |
; 6. This is DEV_DEL_DISK request, input is del_disk_struc |
; 6a. Input size must be exactly del_disk_struc.sizeof bytes. |
cmp [edx+IOCTL.inp_size], del_disk_struc.sizeof |
jnz .return |
; 6b. Load input parameters and call the worker procedure. |
mov eax, [edx+IOCTL.input] |
movzx ebx, [eax+del_disk_struc.DiskId] |
call del_disk |
; 6c. Return back to the caller the value from the worker procedure. |
.return: |
; 7. Exit. |
; 7a. The code above returns a value in al for efficiency, |
; propagate it to eax. |
movzx eax, al |
; 7b. Restore used registers to be stdcall. |
pop edi esi ebx |
; 7c. Return, popping one argument. |
retn 4 |
endp |
; The worker procedure for DEV_ADD_DISK request. |
; Creates a memory-based disk of given size and formats it in FAT16/32. |
; Called with ebx = disk id, esi = disk size, |
; returns error code in al. |
proc add_disk |
; 1. Check that disk id is correct and free. |
; Otherwise, return the corresponding error code. |
mov al, ERROR_INVALID_ID |
cmp ebx, max_num_disks |
jae .return |
cmp [disk_pointers+ebx*4], 0 |
jnz .return |
; 2. Check that the size is reasonable. |
; Otherwise, return the corresponding error code. |
mov al, ERROR_SIZE_TOO_LARGE |
cmp esi, MAX_SIZE |
ja .return |
mov al, ERROR_SIZE_TOO_SMALL |
cmp esi, MIN_FAT16_SIZE |
jb .return |
; 3. Allocate memory for the disk, store the pointer in edi. |
; If failed, return the corresponding error code. |
mov eax, esi |
shl eax, 9 |
stdcall KernelAlloc, eax |
mov edi, eax |
test eax, eax |
mov al, ERROR_NO_MEMORY |
jz .return |
; 4. Store the pointer and the size in the global variables. |
; It is possible, though very unlikely, that two threads |
; have called this function in parallel with the same id, |
; so [disk_pointers+ebx*4] could be filled by another thread. |
; Play extra safe and store new value only if old value is zero. |
xor eax, eax |
lock cmpxchg [disk_pointers+ebx*4], edi |
jz @f |
; Otherwise, free the allocated memory and return the corresponding error code. |
stdcall KernelFree, edi |
mov al, ERROR_INVALID_ID |
jmp .return |
@@: |
mov [disk_sizes+ebx*4], esi |
; 5. Call the worker procedure for formatting this disk. |
; It should not fail. |
call format_disk |
; 6. Register the disk in the system. |
; 6a. Generate name as /tmp#, where # = ebx + '0'. Use two dwords in the stack. |
push 0 |
push 'tmp' |
mov eax, esp ; eax points to 'tmp' + zero byte + zero dword |
lea ecx, [ebx+'0'] ; ecx = digit |
mov [eax+3], cl ; eax points to 'tmp#' + zero dword |
; 6b. Call the kernel API. Use disk id as 'userdata' parameter for callbacks. |
stdcall DiskAdd, disk_functions, eax, ebx, 0 |
; 6c. Restore the stack after 6a. |
pop ecx ecx |
; 6c. Check the result. If DiskAdd has failed, cleanup and return |
; ERROR_NO_MEMORY, this is the most probable or even the only reason to fail. |
test eax, eax |
jnz @f |
mov [disk_sizes+ebx*4], 0 |
mov [disk_pointers+ebx*4], 0 |
stdcall KernelFree, edi |
mov al, ERROR_NO_MEMORY |
jmp .return |
@@: |
push eax |
; 6d. Notify the kernel that media is inserted. |
stdcall DiskMediaChanged, eax, 1 |
; 6e. Disk is fully configured; store its handle in the global variable |
; and return success. |
pop [disk_handles+ebx*4] |
xor eax, eax |
; 7. Return. |
.return: |
retn |
endp |
; The worker procedure for DEV_DEL_DISK request. |
; Deletes a previously created memory-based disk. |
; Called with ebx = disk id, |
; returns error code in al. |
proc del_disk |
; 1. Check that disk id is correct. |
; Otherwise, return the corresponding error code. |
mov al, ERROR_INVALID_ID |
cmp ebx, max_num_disks |
jae .return |
; 2. Get the disk handle, simultaneously clearing the global variable. |
xor edx, edx |
xchg edx, [disk_handles+ebx*4] |
; 3. Check that the handle is non-zero. |
; Otherwise, return the corresponding error code. |
test edx, edx |
jz .return |
; 4. Delete the disk from the system. |
stdcall DiskDel, edx |
; 5. Return success. |
; Note that we can't free memory yet; it will be done in tmpdisk_close. |
xor eax, eax |
.return: |
retn |
endp |
; Include implementation of tmpdisk_* callbacks. |
include 'tmpdisk_work.inc' |
; Include FAT-specific code. |
include 'tmpdisk_fat.inc' |
; initialized data |
align 4 |
disk_functions: |
dd disk_functions_end - disk_functions |
dd tmpdisk_close |
dd 0 ; no need in .closemedia |
dd tmpdisk_querymedia |
dd tmpdisk_read |
dd tmpdisk_write |
dd 0 ; no need in .flush |
dd tmpdisk_adjust_cache_size |
disk_functions_end: |
; disk_handles = array of values for Disk* kernel functions |
label disk_handles dword |
times max_num_disks dd 0 |
; disk_pointers = array of pointers to disk data |
label disk_pointers dword |
times max_num_disks dd 0 |
; disk_sizes = array of disk sizes |
label disk_sizes dword |
times max_num_disks dd 0 |
version dd 0x00060006 |
my_service db 'tmpdisk',0 |
; uninitialized data |
; actually, not used here |
;section '.data' data readable writable align 16 ; standard driver stuff |
/kernel/branches/Kolibri-acpi/drivers/tmpdisk_work.inc |
---|
0,0 → 1,144 |
; Callbacks which implement tmpdisk-specific disk functions for tmpdisk.asm. |
; The first argument of every callback is .userdata = userdata arg of AddDisk. |
; For tmpdisk, .userdata is the disk id, one of 0,...,max_num_disks-1. |
DISK_STATUS_OK = 0 ; success |
DISK_STATUS_GENERAL_ERROR = -1; if no other code is suitable |
DISK_STATUS_INVALID_CALL = 1 ; invalid input parameters |
DISK_STATUS_NO_MEDIA = 2 ; no media present |
DISK_STATUS_END_OF_MEDIA = 3 ; end of media while reading/writing data |
; The last function that is called for the given disk. The kernel calls it when |
; the kernel has finished all operations with the disk and it is safe to free |
; all driver-specific data identified by 'userdata'. |
proc tmpdisk_close |
virtual at esp+4 |
.userdata dd ? |
end virtual |
; Free the memory for disk and zero global variables. |
mov edx, [.userdata] |
mov [disk_sizes+edx*4], 0 |
xor eax, eax |
xchg eax, [disk_pointers+edx*4] |
stdcall KernelFree, eax |
retn 4 |
endp |
struc DISKMEDIAINFO |
{ |
.flags dd ? |
DISK_MEDIA_READONLY = 1 |
.sectorsize dd ? |
.capacity dq ? |
} |
virtual at 0 |
DISKMEDIAINFO DISKMEDIAINFO |
end virtual |
; Returns information about disk media. |
proc tmpdisk_querymedia |
virtual at esp+4 |
.userdata dd ? |
.info dd ? |
end virtual |
; Media is always present, sector size is always 512 bytes, |
; the size of disk in sectors is stored in a global variable. |
mov edx, [.userdata] |
mov ecx, [.info] |
mov [ecx+DISKMEDIAINFO.flags], 0 |
mov [ecx+DISKMEDIAINFO.sectorsize], 512 |
mov eax, [disk_sizes+edx*4] |
mov dword [ecx+DISKMEDIAINFO.capacity], eax |
mov dword [ecx+DISKMEDIAINFO.capacity+4], 0 |
; Return zero as an indicator of success. |
xor eax, eax |
retn 8 |
endp |
; Reads one or more sectors from the device. |
tmpdisk_read: |
xor edx, edx ; 0 = reading |
jmp tmpdisk_readwrite |
; Writes one or more sectors to the device. |
tmpdisk_write: |
mov dl, 1 ; 1 = writing |
; Fall through to tmpdisk_readwrite. |
; Common procedure for reading and writing. |
; dl = 0 for reading, dl = 1 for writing. |
; Arguments of tmpdisk_read and tmpdisk_write are the same, |
; they continue to be stack arguments of this procedure. |
proc tmpdisk_readwrite \ |
userdata:dword, \ |
buffer:dword, \ |
start_sector:qword, \ |
numsectors_ptr:dword |
; 1. Save used registers to be stdcall. |
push esi edi |
mov esi, [userdata] |
mov edi, [numsectors_ptr] |
; 1. Determine number of sectors to be transferred. |
; This is either the requested number of sectors or number of sectors |
; up to the disk boundary, depending of what is less. |
xor ecx, ecx |
; 1a. Test whether [start_sector] is less than [disk_sizes] for selected disk. |
; If so, calculate number of sectors between [start_sector] and [disk_sizes]. |
; Otherwise, the actual number of sectors is zero. |
cmp dword [start_sector+4], ecx |
jnz .got_number |
mov eax, [disk_sizes+esi*4] |
sub eax, dword [start_sector] |
jbe .got_number |
; 1b. Get the requested number of sectors. |
mov ecx, [edi] |
; 1c. If it is greater than number of sectors calculated in 1a, use the value |
; from 1a. |
cmp ecx, eax |
jb .got_number |
mov ecx, eax |
.got_number: |
; 2. Compare the actual number of sectors with requested. If they are |
; equal, set eax (it will be the returned value) to zero. Otherwise, |
; use DISK_STATUS_END_OF_MEDIA. |
xor eax, eax |
cmp ecx, [edi] |
jz @f |
mov al, DISK_STATUS_END_OF_MEDIA |
@@: |
; 3. Store the actual number of sectors. |
mov [edi], ecx |
; 4. Calculate source and destination addresses. |
mov edi, dword [start_sector] |
shl edi, 9 |
add edi, [disk_pointers+esi*4] |
mov esi, [buffer] |
; 5. Calculate number of dwords to be transferred. |
shl ecx, 9-2 |
; 6. Now esi = [buffer], edi = pointer inside disk. |
; This is normal for write operations; |
; exchange esi and edi for read operations. |
test dl, dl |
jnz @f |
xchg esi, edi |
@@: |
; 7. Copy data. |
rep movsd |
; 8. Restore used registers to be stdcall and return. |
; The value in eax was calculated in step 2. |
pop edi esi |
ret |
endp |
; The kernel calls this function when initializing cache subsystem for |
; the media. This call allows the driver to adjust the cache size. |
proc tmpdisk_adjust_cache_size |
virtual at esp+4 |
.userdata dd ? |
.suggested_size dd ? |
end virtual |
; Since tmpdisk does not need cache, just return 0. |
xor eax, eax |
retn 8 |
endp |
/kernel/branches/Kolibri-acpi/drivers/codec.inc |
---|
0,0 → 1,326 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
AD_LOSEL equ BIT5 |
AD_HPSEL equ BIT10 |
align 4 |
proc detect_codec |
locals |
codec_id dd ? |
endl |
stdcall codec_read, dword 0x7C |
shl eax, 16 |
mov [codec_id], eax |
stdcall codec_read, dword 0x7E |
or eax, [codec_id] |
mov [codec.chip_id], eax |
and eax, 0xFFFFFF00 |
mov edi, codecs |
@@: |
mov ebx, [edi] |
test ebx, ebx |
jz .unknown |
cmp eax, ebx |
jne .next |
mov eax, [edi+4] |
mov [codec.ac_vendor_ids], eax |
mov esi, eax |
call SysMsgBoardStr |
stdcall detect_chip, [edi+8] |
ret |
.next: |
add edi, 12 |
jmp @B |
.unknown: |
mov [codec.ac_vendor_ids], ac_unknown |
mov [codec.chip_ids], chip_unknown |
mov esi, chip_unknown |
call SysMsgBoardStr |
mov eax, [codec.chip_id] |
call dword2str |
call SysMsgBoardStr |
ret |
endp |
align 4 |
proc detect_chip stdcall, chip_tab:dword |
mov eax, [codec.chip_id] |
and eax, 0xFF |
mov edi, [chip_tab] |
@@: |
mov ebx, [edi] |
cmp ebx, 0xFF |
je .unknown |
cmp eax, ebx |
jne .next |
mov eax, [edi+4] |
mov [codec.chip_ids], eax |
mov esi, eax |
call SysMsgBoardStr |
ret |
.next: |
add edi, 8 |
jmp @b |
.unknown: |
mov [codec.chip_ids], chip_unknown |
mov esi, chip_unknown |
call SysMsgBoardStr |
mov eax, [codec.chip_id] |
call dword2str |
call SysMsgBoardStr |
ret |
endp |
align 4 |
proc setup_codec |
xor eax, eax |
stdcall codec_write, dword CODEC_AUX_VOL |
mov eax, 0x0B0B |
stdcall codec_write, dword CODEC_MASTER_VOL_REG |
mov ax, 0x08 |
stdcall codec_write, dword 0x0C |
mov ax, 0x0808 |
stdcall codec_write, dword CODEC_PCM_OUT_REG |
mov ax, 0x0808 |
stdcall codec_write, dword 0x10 |
mov ax, 0x0808 |
stdcall codec_write, dword 0x12 |
mov ax, 0x0808 |
stdcall codec_write, dword 0x16 |
stdcall codec_read, dword CODEC_EXT_AUDIO_CTRL_REG |
and eax, 0FFFFh - BIT1 ; clear DRA (BIT1) |
or eax, BIT0 ; set VRA (BIT0) |
stdcall codec_write, dword CODEC_EXT_AUDIO_CTRL_REG |
stdcall set_sample_rate, dword 48000 |
.init_error: |
xor eax, eax ; exit with error |
ret |
endp |
; param |
; eax= volume -10000 - 0 for both channels |
align 4 |
set_master_vol: |
cmp eax, 0 |
jl @F |
xor eax, eax |
jmp .set |
@@: |
cmp eax, -9450 |
jg .set |
mov eax, -9450 ;clamp into 6 bits |
.set: |
cdq |
mov ebx, -150 |
idiv ebx |
mov ah, al |
stdcall codec_write, dword CODEC_MASTER_VOL_REG |
xor eax, eax |
ret |
align 4 |
proc get_master_vol stdcall, pvol:dword |
stdcall codec_read, dword CODEC_MASTER_VOL_REG |
and eax, 0x3F |
imul eax, -150 |
mov ebx, [pvol] |
mov [ebx], eax |
xor eax, eax |
ret |
endp |
align 4 |
proc set_sample_rate stdcall, rate:dword |
mov eax, [rate] |
stdcall codec_write, dword CODEC_PCM_FRONT_DACRATE_REG |
ret |
endp |
patch_AD: |
stdcall codec_read, 0x76 |
or ax, BIT5+BIT10 |
stdcall codec_write, 0x76 |
ret |
align 16 |
ac_unknown db 'unknown manufacturer',13,10,0 |
ac_Realtek db 'Realtek Semiconductor',13,10,0 |
ac_Analog db 'Analog Devices',13,10,0 |
ac_CMedia db 'C-Media Electronics',13,10,0 |
ac_Cirrus db 'Cirrus Logic',13,10,0 |
ac_Wolfson db 'Wolfson Microelectronics',13,10,0 |
ac_VIA db 'VIA Technologies',13,10,0 |
ac_SigmaTel db 'SigmaTel',13,10,0 |
ac_eMicro db 'eMicro',13,10,0 |
chip_unknown db 'unknown codec id ', 0 |
CHIP_ANALOG equ 0x41445300 |
CHIP_REALTEK equ 0x414C4700 |
CHIP_CMEDIA equ 0x434D4900 |
CHIP_CIRRUS equ 0x43525900 |
CHIP_WOLFSON equ 0x574D4C00 |
CHIP_VIA equ 0x56494100 |
CHIP_SIGMATEL equ 0x83847600 |
CHIP_EMICRO equ 0x454D4300 |
align 16 |
codecs dd CHIP_ANALOG, ac_Analog, chips_Analog |
dd CHIP_CMEDIA, ac_CMedia, chips_CMedia |
dd CHIP_REALTEK,ac_Realtek, chips_Realtek |
dd CHIP_CIRRUS, ac_Cirrus, chips_Cirrus |
dd CHIP_WOLFSON,ac_Wolfson, chips_Wolfson |
dd CHIP_VIA, ac_VIA, chips_VIA |
dd CHIP_SIGMATEL, ac_SigmaTel, chips_SigmaTel |
dd CHIP_EMICRO, ac_eMicro, chips_eMicro |
dd 0 |
align 16 |
chips_Analog dd 0x03, chip_AD1819 |
dd 0x40, chip_AD1881 |
dd 0x48, chip_AD1881A |
dd 0x60, chip_AD1884 |
dd 0x61, chip_AD1886 |
dd 0x62, chip_AD1887 |
dd 0x63, chip_AD1886A |
dd 0x70, chip_AD1980 |
dd 0x72, chip_AD1981A |
dd 0x74, chip_AD1981B |
dd 0x75, chip_AD1985 |
dd 0xFF |
chips_Realtek: |
dd 0x10, chip_ALC201a |
dd 0x20, chip_ALC650 |
dd 0x21, chip_ALC650D |
dd 0x22, chip_ALC650E |
dd 0x23, chip_ALC650F |
dd 0x60, chip_ALC655 |
dd 0x80, chip_ALC658 |
dd 0x81, chip_ALC658D |
dd 0x90, chip_ALC850 |
dd 0xFF |
chips_CMedia dd 0x41, chip_CM9738 |
dd 0x61, chip_CM9739 |
dd 0x69, chip_CM9780 |
dd 0x78, chip_CM9761 |
dd 0x82, chip_CM9761 |
dd 0x83, chip_CM9761 |
dd 0xFF |
chips_Cirrus dd 0x00, chip_CS4297 |
dd 0x10, chip_CS4297A |
dd 0x20, chip_CS4298 |
dd 0x28, chip_CS4294 |
dd 0x30, chip_CS4299 |
dd 0x34, chip_CS4299D |
dd 0x48, chip_CS4201 |
dd 0x58, chip_CS4205 |
dd 0x60, chip_CS4291 |
dd 0x70, chip_CS4202 |
dd 0xFF |
chips_Wolfson dd 0x00, chip_WM9700 |
dd 0x03, chip_WM9703 |
dd 0x04, chip_WM9704 |
dd 0xFF |
chips_VIA dd 0x61, chip_VIA1612A |
dd 0xFF |
chips_SigmaTel dd 0x58, chip_STAC9758 |
dd 0xFF |
chips_eMicro dd 0x28, chip_EM28028 |
dd 0xFF |
align 16 |
;Analog Devices |
chip_AD1819 db 'AD1819 ',0dh,0ah,00h |
chip_AD1881 db 'AD1881 ',0dh,0ah,00h |
chip_AD1881A db 'AD1881A',0dh,0ah,00h |
chip_AD1884 db 'AD1885 ',0dh,0ah,00h |
chip_AD1885 db 'AD1885 ',0dh,0ah,00h |
chip_AD1886 db 'AD1886 ',0dh,0ah,00h |
chip_AD1886A db 'AD1886A',0dh,0ah,00h |
chip_AD1887 db 'AD1887 ',0dh,0ah,00h |
chip_AD1980 db 'AD1980 ',0dh,0ah,00h |
chip_AD1981A db 'AD1981A',0dh,0ah,00h |
chip_AD1981B db 'AD1981B',0dh,0ah,00h |
chip_AD1985 db 'AD1985 ',0dh,0ah,00h |
;Realtek |
chip_ALC201a db 'ALC201a',0dh,0ah,00h |
chip_ALC650 db 'ALC650 ',0dh,0ah,00h |
chip_ALC650D db 'ALC650D',0dh,0ah,00h |
chip_ALC650E db 'ALC650E',0dh,0ah,00h |
chip_ALC650F db 'ALC650F',0dh,0ah,00h |
chip_ALC655 db 'ALC655 ',0dh,0ah,00h |
chip_ALC658 db 'ALC658 ',0dh,0ah,00h |
chip_ALC658D db 'ALC658D',0dh,0ah,00h |
chip_ALC850 db 'ALC850 ',0dh,0ah,00h |
;CMedia |
chip_CM9738 db 'CMI9738', 0dh,0ah,0 |
chip_CM9739 db 'CMI9739', 0dh,0ah,0 |
chip_CM9780 db 'CMI9780', 0dh,0ah,0 |
chip_CM9761 db 'CMI9761', 0dh,0ah,0 |
;Cirrus |
chip_CS4297 db 'CS4297',13,10,0 |
chip_CS4297A db 'CS4297A',13,10,0 |
chip_CS4298 db 'CS4298',13,10,0 |
chip_CS4294 db 'CS4294',13,10,0 |
chip_CS4299 db 'CS4299',13,10,0 |
chip_CS4299D db 'CS4299D',13,10,0 |
chip_CS4201 db 'CS4201',13,10,0 |
chip_CS4205 db 'CS4205',13,10,0 |
chip_CS4291 db 'CS4291',13,10,0 |
chip_CS4202 db 'CS4202',13,10,0 |
;Wolfson |
chip_WM9700 db 'WM9704',13,10,0 |
chip_WM9703 db 'WM9703/9704',13,10,0 |
chip_WM9704 db 'WM9704 (quad)',13,10,0 |
;VIA |
chip_VIA1612A db 'VIA1612A',13,10,0 |
;SigmaTel |
chip_STAC9758 db 'STAC9758,59',13,10,0 |
;eMicro |
chip_EM28028 db 'EM28028',13,10,0 |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
/kernel/branches/Kolibri-acpi/drivers/main.inc |
---|
0,0 → 1,173 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2006-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
; Serge 2006-2008 |
; email: infinity_sound@mail.ru |
PLAY_SYNC equ 0x80000000 |
PCM_ALL equ 0 |
PCM_OUT equ 0x08000000 |
PCM_RING equ 0x10000000 |
PCM_STATIC equ 0x20000000 |
PCM_FLOAT equ 0x40000000 ;reserved |
PCM_FILTER equ 0x80000000 ;reserved |
PCM_2_16_48 equ 1 |
PCM_1_16_48 equ 2 |
PCM_2_16_44 equ 3 |
PCM_1_16_44 equ 4 |
PCM_2_16_32 equ 5 |
PCM_1_16_32 equ 6 |
PCM_2_16_24 equ 7 |
PCM_1_16_24 equ 8 |
PCM_2_16_22 equ 9 |
PCM_1_16_22 equ 10 |
PCM_2_16_16 equ 11 |
PCM_1_16_16 equ 12 |
PCM_2_16_12 equ 13 |
PCM_1_16_12 equ 14 |
PCM_2_16_11 equ 15 |
PCM_1_16_11 equ 16 |
PCM_2_16_8 equ 17 |
PCM_1_16_8 equ 18 |
PCM_2_8_48 equ 19 |
PCM_1_8_48 equ 20 |
PCM_2_8_44 equ 21 |
PCM_1_8_44 equ 22 |
PCM_2_8_32 equ 23 |
PCM_1_8_32 equ 24 |
PCM_2_8_24 equ 25 |
PCM_1_8_24 equ 26 |
PCM_2_8_22 equ 27 |
PCM_1_8_22 equ 28 |
PCM_2_8_16 equ 29 |
PCM_1_8_16 equ 30 |
PCM_2_8_12 equ 31 |
PCM_1_8_12 equ 32 |
PCM_2_8_11 equ 33 |
PCM_1_8_11 equ 34 |
PCM_2_8_8 equ 35 |
PCM_1_8_8 equ 36 |
SRV_GETVERSION equ 0 |
SND_CREATE_BUFF equ 1 |
SND_DESTROY_BUFF equ 2 |
SND_SETFORMAT equ 3 |
SND_GETFORMAT equ 4 |
SND_RESET equ 5 |
SND_SETPOS equ 6 |
SND_GETPOS equ 7 |
SND_SETBUFF equ 8 |
SND_OUT equ 9 |
SND_PLAY equ 10 |
SND_STOP equ 11 |
SND_SETVOLUME equ 12 |
SND_GETVOLUME equ 13 |
SND_SETPAN equ 14 |
SND_GETPAN equ 15 |
SND_GETBUFFSIZE equ 16 |
SND_GETFREESPACE equ 17 |
SND_SETTIMEBASE equ 18 |
SND_GETTIMESTAMP equ 19 |
struc STREAM |
{ |
.magic dd ? ;'WAVE' |
.destroy dd ? ;internal destructor |
.fd dd ? ;next object in list |
.bk dd ? ;prev object in list |
.pid dd ? ;owner id |
.size dd ? |
.str_fd dd ? |
.str_bk dd ? |
.device dd ? |
.format dd ? |
.flags dd ? |
.out_base dd ? |
.out_wp dd ? |
.out_rp dd ? |
.out_count dd ? |
.out_top dd ? ;16*4 |
.in_base dd ? |
.in_size dd ? |
.in_wp dd ? |
.in_rp dd ? |
.in_count dd ? |
.in_free dd ? |
.in_top dd ? |
align 8 |
.time_base dq ? |
.time_stamp dq ? |
.last_ts dd ? |
.notify_event dd ? |
.notify_id dd ? |
.r_size dd ? |
.r_dt dd ? |
.r_silence dd ? |
.resample dd ? |
.l_vol dd ? |
.r_vol dd ? |
.l_amp dw ? |
.r_amp dw ? |
.pan dd ? |
.l_amp_f dd ? ;float point left |
.r_amp_f dd ? ;float point right |
.sizeof: |
} |
FD_OFFSET equ 24 |
virtual at 0 |
STREAM STREAM |
end virtual |
struc WAVE_HEADER |
{ .riff_id dd ? |
.riff_size dd ? |
.riff_format dd ? |
.fmt_id dd ? |
.fmt_size dd ? |
.format_tag dw ? |
.channels dw ? |
.freq dd ? |
.bytes_sec dd ? |
.block_align dw ? |
.bits_sample dw ? |
.data_id dd ? |
.data_size dd ? |
} |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
/kernel/branches/Kolibri-acpi/drivers/mix_mmx.inc |
---|
0,0 → 1,247 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
; params |
; edi= output |
; eax= input stream 1 |
; ebx= input stream 2 |
if used mmx_mix_2 |
align 4 |
mmx_mix_2: |
movq mm0, [eax] |
movq mm1, [eax+8] |
movq mm2, [eax+16] |
movq mm3, [eax+24] |
movq mm4, [eax+32] |
movq mm5, [eax+40] |
movq mm6, [eax+48] |
movq mm7, [eax+56] |
paddsw mm0, [ebx] |
movq [edi], mm0 |
paddsw mm1, [ebx+8] |
movq [edi+8], mm1 |
paddsw mm2, [ebx+16] |
movq [edi+16], mm2 |
paddsw mm3, [ebx+24] |
movq [edi+24], mm3 |
paddsw mm4, [ebx+32] |
movq [edi+32], mm4 |
paddsw mm5, [ebx+40] |
movq [edi+40], mm5 |
paddsw mm6, [ebx+48] |
movq [edi+48], mm6 |
paddsw mm7, [ebx+56] |
movq [edi+56], mm7 |
movq mm0, [eax+64] |
movq mm1, [eax+72] |
movq mm2, [eax+80] |
movq mm3, [eax+88] |
movq mm4, [eax+96] |
movq mm5, [eax+104] |
movq mm6, [eax+112] |
movq mm7, [eax+120] |
paddsw mm0, [ebx+64] |
movq [edi+64], mm0 |
paddsw mm1, [ebx+72] |
movq [edi+72], mm1 |
paddsw mm2, [ebx+80] |
movq [edi+80], mm2 |
paddsw mm3, [ebx+88] |
movq [edi+88], mm3 |
paddsw mm4, [ebx+96] |
movq [edi+96], mm4 |
paddsw mm5, [ecx+104] |
movq [edx+104], mm5 |
paddsw mm6, [ebx+112] |
movq [edi+112], mm6 |
paddsw mm7, [ebx+120] |
movq [edi+120], mm7 |
ret |
align 4 |
mmx_mix_3: |
movq mm0, [eax] |
movq mm1, [eax+8] |
movq mm2, [eax+16] |
movq mm3, [eax+24] |
movq mm4, [eax+32] |
movq mm5, [eax+40] |
movq mm6, [eax+48] |
movq mm7, [eax+56] |
paddsw mm0, [ebx] |
paddsw mm1, [ebx+8] |
paddsw mm2, [ebx+16] |
paddsw mm3, [ebx+24] |
paddsw mm4, [ebx+32] |
paddsw mm5, [ebx+40] |
paddsw mm6, [ebx+48] |
paddsw mm7, [ebx+56] |
paddsw mm0, [ecx] |
movq [edi], mm0 |
paddsw mm1, [ecx+8] |
movq [edi+8], mm1 |
paddsw mm2, [ecx+16] |
movq [edi+16], mm2 |
paddsw mm3, [ecx+24] |
movq [edi+24], mm3 |
paddsw mm4, [ecx+32] |
movq [edi+32], mm4 |
paddsw mm5, [ecx+40] |
movq [edi+40], mm5 |
paddsw mm6, [ecx+48] |
movq [edi+48], mm6 |
paddsw mm7, [ecx+56] |
movq [edi+56], mm7 |
movq mm0, [eax+64] |
movq mm1, [eax+72] |
movq mm2, [eax+80] |
movq mm3, [eax+88] |
movq mm4, [eax+96] |
movq mm5, [eax+104] |
movq mm6, [eax+112] |
movq mm7, [eax+120] |
paddsw mm0, [ebx+64] |
paddsw mm1, [ebx+72] |
paddsw mm2, [ebx+80] |
paddsw mm3, [ebx+88] |
paddsw mm4, [ebx+96] |
paddsw mm5, [ebx+104] |
paddsw mm6, [ebx+112] |
paddsw mm7, [ebx+120] |
paddsw mm0, [ecx+64] |
movq [edi+64], mm0 |
paddsw mm1, [ecx+72] |
movq [edi+72], mm1 |
paddsw mm2, [ecx+80] |
movq [edi+80], mm2 |
paddsw mm3, [ecx+88] |
movq [edi+88], mm3 |
paddsw mm4, [ecx+96] |
movq [edi+96], mm4 |
paddsw mm5, [ecx+104] |
movq [edi+104], mm5 |
paddsw mm6, [ecx+112] |
movq [edi+112], mm6 |
paddsw mm7, [ecx+120] |
movq [edi+120], mm7 |
ret |
align 4 |
mmx_mix_4: |
movq mm0, [eax] |
movq mm2, [eax+8] |
movq mm4, [eax+16] |
movq mm6, [eax+24] |
movq mm1, [ebx] |
movq mm3, [ebx+8] |
movq mm5, [ebx+16] |
movq mm7, [ebx+24] |
paddsw mm0, [ecx] |
paddsw mm2, [ecx+8] |
paddsw mm4, [ecx+16] |
paddsw mm6, [ecx+24] |
paddsw mm1, [edx] |
paddsw mm3, [edx+8] |
paddsw mm5, [edx+16] |
paddsw mm7, [edx+24] |
paddsw mm0, mm1 |
movq [edi], mm0 |
paddsw mm2, mm3 |
movq [edi+8], mm2 |
paddsw mm4, mm5 |
movq [edi+16], mm4 |
paddsw mm5, mm6 |
movq [edi+24], mm6 |
movq mm0, [eax+32] |
movq mm2, [eax+40] |
movq mm4, [eax+48] |
movq mm6, [eax+56] |
movq mm1, [ebx+32] |
movq mm3, [ebx+40] |
movq mm5, [ebx+48] |
movq mm7, [ebx+56] |
paddsw mm0, [ecx+32] |
paddsw mm2, [ecx+40] |
paddsw mm4, [ecx+48] |
paddsw mm6, [ecx+56] |
paddsw mm1, [edx+32] |
paddsw mm3, [edx+40] |
paddsw mm5, [edx+48] |
paddsw mm7, [edx+56] |
paddsw mm0, mm1 |
movq [edi+32], mm0 |
paddsw mm2, mm2 |
movq [edi+40], mm2 |
paddsw mm4, mm5 |
movq [edi+48], mm4 |
paddsw mm6, mm7 |
movq [edi+56], mm6 |
movq mm0, [eax+64] |
movq mm2, [eax+72] |
movq mm4, [eax+80] |
movq mm6, [eax+88] |
movq mm1, [ebx+64] |
movq mm3, [ebx+72] |
movq mm5, [ebx+80] |
movq mm7, [ebx+88] |
paddsw mm0, [ecx+64] |
paddsw mm2, [ecx+72] |
paddsw mm4, [ecx+80] |
paddsw mm6, [ecx+88] |
paddsw mm1, [edx+64] |
paddsw mm3, [edx+72] |
paddsw mm5, [edx+80] |
paddsw mm7, [edx+88] |
paddsw mm0, mm1 |
movq [edi+64], mm0 |
paddsw mm2, mm3 |
movq [edi+72], mm2 |
paddsw mm4, mm5 |
movq [edi+80], mm4 |
paddsw mm6, mm5 |
movq [edi+88], mm7 |
movq mm0, [eax+96] |
movq mm2, [eax+104] |
movq mm4, [eax+112] |
movq mm6, [eax+120] |
movq mm1, [ebx+96] |
movq mm3, [ebx+104] |
movq mm5, [ebx+112] |
movq mm7, [ebx+120] |
paddsw mm0, [ecx+96] |
paddsw mm2, [ecx+104] |
paddsw mm4, [ecx+112] |
paddsw mm6, [ecx+120] |
paddsw mm1, [edx+96] |
paddsw mm3, [edx+104] |
paddsw mm5, [edx+112] |
paddsw mm7, [edx+120] |
paddsw mm0, mm1 |
movq [eax+96], mm0 |
paddsw mm2, mm3 |
movq [edi+104], mm2 |
paddsw mm4, mm5 |
movq [edi+112], mm4 |
paddsw mm6, mm7 |
movq [edi+120], mm6 |
ret |
end if |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
/kernel/branches/Kolibri-acpi/drivers/mix_sse2.inc |
---|
0,0 → 1,145 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
if used mmx128_mix_2 |
align 4 |
mmx128_mix_2: |
prefetcht1 [eax+128] |
prefetcht1 [ebx+128] |
movaps xmm0, [eax] |
movaps xmm1, [eax+16] |
movaps xmm2, [eax+32] |
movaps xmm3, [eax+48] |
movaps xmm4, [eax+64] |
movaps xmm5, [eax+80] |
movaps xmm6, [eax+96] |
movaps xmm7, [eax+112] |
paddsw xmm0, [ebx] |
movaps [edi], xmm0 |
paddsw xmm1, [ebx+16] |
movaps [edi+16], xmm1 |
paddsw xmm2, [ebx+32] |
movaps [edi+32], xmm2 |
paddsw xmm3, [ebx+48] |
movaps [edi+48], xmm3 |
paddsw xmm4, [ebx+64] |
movaps [edi+64], xmm4 |
paddsw xmm5, [ebx+80] |
movaps [edi+80], xmm5 |
paddsw xmm6, [ebx+96] |
movaps [edi+96], xmm6 |
paddsw xmm7, [ebx+112] |
movaps [edi+112], xmm7 |
ret |
align 4 |
mmx128_mix_3: |
prefetcht1 [eax+128] |
prefetcht1 [ebx+128] |
prefetcht1 [ecx+128] |
movaps xmm0, [eax] |
movaps xmm1, [eax+16] |
movaps xmm2, [eax+32] |
movaps xmm3, [eax+48] |
movaps xmm4, [eax+64] |
movaps xmm5, [eax+80] |
movaps xmm6, [eax+96] |
movaps xmm7, [eax+112] |
paddsw xmm0, [ebx] |
paddsw xmm1, [ebx+16] |
paddsw xmm2, [ebx+32] |
paddsw xmm3, [ebx+48] |
paddsw xmm4, [ebx+64] |
paddsw xmm5, [ebx+80] |
paddsw xmm6, [ebx+96] |
paddsw xmm7, [ebx+112] |
paddsw xmm0, [ecx] |
movaps [edi], xmm0 |
paddsw xmm1, [ecx+16] |
movaps [edi+16], xmm1 |
paddsw xmm2, [ecx+32] |
movaps [edi+32], xmm2 |
paddsw xmm3, [ecx+48] |
movaps [edi+48], xmm3 |
paddsw xmm4, [ecx+64] |
movaps [edi+64], xmm4 |
paddsw xmm5, [ecx+80] |
movaps [edi+80], xmm5 |
paddsw xmm6, [ecx+96] |
movaps [edi+96], xmm6 |
paddsw xmm7, [ecx+112] |
movaps [edi+112], xmm7 |
ret |
align 4 |
mmx128_mix_4: |
prefetcht1 [eax+128] |
prefetcht1 [ebx+128] |
prefetcht1 [ecx+128] |
prefetcht1 [edx+128] |
movaps xmm0, [eax] |
movaps xmm2, [eax+16] |
movaps xmm4, [eax+32] |
movaps xmm6, [eax+48] |
movaps xmm1, [ebx] |
movaps xmm3, [ebx+16] |
movaps xmm5, [ebx+32] |
movaps xmm7, [ebx+48] |
paddsw xmm0, [ecx] |
paddsw xmm2, [ecx+16] |
paddsw xmm4, [ecx+32] |
paddsw xmm6, [ecx+48] |
paddsw xmm1, [edx] |
paddsw xmm3, [edx+16] |
paddsw xmm5, [edx+32] |
paddsw xmm7, [edx+48] |
paddsw xmm0, xmm1 |
movaps [edi], xmm0 |
paddsw xmm2, xmm3 |
movaps [edi+16], xmm2 |
paddsw xmm4, xmm5 |
movaps [edi+32], xmm4 |
paddsw xmm6, xmm7 |
movaps [edi+48], xmm6 |
movaps xmm0, [eax+64] |
movaps xmm2, [eax+80] |
movaps xmm4, [eax+96] |
movaps xmm6, [eax+112] |
movaps xmm1, [ebx+64] |
movaps xmm3, [ebx+80] |
movaps xmm5, [ebx+96] |
movaps xmm7, [ebx+112] |
paddsw xmm0, [ecx+64] |
paddsw xmm2, [ecx+80] |
paddsw xmm4, [ecx+96] |
paddsw xmm6, [ecx+112] |
paddsw xmm1, [edx+64] |
paddsw xmm3, [edx+80] |
paddsw xmm5, [edx+96] |
paddsw xmm7, [edx+112] |
paddsw xmm0, xmm1 |
movaps [edi+64], xmm0 |
paddsw xmm2, xmm3 |
movaps [edi+80], xmm2 |
paddsw xmm4, xmm5 |
movaps [edi+96], xmm4 |
paddsw xmm6, xmm7 |
movaps [edi+112], xmm6 |
ret |
end if |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
/kernel/branches/Kolibri-acpi/drivers/mixer.asm |
---|
0,0 → 1,1266 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2006-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
; (C) copyright Serge 2006 |
; email: infinity_sound@mail.ru |
align 4 |
mix_list rd 32*3 |
align 4 |
proc new_mix stdcall, output:dword |
locals |
main_count rd 1 |
fpu_state rb 528 ;512+16 |
endl |
mov [main_count], 32 |
call prepare_playlist |
cmp [play_count], 0 |
je .clear |
lea eax, [fpu_state+16] |
and eax, -16 ;must be 16b aligned |
call FpuSave |
call update_streams |
.mix: |
lea eax, [mix_list] |
call do_mix_list |
test eax, eax |
je .done |
if USE_SSE2_MIXER |
cmp eax, 1 |
ja @F |
;use fast path |
mov edi, [output] |
lea edx, [mix_list] |
call mix_fast |
jmp .next |
@@: |
cmp eax, 2 |
ja @F |
mov edi, [output] |
lea edx, [mix_list] |
call mix_fast_2_stream |
jmp .next |
@@: |
end if |
lea ebx, [mix_list] |
stdcall mix_all, [output], ebx, eax |
.next: |
add [output], 512 |
dec [main_count] |
jnz .mix |
.exit: |
lea eax, [fpu_state+16] |
and eax, -16 |
call FpuRestore |
ret |
.done: |
mov ecx, [main_count] |
shl ecx, 7 ;ecx*= 512/4 |
mov edi, [output] |
xor eax, eax |
cld |
rep stosd |
jmp .exit |
.clear: |
mov edi, [output] |
mov ecx, 4096 |
xor eax, eax |
cld |
rep stosd |
ret |
endp |
align 4 |
proc update_streams |
locals |
stream_index dd ? |
event rd 6 |
endl |
mov [stream_index], 0 |
.l1: |
mov edx, [stream_index] |
mov esi, [play_list+edx*4] |
add dword [esi+STREAM.time_stamp], 4096 |
adc dword [esi+STREAM.time_stamp+4], 0 |
mov dword [esi+STREAM.last_ts], 0 |
mov eax, [esi+STREAM.out_rp] |
cmp eax, [esi+STREAM.out_top] |
jb @f |
sub eax, 64*1024 |
@@: |
mov [esi+STREAM.out_rp], eax |
cmp [esi+STREAM.out_count], 16384 |
ja .skip |
test [esi+STREAM.format], PCM_RING |
jnz .ring |
stdcall refill, esi |
.skip: |
inc [stream_index] |
dec [play_count] |
jnz .l1 |
ret |
.ring: |
stdcall refill_ring, esi |
jmp .skip |
endp |
align 4 |
proc refill stdcall, str:dword |
locals |
r_size rd 1 |
endl |
mov ebx, [str] |
mov edi, [ebx+STREAM.out_wp] |
cmp edi, [ebx+STREAM.out_top] |
jb @F |
sub edi, 0x10000 |
mov [ebx+STREAM.out_wp], edi |
@@: |
mov eax, [ebx+STREAM.in_count] |
test eax, eax |
jz .done |
mov ecx, [ebx+STREAM.r_size] |
cmp eax, ecx |
jle @F |
mov eax, ecx |
@@: |
mov ecx, eax |
cmp word [ebx+STREAM.format], PCM_1_16_8 |
ja @F |
shr eax, 1 ;two channles |
@@: |
test [ebx+STREAM.format], 1 ;even formats mono |
jz @F |
shr eax, 1 ;eax= samples |
@@: |
shl eax, 15 ;eax*=32768 =r_end |
mov [r_size], ecx |
mov esi, [ebx+STREAM.in_rp] |
mov edi, [ebx+STREAM.out_wp] |
stdcall [ebx+STREAM.resample], edi, esi, \ |
[ebx+STREAM.r_dt], ecx, eax |
mov ebx, [str] |
add [ebx+STREAM.out_count], eax; |
add [ebx+STREAM.out_wp], eax; |
mov eax, [ebx+STREAM.in_rp] |
mov ecx, [r_size] |
add eax, ecx |
add [ebx+STREAM.in_free], ecx |
sub [ebx+STREAM.in_count], ecx |
cmp eax, [ebx+STREAM.in_top] |
jb @f |
sub eax, [ebx+STREAM.in_size] |
@@: |
mov [ebx+STREAM.in_rp], eax |
.done: |
mov eax, [ebx+STREAM.notify_event] |
test eax, eax |
jz .exit |
mov ebx, [ebx+STREAM.notify_id] |
mov edx, EVENT_WATCHED |
xor esi, esi |
call RaiseEvent ;eax, ebx, edx, esi |
.exit: |
ret |
endp |
align 4 |
proc refill_ring stdcall, str:dword |
locals |
event rd 6 |
endl |
mov ebx, [str] |
mov edi, [ebx+STREAM.out_wp] |
cmp edi, [ebx+STREAM.out_top] |
jb @F |
sub edi, 0x10000 |
mov [ebx+STREAM.out_wp], edi |
@@: |
mov ecx, [ebx+STREAM.r_size] |
mov eax, ecx |
cmp word [ebx+STREAM.format], PCM_1_16_8 |
ja @F |
shr eax, 1 ;two channles |
@@: |
test [ebx+STREAM.format], 1 ;even formats mono |
jz @F |
shr eax, 1 ;eax= samples |
@@: |
shl eax, 15 ;eax*=32768 =r_end |
mov esi, [ebx+STREAM.in_rp] |
mov edi, [ebx+STREAM.out_wp] |
stdcall [ebx+STREAM.resample], edi, esi, \ |
[ebx+STREAM.r_dt], ecx, eax |
mov ebx, [str] |
add [ebx+STREAM.out_count], eax; |
add [ebx+STREAM.out_wp], eax; |
mov eax, [ebx+STREAM.in_rp] |
mov ecx, [ebx+STREAM.r_size] |
add eax, ecx |
add [ebx+STREAM.in_free], ecx |
sub [ebx+STREAM.in_count], ecx |
cmp eax, [ebx+STREAM.in_top] |
jb @f |
sub eax, [ebx+STREAM.in_size] |
@@: |
mov [ebx+STREAM.in_rp], eax |
sub eax, [ebx+STREAM.in_base] |
sub eax, 128 |
lea esi, [event] |
mov dword [esi], RT_INP_EMPTY |
mov dword [esi+4], 0 |
mov dword [esi+8], ebx |
mov dword [esi+12], eax |
mov eax, [ebx+STREAM.notify_event] |
test eax, eax |
jz .exit |
mov ebx, [ebx+STREAM.notify_id] |
xor edx, edx |
call RaiseEvent ;eax, ebx, edx, esi |
.exit: |
ret |
endp |
if USE_SSE2_MIXER |
align 4 |
proc mix_all stdcall, dest:dword, list:dword, count:dword |
mov edi, [dest] |
mov ebx, 32 |
.mix: |
mov edx, [list] |
mov ecx, [count] |
mov eax, [edx] |
movdqa xmm1, [eax] |
movss xmm2, [edx+4] |
movss xmm3, [edx+8] |
punpcklwd xmm0, xmm1 |
punpckhwd xmm1, xmm1 |
shufps xmm2, xmm3, 0 |
shufps xmm2, xmm2, 0x88 |
psrad xmm0, 16 |
psrad xmm1, 16 |
cvtdq2ps xmm0, xmm0 |
cvtdq2ps xmm1, xmm1 |
mulps xmm0, xmm2 |
mulps xmm1, xmm2 |
.mix_loop: |
add dword [edx], 16 |
add edx, 12 |
dec ecx |
jz @F |
mov eax, [edx] |
movdqa xmm3, [eax] |
movss xmm4, [edx+4] |
movss xmm5, [edx+8] |
punpcklwd xmm2, xmm3 |
punpckhwd xmm3, xmm3 |
shufps xmm4, xmm5, 0 |
shufps xmm4, xmm4, 0x88 |
psrad xmm2, 16 |
psrad xmm3, 16 |
cvtdq2ps xmm2, xmm2 |
cvtdq2ps xmm3, xmm3 |
mulps xmm2, xmm4 |
mulps xmm3, xmm4 |
addps xmm0, xmm2 |
addps xmm1, xmm3 |
jmp .mix_loop |
@@: |
cvtps2dq xmm0, xmm0 |
cvtps2dq xmm1, xmm1 |
packssdw xmm0, xmm0 |
packssdw xmm1, xmm1 |
punpcklqdq xmm0, xmm1 |
movntdq [edi], xmm0 |
add edi, 16 |
dec ebx |
jnz .mix |
ret |
endp |
; param |
; edi = dest |
; edx = mix_list |
align 4 |
mix_fast: |
mov ebx, 32 |
mov eax, [edx] |
movss xmm2, [edx+4] ; vol Lf |
movss xmm3, [edx+8] ; vol Rf |
shufps xmm2, xmm3, 0 ; Rf Rf Lf Lf |
shufps xmm2, xmm2, 0x88 ; volume level Rf Lf Rf Lf |
.mix: |
movdqa xmm1, [eax] ; R3w L3w R2w L2w R1w L1w R0w L0w |
add eax, 16 |
punpcklwd xmm0, xmm1 ; R1w R1w L1w L1W R0w R0w L0w L0w |
punpckhwd xmm1, xmm1 ; R3w R3w L3w L3w R2w R2w L2w L2w |
psrad xmm0, 16 ; R1d L1d R0d L0d |
psrad xmm1, 16 ; R3d L3d R2d L2d |
cvtdq2ps xmm0, xmm0 ; time to use all power |
cvtdq2ps xmm1, xmm1 ; of the dark side |
mulps xmm0, xmm2 ; R1f' L1f' R0f' L0f' |
mulps xmm1, xmm2 ; R3f' L3f' R2f' L2f' |
cvtps2dq xmm0, xmm0 ; R1d' L1d' R0d' L0d' |
cvtps2dq xmm1, xmm1 ; R3d' L3d' R2d' L2d' |
packssdw xmm0, xmm0 ; R1w' L1w' R0w' L0w' R1w' L1w' R0w' L0w' |
packssdw xmm1, xmm1 ; R3w' L3w' R2w' L2w' R3w' L3w' R2w' L2w' |
punpcklqdq xmm0, xmm1 ; R3w' L3w' R2w' L2w' R1w' L1w' R0w' L0w' |
movntdq [edi], xmm0 |
add edi, 16 |
dec ebx |
jnz .mix |
ret |
align 4 |
mix_fast_2_stream: |
mov ebx, 32 |
mov eax, [edx] |
movss xmm4, [edx+4] ; vol Lf |
movss xmm5, [edx+8] ; vol Rf |
mov ecx, [edx+12] |
movss xmm6, [edx+16] ; vol Lf |
movss xmm7, [edx+20] ; vol Rf |
shufps xmm4, xmm5, 0 ; Rf Rf Lf Lf |
shufps xmm4, xmm4, 0x88 ; volume level Rf Lf Rf Lf |
shufps xmm6, xmm7, 0 ; Rf Rf Lf Lf |
shufps xmm6, xmm6, 0x88 ; volume level Rf Lf Rf Lf |
.mix: |
movdqa xmm1, [eax] ; R3w L3w R2w L2w R1w L1w R0w L0w |
movdqa xmm3, [ecx] ; R3w L3w R2w L2w R1w L1w R0w L0w |
add eax, 16 |
add ecx, 16 |
punpcklwd xmm0, xmm1 ; R1w R1w L1w L1W R0w R0w L0w L0w |
punpckhwd xmm1, xmm1 ; R3w R3w L3w L3w R2w R2w L2w L2w |
psrad xmm0, 16 ; R1d L1d R0d L0d |
psrad xmm1, 16 ; R3d L3d R2d L2d |
cvtdq2ps xmm0, xmm0 ; time to use all power |
cvtdq2ps xmm1, xmm1 ; of the dark side |
mulps xmm0, xmm4 ; R1f' L1f' R0f' L0f' |
mulps xmm1, xmm4 ; R3f' L3f' R2f' L2f' |
punpcklwd xmm2, xmm3 ; R1w R1w L1w L1W R0w R0w L0w L0w |
punpckhwd xmm3, xmm3 ; R3w R3w L3w L3w R2w R2w L2w L2w |
psrad xmm2, 16 ; R1d L1d R0d L0d |
psrad xmm3, 16 ; R3d L3d R2d L2d |
cvtdq2ps xmm2, xmm2 ; time to use all power |
cvtdq2ps xmm3, xmm3 ; of the dark side |
mulps xmm2, xmm6 ; R1f' L1f' R0f' L0f' |
mulps xmm3, xmm6 ; R3f' L3f' R2f' L2f' |
addps xmm0, xmm2 |
addps xmm1, xmm3 |
cvtps2dq xmm0, xmm0 ; R1d' L1d' R0d' L0d' |
cvtps2dq xmm1, xmm1 ; R3d' L3d' R2d' L2d' |
packssdw xmm0, xmm0 ; R1w' L1w' R0w' L0w' R1w' L1w' R0w' L0w' |
packssdw xmm1, xmm1 ; R3w' L3w' R2w' L2w' R3w' L3w' R2w' L2w' |
punpcklqdq xmm0, xmm1 ; R3w' L3w' R2w' L2w' R1w' L1w' R0w' L0w' |
movntdq [edi], xmm0 |
add edi, 16 |
dec ebx |
jnz .mix |
ret |
else ; fixed point mmx version |
align 4 |
proc mix_all stdcall, dest:dword, list:dword, count:dword |
mov edi, [dest] |
mov ebx, 64 |
.mix: |
mov edx, [list] |
mov ecx, [count] |
mov eax, [edx] |
movq mm0, [eax] |
movd mm1, [edx+4] |
punpckldq mm1, mm1 |
pmulhw mm0, mm1 |
psllw mm0, 1 |
.mix_loop: |
add dword [edx], 8 |
add edx, 12 |
dec ecx |
jz @F |
mov eax, [edx] |
movq mm1, [eax] |
movd mm2, [edx+4] |
punpckldq mm2, mm2 |
pmulhw mm1, mm2 |
psllw mm1, 1 |
paddsw mm0, mm1 |
jmp .mix_loop |
@@: |
movq [edi], mm0 |
add edi, 8 |
dec ebx |
jnz .mix |
ret |
endp |
end if |
align 4 |
proc resample_1 stdcall, dest:dword,src:dword,\ |
r_dt:dword, r_size:dword,r_end:dword |
; dest equ esp+8 |
; src equ esp+12 |
; r_dt equ esp+16 |
; r_size equ esp+20 |
; r_end equ esp+24 |
mov edi, [dest] |
mov edx, [src] |
sub edx, 32*2 |
mov eax, 16 |
align 4 |
.l1: |
mov ecx, eax |
mov esi, eax |
and ecx, 0x7FFF |
shr esi, 15 |
lea esi, [edx+esi*2] |
movsx ebp, word [esi] |
movsx esi, word [esi+2] |
mov ebx, 32768 |
imul esi, ecx |
sub ebx, ecx |
imul ebx, ebp |
lea ecx, [ebx+esi+16384] |
sar ecx, 15 |
cmp ecx, 32767 ; 00007fffH |
jle @f |
mov ecx, 32767 ; 00007fffH |
jmp .write |
@@: |
cmp ecx, -32768 ; ffff8000H |
jge .write |
mov ecx, -32768 ; ffff8000H |
.write: |
mov ebx, ecx |
shl ebx, 16 |
mov bx, cx |
mov [edi], ebx |
add edi, 4 |
add eax, [esp+16] |
cmp eax, [esp+24] |
jb .l1 |
mov ebp, esp |
sub edi, [dest] |
mov eax, edi |
ret |
endp |
align 4 |
proc resample_18 stdcall, dest:dword,src:dword,\ |
r_dt:dword, r_size:dword,r_end:dword |
mov edi, [dest] |
mov edx, [src] |
sub edx, 32 |
mov esi, 16 |
align 4 |
.l1: |
mov ecx, esi |
mov eax, esi |
and ecx, 0x7FFF |
shr eax, 15 |
lea eax, [edx+eax] |
mov bx, word [eax] |
sub bh, 0x80 |
sub bl, 0x80 |
movsx eax, bh |
shl eax, 8 |
movsx ebp, bl |
shl ebp, 8 |
mov ebx, 32768 |
imul eax, ecx |
sub ebx, ecx |
imul ebx, ebp |
lea ecx, [ebx+eax+16384] |
sar ecx, 15 |
cmp ecx, 32767 ; 00007fffH |
jle @f |
mov ecx, 32767 ; 00007fffH |
jmp .write |
@@: |
cmp ecx, -32768 ; ffff8000H |
jge .write |
mov ecx, -32768 ; ffff8000H |
.write: |
mov ebx, ecx |
shl ebx, 16 |
mov bx, cx |
mov [edi], ebx |
add edi, 4 |
add esi, [esp+16] |
cmp esi, [esp+24] |
jb .l1 |
mov ebp, esp |
sub edi, [dest] |
mov eax, edi |
ret |
endp |
align 4 |
proc copy_stream stdcall, dest:dword,src:dword,\ |
r_dt:dword, r_size:dword,r_end:dword |
mov ecx, [r_size] |
mov eax, ecx |
shr ecx, 2 |
mov esi, [src] |
mov edi, [dest] |
cld |
rep movsd |
ret |
endp |
align 4 |
proc resample_2 stdcall, dest:dword,src:dword,\ |
r_dt:dword, r_size:dword,r_end:dword |
mov edx, [src] |
sub edx, 32*4 |
mov edi, [dest] |
mov ebx, [r_dt] |
mov eax, 16 |
emms |
align 4 |
.l1: |
mov ecx, eax |
mov esi, eax |
and ecx, 0x7FFF |
shr esi, 15 |
lea esi, [edx+esi*4] |
movq mm0, [esi] |
movq mm1, mm0 |
movd mm2, ecx |
punpcklwd mm2, mm2 |
movq mm3, qword [m7] ;0x8000 |
psubw mm3, mm2 ; ;0x8000 - iconst |
punpckldq mm3, mm2 |
pmulhw mm0, mm3 |
pmullw mm1, mm3 |
movq mm4, mm1 |
punpcklwd mm1, mm0 |
punpckhwd mm4, mm0 |
paddd mm1, mm4 |
psrad mm1, 15 |
packssdw mm1, mm1 |
movd [edi], mm1 |
add edi, 4 |
add eax, ebx |
cmp eax, [r_end] |
jb .l1 |
emms |
sub edi, [dest] |
mov eax, edi |
ret |
endp |
align 4 |
proc resample_28 stdcall, dest:dword,src:dword,\ |
r_dt:dword, r_size:dword,r_end:dword |
mov edx, [src] |
sub edx, 32*2 |
mov edi, [dest] |
mov ebx, [r_dt] |
mov eax, 16 |
emms |
movq mm7, [mm80] |
movq mm6, [mm_mask] |
align 4 |
.l1: |
mov ecx, eax |
mov esi, eax |
and ecx, 0x7FFF |
shr esi, 15 |
lea esi, [edx+esi*2] |
movq mm0, [esi] |
psubb mm0, mm7 |
punpcklbw mm0, mm0 |
pand mm0, mm6 |
movq mm1, mm0 |
movd mm2, ecx |
punpcklwd mm2, mm2 |
movq mm3, qword [m7] ; // 0x8000 |
psubw mm3, mm2 ; // 0x8000 - iconst |
punpckldq mm3, mm2 |
pmulhw mm0, mm3 |
pmullw mm1, mm3 |
movq mm4, mm1 |
punpcklwd mm1, mm0 |
punpckhwd mm4, mm0 |
paddd mm1, mm4 |
psrad mm1, 15 |
packssdw mm1, mm1 |
movd [edi], mm1 |
add edi, 4 |
add eax, ebx |
cmp eax, [r_end] |
jb .l1 |
emms |
sub edi, [dest] |
mov eax, edi |
ret |
endp |
proc m16_stereo stdcall, dest:dword,src:dword,\ |
r_dt:dword, r_size:dword,r_end:dword |
mov esi, [src] |
mov edi, [dest] |
mov ecx, [r_size] |
shr ecx, 8 |
@@: |
call m16_s_mmx |
add edi, 128 |
add esi, 64 |
call m16_s_mmx |
add edi, 128 |
add esi, 64 |
call m16_s_mmx |
add edi, 128 |
add esi, 64 |
call m16_s_mmx |
add edi, 128 |
add esi, 64 |
dec ecx |
jnz @b |
mov eax, [r_size] |
add eax, eax |
ret |
endp |
align 4 |
proc s8_stereo stdcall, dest:dword,src:dword,\ |
r_dt:dword, r_size:dword,r_end:dword |
mov esi, [src] |
mov edi, [dest] |
mov ecx, [r_size] |
shr ecx, 7 |
movq mm7, [mm80] |
movq mm6, [mm_mask] |
@@: |
call s8_s_mmx |
add edi, 64 |
add esi, 32 |
call s8_s_mmx |
add edi, 64 |
add esi, 32 |
call s8_s_mmx |
add edi, 64 |
add esi, 32 |
call s8_s_mmx |
add edi, 64 |
add esi, 32 |
dec ecx |
jnz @b |
mov eax, [r_size] |
add eax, eax |
ret |
endp |
proc m8_stereo stdcall, dest:dword,src:dword,\ |
r_dt:dword, r_size:dword,r_end:dword |
mov esi, [src] |
mov edi, [dest] |
mov ecx, [r_size] |
shr ecx, 6 |
movq mm7, [mm80] |
movq mm6, [mm_mask] |
@@: |
call m8_s_mmx |
add edi, 64 |
add esi, 16 |
call m8_s_mmx |
add edi, 64 |
add esi, 16 |
call m8_s_mmx |
add edi, 64 |
add esi, 16 |
call m8_s_mmx |
add edi, 64 |
add esi, 16 |
dec ecx |
jnz @b |
mov eax, [r_size] |
add eax, eax |
add eax, eax |
ret |
endp |
align 4 |
proc alloc_mix_buff |
bsf eax, [mix_buff_map] |
jnz .find |
xor eax, eax |
ret |
.find: |
btr [mix_buff_map], eax |
shl eax, 9 |
add eax, [mix_buff] |
ret |
endp |
align 4 |
proc m16_s_mmx |
movq mm0, [esi] |
movq mm1, mm0 |
punpcklwd mm0, mm0 |
punpckhwd mm1, mm1 |
movq [edi], mm0 |
movq [edi+8], mm1 |
movq mm0, [esi+8] |
movq mm1, mm0 |
punpcklwd mm0, mm0 |
punpckhwd mm1, mm1 |
movq [edi+16], mm0 |
movq [edi+24], mm1 |
movq mm0, [esi+16] |
movq mm1, mm0 |
punpcklwd mm0, mm0 |
punpckhwd mm1, mm1 |
movq [edi+32], mm0 |
movq [edi+40], mm1 |
movq mm0, [esi+24] |
movq mm1, mm0 |
punpcklwd mm0, mm0 |
punpckhwd mm1, mm1 |
movq [edi+48], mm0 |
movq [edi+56], mm1 |
movq mm0, [esi+32] |
movq mm1, mm0 |
punpcklwd mm0, mm0 |
punpckhwd mm1, mm1 |
movq [edi+64], mm0 |
movq [edi+72], mm1 |
movq mm0, [esi+40] |
movq mm1, mm0 |
punpcklwd mm0, mm0 |
punpckhwd mm1, mm1 |
movq [edi+80], mm0 |
movq [edi+88], mm1 |
movq mm0, [esi+48] |
movq mm1, mm0 |
punpcklwd mm0, mm0 |
punpckhwd mm1, mm1 |
movq [edi+96], mm0 |
movq [edi+104], mm1 |
movq mm0, [esi+56] |
movq mm1, mm0 |
punpcklwd mm0, mm0 |
punpckhwd mm1, mm1 |
movq [edi+112], mm0 |
movq [edi+120], mm1 |
ret |
endp |
align 4 |
proc s8_s_mmx |
movq mm0, [esi] |
psubb mm0, mm7 |
movq mm1, mm0 |
punpcklbw mm0, mm0 |
pand mm0, mm6 |
punpckhbw mm1, mm1 |
pand mm1, mm6 |
movq [edi], mm0 |
movq [edi+8], mm1 |
movq mm0, [esi+8] |
psubb mm0, mm7 |
movq mm1, mm0 |
punpcklbw mm0, mm0 |
pand mm0, mm6 |
punpckhbw mm1, mm1 |
pand mm1, mm6 |
movq [edi+16], mm0 |
movq [edi+24], mm1 |
movq mm0, [esi+16] |
psubb mm0, mm7 |
movq mm1, mm0 |
punpcklbw mm0, mm0 |
pand mm0, mm6 |
punpckhbw mm1, mm1 |
pand mm1, mm6 |
movq [edi+32], mm0 |
movq [edi+40], mm1 |
movq mm0, [esi+24] |
psubb mm0, mm7 |
movq mm1, mm0 |
punpcklbw mm0, mm0 |
pand mm0, mm6 |
punpckhbw mm1, mm1 |
pand mm1, mm6 |
movq [edi+48], mm0 |
movq [edi+56], mm1 |
ret |
endp |
align 4 |
proc m8_s_mmx |
movq mm0, [esi] |
psubb mm0, mm7 |
movq mm1, mm0 |
punpcklbw mm0, mm0 |
pand mm0, mm6 |
punpckhbw mm1, mm1 |
pand mm1, mm6 |
movq mm2, mm0 |
punpcklwd mm0, mm0 |
punpckhwd mm2, mm2 |
movq mm3, mm1 |
punpcklwd mm1, mm1 |
punpckhwd mm3, mm3 |
movq [edi], mm0 |
movq [edi+8], mm2 |
movq [edi+16], mm1 |
movq [edi+24], mm3 |
movq mm0, [esi+8] |
psubb mm0, mm7 |
movq mm1, mm0 |
punpcklbw mm0, mm0 |
pand mm0, mm6 |
punpckhbw mm1, mm1 |
pand mm1, mm6 |
movq mm2, mm0 |
punpcklwd mm0, mm0 |
punpckhwd mm2, mm2 |
movq mm3, mm1 |
punpcklwd mm1, mm1 |
punpckhwd mm3, mm3 |
movq [edi+32], mm0 |
movq [edi+40], mm2 |
movq [edi+48], mm1 |
movq [edi+56], mm3 |
ret |
endp |
align 4 |
proc mix_2_1 stdcall, output:dword, str0:dword, str1:dword |
mov edi, [output] |
mov eax, [str0] |
mov ebx, [str1] |
mov esi, 128 |
call [mix_2_core] ;edi, eax, ebx |
add edi, esi |
add eax, esi |
add ebx, esi |
call [mix_2_core] ;edi, eax, ebx |
add edi, esi |
add eax, esi |
add ebx, esi |
call [mix_2_core] ;edi, eax, ebx |
add edi, esi |
add eax, esi |
add ebx, esi |
call [mix_2_core] ;edi, eax, ebx |
ret |
endp |
align 4 |
proc mix_3_1 stdcall, output:dword, str0:dword, str1:dword, str2:dword |
mov edi, [output] |
mov eax, [str0] |
mov ebx, [str1] |
mov ecx, [str2] |
mov esi, 128 |
call [mix_3_core] |
add edi, esi |
add eax, esi |
add ebx, esi |
add ecx, esi |
call [mix_3_core] |
add edi, esi |
add eax, esi |
add ebx, esi |
add ecx, esi |
call [mix_3_core] |
add edi, esi |
add eax, esi |
add ebx, esi |
add ecx, esi |
call [mix_3_core] |
ret |
endp |
align 4 |
proc mix_4_1 stdcall, str0:dword, str1:dword,\ |
str2:dword, str3:dword |
local output:DWORD |
call alloc_mix_buff |
and eax, eax |
jz .err |
mov [output], eax |
mov edi, eax |
mov eax, [str0] |
mov ebx, [str1] |
mov ecx, [str2] |
mov edx, [str3] |
mov esi, 128 |
call [mix_4_core] ;edi, eax, ebx, ecx, edx |
add edi, esi |
add eax, esi |
add ebx, esi |
add ecx, esi |
add edx, esi |
call [mix_4_core] ;edi, eax, ebx, ecx, edx |
add edi, esi |
add eax, esi |
add ebx, esi |
add ecx, esi |
add edx, esi |
call [mix_4_core] ;edi, eax, ebx, ecx, edx |
add edi, esi |
add eax, esi |
add ebx, esi |
add ecx, esi |
add edx, esi |
call [mix_4_core] ;edi, eax, ebx, ecx, edx |
mov eax, [output] |
ret |
.err: |
xor eax, eax |
ret |
endp |
align 4 |
proc final_mix stdcall, output:dword, str0:dword, str1:dword,\ |
str2:dword, str3:dword |
mov edi, [output] |
mov eax, [str0] |
mov ebx, [str1] |
mov ecx, [str2] |
mov edx, [str3] |
mov esi, 128 |
call [mix_4_core] ;edi, eax, ebx, ecx, edx |
add edi, esi |
add eax, esi |
add ebx, esi |
add ecx, esi |
add edx, esi |
call [mix_4_core] ;edi, eax, ebx, ecx, edx |
add edi, esi |
add eax, esi |
add ebx, esi |
add ecx, esi |
add edx, esi |
call [mix_4_core] ;edi, eax, ebx, ecx, edx |
add edi, esi |
add eax, esi |
add ebx, esi |
add ecx, esi |
add edx, esi |
call [mix_4_core] ;edi, eax, ebx, ecx, edx |
ret |
endp |
align 4 |
proc copy_mem stdcall, output:dword, input:dword |
mov edi, [output] |
mov esi, [input] |
mov ecx, 0x80 |
.l1: |
mov eax, [esi] |
mov [edi], eax |
add esi, 4 |
add edi, 4 |
loop .l1 |
ret |
endp |
proc memcpy |
@@: |
mov eax, [esi] |
mov [edi], eax |
add esi, 4 |
add edi, 4 |
dec ecx |
jnz @B |
ret |
endp |
if 0 |
align 4 |
proc new_mix stdcall, output:dword |
locals |
mixCounter dd ? |
mixIndex dd ? |
streamIndex dd ? |
inputCount dd ? |
main_count dd ? |
blockCount dd ? |
mix_out dd ? |
endl |
call prepare_playlist |
cmp [play_count], 0 |
je .exit |
call FpuSave |
mov [main_count], 32; |
.l00: |
mov [mix_buff_map], 0x0000FFFF; |
xor eax, eax |
mov [mixCounter], eax |
mov [mixIndex], eax |
mov [streamIndex], eax; |
mov ebx, [play_count] |
mov [inputCount], ebx |
.l0: |
mov ecx, 4 |
.l1: |
mov ebx, [streamIndex] |
mov esi, [play_list+ebx*4] |
mov eax, [esi+STREAM.work_read] |
add [esi+STREAM.work_read], 512 |
mov ebx, [mixIndex] |
mov [mix_input+ebx*4], eax |
inc [mixCounter] |
inc [mixIndex] |
inc [streamIndex] |
dec [inputCount] |
jz .m2 |
dec ecx |
jnz .l1 |
cmp [mixCounter], 4 |
jnz .m2 |
stdcall mix_4_1, [mix_input], [mix_input+4], [mix_input+8], [mix_input+12] |
sub [mixIndex], 4 |
mov ebx, [mixIndex] |
mov [mix_input+ebx*4], eax |
inc [mixIndex] |
mov [mixCounter], 0 |
cmp [inputCount], 0 |
jnz .l0 |
.m2: |
cmp [mixIndex], 1 |
jne @f |
stdcall copy_mem, [output], [mix_input] |
jmp .m3 |
@@: |
cmp [mixIndex], 2 |
jne @f |
stdcall mix_2_1, [output], [mix_input], [mix_input+4] |
jmp .m3 |
@@: |
cmp [mixIndex], 3 |
jne @f |
stdcall mix_3_1, [output], [mix_input], [mix_input+4], [mix_input+8] |
jmp .m3 |
@@: |
stdcall final_mix, [output], [mix_input], [mix_input+4], [mix_input+8], [mix_input+12] |
.m3: |
add [output], 512 |
dec [main_count] |
jnz .l00 |
call update_stream |
emms |
call FpuRestore |
ret |
.exit: |
mov edi, [output] |
mov ecx, 0x1000 |
xor eax, eax |
cld |
rep stosd |
ret |
endp |
end if |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
/kernel/branches/Kolibri-acpi/drivers/proc32.inc |
---|
0,0 → 1,267 |
; Macroinstructions for defining and calling procedures |
macro stdcall proc,[arg] ; directly call STDCALL procedure |
{ common |
if ~ arg eq |
reverse |
pushd arg |
common |
end if |
call proc } |
macro invoke proc,[arg] ; indirectly call STDCALL procedure |
{ common |
if ~ arg eq |
reverse |
pushd arg |
common |
end if |
call [proc] } |
macro ccall proc,[arg] ; directly call CDECL procedure |
{ common |
size@ccall = 0 |
if ~ arg eq |
reverse |
pushd arg |
size@ccall = size@ccall+4 |
common |
end if |
call proc |
if size@ccall |
add esp, size@ccall |
end if } |
macro cinvoke proc,[arg] ; indirectly call CDECL procedure |
{ common |
size@ccall = 0 |
if ~ arg eq |
reverse |
pushd arg |
size@ccall = size@ccall+4 |
common |
end if |
call [proc] |
if size@ccall |
add esp, size@ccall |
end if } |
macro proc [args] ; define procedure |
{ common |
match name params, args> |
\{ define@proc name,<params \} } |
prologue@proc equ prologuedef |
macro prologuedef procname,flag,parmbytes,localbytes,reglist |
{ if parmbytes | localbytes |
push ebp |
mov ebp, esp |
if localbytes |
sub esp, localbytes |
end if |
end if |
irps reg, reglist \{ push reg \} } |
epilogue@proc equ epiloguedef |
macro epiloguedef procname,flag,parmbytes,localbytes,reglist |
{ irps reg, reglist \{ reverse pop reg \} |
if parmbytes | localbytes |
leave |
end if |
if flag and 10000b |
retn |
else |
retn parmbytes |
end if } |
macro define@proc name,statement |
{ local params,flag,regs,parmbytes,localbytes,current |
if used name |
name: |
match =stdcall args, statement \{ params equ args |
flag = 11b \} |
match =stdcall, statement \{ params equ |
flag = 11b \} |
match =c args, statement \{ params equ args |
flag = 10001b \} |
match =c, statement \{ params equ |
flag = 10001b \} |
match =params, params \{ params equ statement |
flag = 0 \} |
virtual at ebp+8 |
match =uses reglist=,args, params \{ regs equ reglist |
params equ args \} |
match =regs =uses reglist, regs params \{ regs equ reglist |
params equ \} |
match =regs, regs \{ regs equ \} |
match =,args, params \{ defargs@proc args \} |
match =args@proc args, args@proc params \{ defargs@proc args \} |
parmbytes = $ - (ebp+8) |
end virtual |
name # % = parmbytes/4 |
all@vars equ |
current = 0 |
match prologue:reglist, prologue@proc:<regs> \{ prologue name,flag,parmbytes,localbytes,reglist \} |
macro locals |
\{ virtual at ebp-localbytes+current |
macro label . \\{ deflocal@proc .,:, \\} |
struc db [val] \\{ \common deflocal@proc .,db,val \\} |
struc dw [val] \\{ \common deflocal@proc .,dw,val \\} |
struc dp [val] \\{ \common deflocal@proc .,dp,val \\} |
struc dd [val] \\{ \common deflocal@proc .,dd,val \\} |
struc dt [val] \\{ \common deflocal@proc .,dt,val \\} |
struc dq [val] \\{ \common deflocal@proc .,dq,val \\} |
struc rb cnt \\{ deflocal@proc .,rb cnt, \\} |
struc rw cnt \\{ deflocal@proc .,rw cnt, \\} |
struc rp cnt \\{ deflocal@proc .,rp cnt, \\} |
struc rd cnt \\{ deflocal@proc .,rd cnt, \\} |
struc rt cnt \\{ deflocal@proc .,rt cnt, \\} |
struc rq cnt \\{ deflocal@proc .,rq cnt, \\} \} |
macro endl |
\{ purge label |
restruc db,dw,dp,dd,dt,dq |
restruc rb,rw,rp,rd,rt,rq |
restruc byte,word,dword,pword,tword,qword |
current = $-(ebp-localbytes) |
end virtual \} |
macro ret operand |
\{ match any, operand \\{ retn operand \\} |
match , operand \\{ match epilogue:reglist, epilogue@proc:<regs> |
\\\{ epilogue name,flag,parmbytes,localbytes,reglist \\\} \\} \} |
macro finish@proc \{ localbytes = (((current-1) shr 2)+1) shl 2 |
end if \} } |
macro defargs@proc [arg] |
{ common |
if ~ arg eq |
forward |
local ..arg,current@arg |
match argname:type, arg |
\{ current@arg equ argname |
label ..arg type |
argname equ ..arg |
if dqword eq type |
dd ?,?,?,? |
else if tbyte eq type |
dd ?,?,? |
else if qword eq type | pword eq type |
dd ?,? |
else |
dd ? |
end if \} |
match =current@arg,current@arg |
\{ current@arg equ arg |
arg equ ..arg |
..arg dd ? \} |
common |
args@proc equ current@arg |
forward |
restore current@arg |
common |
end if } |
macro deflocal@proc name,def,[val] |
{ common |
match vars, all@vars \{ all@vars equ all@vars, \} |
all@vars equ all@vars name |
forward |
local ..var,..tmp |
..var def val |
match =?, val \{ ..tmp equ \} |
match any =dup (=?), val \{ ..tmp equ \} |
match tmp : value, ..tmp : val |
\{ tmp: end virtual |
initlocal@proc ..var,def value |
virtual at tmp\} |
common |
match first rest, ..var, \{ name equ first \} } |
macro initlocal@proc name,def |
{ virtual at name |
def |
size@initlocal = $ - name |
end virtual |
position@initlocal = 0 |
while size@initlocal > position@initlocal |
virtual at name |
def |
if size@initlocal - position@initlocal < 2 |
current@initlocal = 1 |
load byte@initlocal byte from name+position@initlocal |
else if size@initlocal - position@initlocal < 4 |
current@initlocal = 2 |
load word@initlocal word from name+position@initlocal |
else |
current@initlocal = 4 |
load dword@initlocal dword from name+position@initlocal |
end if |
end virtual |
if current@initlocal = 1 |
mov byte [name+position@initlocal], byte@initlocal |
else if current@initlocal = 2 |
mov word [name+position@initlocal], word@initlocal |
else |
mov dword [name+position@initlocal], dword@initlocal |
end if |
position@initlocal = position@initlocal + current@initlocal |
end while } |
macro endp |
{ purge ret,locals,endl |
finish@proc |
purge finish@proc |
restore regs@proc |
match all,args@proc \{ restore all \} |
restore args@proc |
match all,all@vars \{ restore all \} } |
macro local [var] |
{ common |
locals |
forward done@local equ |
match varname[count]:vartype, var |
\{ match =BYTE, vartype \\{ varname rb count |
restore done@local \\} |
match =WORD, vartype \\{ varname rw count |
restore done@local \\} |
match =DWORD, vartype \\{ varname rd count |
restore done@local \\} |
match =PWORD, vartype \\{ varname rp count |
restore done@local \\} |
match =QWORD, vartype \\{ varname rq count |
restore done@local \\} |
match =TBYTE, vartype \\{ varname rt count |
restore done@local \\} |
match =DQWORD, vartype \\{ label varname dqword |
rq count+count |
restore done@local \\} |
match , done@local \\{ virtual |
varname vartype |
end virtual |
rb count*sizeof.\#vartype |
restore done@local \\} \} |
match :varname:vartype, done@local:var |
\{ match =BYTE, vartype \\{ varname db ? |
restore done@local \\} |
match =WORD, vartype \\{ varname dw ? |
restore done@local \\} |
match =DWORD, vartype \\{ varname dd ? |
restore done@local \\} |
match =PWORD, vartype \\{ varname dp ? |
restore done@local \\} |
match =QWORD, vartype \\{ varname dq ? |
restore done@local \\} |
match =TBYTE, vartype \\{ varname dt ? |
restore done@local \\} |
match =DQWORD, vartype \\{ label varname dqword |
dq ?,? |
restore done@local \\} |
match , done@local \\{ varname vartype |
restore done@local \\} \} |
match ,done@local |
\{ var |
restore done@local \} |
common |
endl } |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
/kernel/branches/Kolibri-acpi/drivers/uart.asm |
---|
0,0 → 1,976 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
format MS COFF |
DEBUG equ 1 |
include 'proc32.inc' |
include 'imports.inc' |
API_VERSION equ 0 |
UART_VERSION equ API_VERSION |
PG_SW equ 0x003 |
page_tabs equ 0xFDC00000 ;hack |
OS_BASE equ 0x80000000 |
SLOT_BASE equ (OS_BASE+0x0080000) |
TASK_COUNT equ (OS_BASE+0x0003004) |
CURRENT_TASK equ (OS_BASE+0x0003000) |
struc APPOBJ ;common object header |
{ |
.magic dd ? ; |
.destroy dd ? ;internal destructor |
.fd dd ? ;next object in list |
.bk dd ? ;prev object in list |
.pid dd ? ;owner id |
}; |
virtual at 0 |
APPOBJ APPOBJ |
end virtual |
struc IOCTL |
{ .handle dd ? |
.io_code dd ? |
.input dd ? |
.inp_size dd ? |
.output dd ? |
.out_size dd ? |
} |
virtual at 0 |
IOCTL IOCTL |
end virtual |
DEBUG equ 1 |
DRV_ENTRY equ 1 |
DRV_EXIT equ -1 |
THR_REG equ 0; x3f8 ;transtitter/reciever |
IER_REG equ 1; x3f9 ;interrupt enable |
IIR_REG equ 2; x3fA ;interrupt info |
LCR_REG equ 3; x3FB ;line control |
MCR_REG equ 4; x3FC ;modem control |
LSR_REG equ 5; x3FD ;line status |
MSR_REG equ 6; x3FE ;modem status |
LCR_5BIT equ 0x00 |
LCR_6BIT equ 0x01 |
LCR_7BIT equ 0x02 |
LCR_8BIT equ 0x03 |
LCR_STOP_1 equ 0x00 |
LCR_STOP_2 equ 0x04 |
LCR_PARITY equ 0x08 |
LCR_EVEN equ 0x10 |
LCR_STICK equ 0x20 |
LCR_BREAK equ 0x40 |
LCR_DLAB equ 0x80 |
LSR_DR equ 0x01 ;data ready |
LSR_OE equ 0x02 ;overrun error |
LSR_PE equ 0x04 ;parity error |
LSR_FE equ 0x08 ;framing error |
LSR_BI equ 0x10 ;break interrupt |
LSR_THRE equ 0x20 ;transmitter holding empty |
LSR_TEMT equ 0x40 ;transmitter empty |
LSR_FER equ 0x80 ;FIFO error |
FCR_EFIFO equ 0x01 ;enable FIFO |
FCR_CRB equ 0x02 ;clear reciever FIFO |
FCR_CXMIT equ 0x04 ;clear transmitter FIFO |
FCR_RDY equ 0x08 ;set RXRDY and TXRDY pins |
FCR_FIFO_1 equ 0x00 ;1 byte trigger |
FCR_FIFO_4 equ 0x40 ;4 bytes trigger |
FCR_FIFO_8 equ 0x80 ;8 bytes trigger |
FCR_FIFO_14 equ 0xC0 ;14 bytes trigger |
IIR_INTR equ 0x01 ;1= no interrupts |
IER_RDAI equ 0x01 ;reciever data interrupt |
IER_THRI equ 0x02 ;transmitter empty interrupt |
IER_LSI equ 0x04 ;line status interrupt |
IER_MSI equ 0x08 ;modem status interrupt |
MCR_DTR equ 0x01 ;0-> DTR=1, 1-> DTR=0 |
MCR_RTS equ 0x02 ;0-> RTS=1, 1-> RTS=0 |
MCR_OUT_1 equ 0x04 ;0-> OUT1=1, 1-> OUT1=0 |
MCR_OUT_2 equ 0x08 ;0-> OUT2=1, 1-> OUT2=0; enable intr |
MCR_LOOP equ 0x10 ;lopback mode |
MSR_DCTS equ 0x01 ;delta clear to send |
MSR_DDSR equ 0x02 ;delta data set redy |
MSR_TERI equ 0x04 ;trailinh edge of ring |
MSR_DDCD equ 0x08 ;delta carrier detect |
RATE_50 equ 0 |
RATE_75 equ 1 |
RATE_110 equ 2 |
RATE_134 equ 3 |
RATE_150 equ 4 |
RATE_300 equ 5 |
RATE_600 equ 6 |
RATE_1200 equ 7 |
RATE_1800 equ 8 |
RATE_2000 equ 9 |
RATE_2400 equ 10 |
RATE_3600 equ 11 |
RATE_4800 equ 12 |
RATE_7200 equ 13 |
RATE_9600 equ 14 |
RATE_19200 equ 15 |
RATE_38400 equ 16 |
RATE_57600 equ 17 |
RATE_115200 equ 18 |
COM_1 equ 1 |
COM_2 equ 2 |
COM_3 equ 3 |
COM_4 equ 4 |
COM_MAX equ 2 ;only two port supported |
COM_1_BASE equ 0x3F8 |
COM_2_BASE equ 0x2F8 |
COM_1_IRQ equ 4 |
COM_2_IRQ equ 3 |
UART_CLOSED equ 0 |
UART_TRANSMIT equ 1 |
UART_STOP equ 2 |
struc UART |
{ |
.lock dd ? |
.base dd ? |
.lcr_reg dd ? |
.mcr_reg dd ? |
.rate dd ? |
.mode dd ? |
.state dd ? |
.rcvr_buff dd ? |
.rcvr_rp dd ? |
.rcvr_wp dd ? |
.rcvr_count dd ? |
.rcvr_top dd ? |
.xmit_buff dd ? |
.xmit_rp dd ? |
.xmit_wp dd ? |
.xmit_count dd ? |
.xmit_free dd ? |
.xmit_top dd ? |
} |
virtual at 0 |
UART UART |
end virtual |
UART_SIZE equ 18*4 |
struc CONNECTION |
{ |
.magic dd ? ;'CNCT' |
.destroy dd ? ;internal destructor |
.fd dd ? ;next object in list |
.bk dd ? ;prev object in list |
.pid dd ? ;owner id |
.id dd ? ;reserved |
.uart dd ? ;uart pointer |
} |
virtual at 0 |
CONNECTION CONNECTION |
end virtual |
CONNECTION_SIZE equ 7*4 |
public START |
public service_proc |
public version |
section '.flat' code readable align 16 |
proc START stdcall, state:dword |
cmp [state], 1 |
jne .stop |
mov eax, UART_SIZE |
call Kmalloc |
test eax, eax |
jz .fail |
mov [com1], eax |
mov edi, eax |
mov ecx, UART_SIZE/4 |
xor eax, eax |
cld |
rep stosd |
mov eax, [com1] |
mov [eax+UART.base], COM_1_BASE |
stdcall AllocKernelSpace, 32768 |
mov edi, [com1] |
mov edx, eax |
mov [edi+UART.rcvr_buff], eax |
add eax, 8192 |
mov [edi+UART.rcvr_top], eax |
add eax, 8192 |
mov [edi+UART.xmit_buff], eax |
add eax, 8192 |
mov [edi+UART.xmit_top], eax |
call AllocPage |
test eax, eax |
jz .fail |
shr edx, 12 |
or eax, PG_SW |
mov [page_tabs+edx*4], eax |
mov [page_tabs+edx*4+8], eax |
call AllocPage |
test eax, eax |
jz .fail |
or eax, PG_SW |
mov [page_tabs+edx*4+4], eax |
mov [page_tabs+edx*4+12], eax |
call AllocPage |
test eax, eax |
jz .fail |
or eax, PG_SW |
mov [page_tabs+edx*4+16], eax |
mov [page_tabs+edx*4+24], eax |
call AllocPage |
test eax, eax |
jz .fail |
or eax, PG_SW |
mov [page_tabs+edx*4+20], eax |
mov [page_tabs+edx*4+28], eax |
mov eax, [edi+UART.rcvr_buff] |
invlpg [eax] |
invlpg [eax+0x1000] |
invlpg [eax+0x2000] |
invlpg [eax+0x3000] |
invlpg [eax+0x4000] |
invlpg [eax+0x5000] |
invlpg [eax+0x6000] |
invlpg [eax+0x7000] |
mov eax, edi |
call uart_reset.internal ;eax= uart |
stdcall AttachIntHandler, COM_1_IRQ, com_1_isr, dword 0 |
stdcall RegService, sz_uart_srv, service_proc |
ret |
.fail: |
.stop: |
xor eax, eax |
ret |
endp |
handle equ IOCTL.handle |
io_code equ IOCTL.io_code |
input equ IOCTL.input |
inp_size equ IOCTL.inp_size |
output equ IOCTL.output |
out_size equ IOCTL.out_size |
SRV_GETVERSION equ 0 |
PORT_OPEN equ 1 |
PORT_CLOSE equ 2 |
PORT_RESET equ 3 |
PORT_SETMODE equ 4 |
PORT_GETMODE equ 5 |
PORT_SETMCR equ 6 |
PORT_GETMCR equ 7 |
PORT_READ equ 8 |
PORT_WRITE equ 9 |
align 4 |
proc service_proc stdcall, ioctl:dword |
mov ebx, [ioctl] |
mov eax, [ebx+io_code] |
cmp eax, PORT_WRITE |
ja .fail |
cmp eax, SRV_GETVERSION |
jne @F |
mov eax, [ebx+output] |
cmp [ebx+out_size], 4 |
jne .fail |
mov [eax], dword UART_VERSION |
xor eax, eax |
ret |
@@: |
cmp eax, PORT_OPEN |
jne @F |
cmp [ebx+out_size], 4 |
jne .fail |
mov ebx, [ebx+input] |
mov eax, [ebx] |
call uart_open |
mov ebx, [ioctl] |
mov ebx, [ebx+output] |
mov [ebx], ecx |
ret |
@@: |
mov esi, [ebx+input] ;input buffer |
mov edi, [ebx+output] |
call [uart_func+eax*4] |
ret |
.fail: |
or eax, -1 |
ret |
endp |
restore handle |
restore io_code |
restore input |
restore inp_size |
restore output |
restore out_size |
; param |
; esi= input buffer |
; +0 connection |
; |
; retval |
; eax= error code |
align 4 |
uart_reset: |
mov eax, [esi] |
cmp [eax+APPOBJ.magic], 'CNCT' |
jne .fail |
cmp [eax+APPOBJ.destroy], uart_close.destroy |
jne .fail |
mov eax, [eax+CONNECTION.uart] |
test eax, eax |
jz .fail |
; set mode 2400 bod 8-bit |
; disable DTR & RTS |
; clear FIFO |
; clear pending interrupts |
; |
; param |
; eax= uart |
align 4 |
.internal: |
mov esi, eax |
mov [eax+UART.state], UART_CLOSED |
mov edx, [eax+UART.base] |
add edx, MCR_REG |
xor eax, eax |
out dx, al ;clear DTR & RTS |
mov eax, esi |
mov ebx, RATE_2400 |
mov ecx, LCR_8BIT+LCR_STOP_1 |
call uart_set_mode.internal |
mov edx, [esi+UART.base] |
add edx, IIR_REG |
mov eax, FCR_EFIFO+FCR_CRB+FCR_CXMIT+FCR_FIFO_14 |
out dx, al |
.clear_RB: |
mov edx, [esi+UART.base] |
add edx, LSR_REG |
in al, dx |
test eax, LSR_DR |
jz @F |
mov edx, [esi+UART.base] |
in al, dx |
jmp .clear_RB |
@@: |
mov edx, [esi+UART.base] |
add edx, IER_REG |
mov eax, IER_RDAI+IER_THRI+IER_LSI |
out dx, al |
.clear_IIR: |
mov edx, [esi+UART.base] |
add edx, IIR_REG |
in al, dx |
test al, IIR_INTR |
jnz .done |
shr eax, 1 |
and eax, 3 |
jnz @F |
mov edx, [esi+UART.base] |
add edx, MSR_REG |
in al, dx |
jmp .clear_IIR |
@@: |
cmp eax, 1 |
je .clear_IIR |
cmp eax, 2 |
jne @F |
mov edx, [esi+UART.base] |
in al, dx |
jmp .clear_IIR |
@@: |
mov edx, [esi+UART.base] |
add edx, LSR_REG |
in al, dx |
jmp .clear_IIR |
.done: |
mov edi, [esi+UART.rcvr_buff] |
mov ecx, 8192/4 |
xor eax, eax |
mov [esi+UART.rcvr_rp], edi |
mov [esi+UART.rcvr_wp], edi |
mov [esi+UART.rcvr_count], eax |
cld |
rep stosd |
mov edi, [esi+UART.xmit_buff] |
mov ecx, 8192/4 |
mov [esi+UART.xmit_rp], edi |
mov [esi+UART.xmit_wp], edi |
mov [esi+UART.xmit_count], eax |
mov [esi+UART.xmit_free], 8192 |
rep stosd |
ret ;eax= 0 |
.fail: |
or eax, -1 |
ret |
; param |
; esi= input buffer |
; +0 connection |
; +4 rate |
; +8 mode |
; |
; retval |
; eax= error code |
align 4 |
uart_set_mode: |
mov eax, [esi] |
cmp [eax+APPOBJ.magic], 'CNCT' |
jne .fail |
cmp [eax+APPOBJ.destroy], uart_close.destroy |
jne .fail |
mov eax, [eax+CONNECTION.uart] |
test eax, eax |
jz .fail |
mov ebx, [esi+4] |
mov ecx, [esi+8] |
; param |
; eax= uart |
; ebx= baud rate |
; ecx= mode |
align 4 |
.internal: |
cmp ebx, RATE_115200 |
ja .fail |
cmp ecx, LCR_BREAK |
jae .fail |
mov [eax+UART.rate], ebx |
mov [eax+UART.mode], ecx |
mov esi, eax |
mov bx, [divisor+ebx*2] |
mov edx, [esi+UART.base] |
push edx |
add edx, LCR_REG |
in al, dx |
or al, 0x80 |
out dx, al |
pop edx |
mov al, bl |
out dx, al |
inc dx |
mov al, bh |
out dx, al |
add edx, LCR_REG-1 |
mov eax, ecx |
out dx, al |
xor eax, eax |
ret |
.fail: |
or eax, -1 |
ret |
; param |
; esi= input buffer |
; +0 connection |
; +4 modem control reg valie |
; |
; retval |
; eax= error code |
align 4 |
uart_set_mcr: |
mov eax, [esi] |
cmp [eax+APPOBJ.magic], 'CNCT' |
jne .fail |
cmp [eax+APPOBJ.destroy], uart_close.destroy |
jne .fail |
mov eax, [eax+CONNECTION.uart] |
test eax, eax |
jz .fail |
mov ebx, [esi+4] |
mov [eax+UART.mcr_reg], ebx |
mov edx, [eax+UART.base] |
add edx, MCR_REG |
mov al, bl |
out dx, al |
xor eax, eax |
ret |
.fail: |
or eax, -1 |
ret |
; param |
; eax= port |
; |
; retval |
; ecx= connection |
; eax= error code |
align 4 |
uart_open: |
dec eax |
cmp eax, COM_MAX |
jae .fail |
mov esi, [com1+eax*4] ;uart |
push esi |
.do_wait: |
cmp dword [esi+UART.lock], 0 |
je .get_lock |
; call change_task |
jmp .do_wait |
.get_lock: |
mov eax, 1 |
xchg eax, [esi+UART.lock] |
test eax, eax |
jnz .do_wait |
mov eax, esi ;uart |
call uart_reset.internal |
mov ebx, [CURRENT_TASK] |
shl ebx, 5 |
mov ebx, [CURRENT_TASK+ebx+4] |
mov eax, CONNECTION_SIZE |
call CreateObject |
pop esi ;uart |
test eax, eax |
jz .fail |
mov [eax+APPOBJ.magic], 'CNCT' |
mov [eax+APPOBJ.destroy], uart_close.destroy |
mov [eax+CONNECTION.uart], esi |
mov ecx, eax |
xor eax, eax |
ret |
.fail: |
or eax, -1 |
ret |
restore .uart |
; param |
; esi= input buffer |
align 4 |
uart_close: |
mov eax, [esi] |
cmp [eax+APPOBJ.magic], 'CNCT' |
jne .fail |
cmp [eax+APPOBJ.destroy], uart_close.destroy |
jne .fail |
.destroy: |
push [eax+CONNECTION.uart] |
call DestroyObject ;eax= object |
pop eax ;eax= uart |
test eax, eax |
jz .fail |
mov [eax+UART.state], UART_CLOSED |
mov [eax+UART.lock], 0;release port |
xor eax, eax |
ret |
.fail: |
or eax, -1 |
ret |
; param |
; eax= uart |
; ebx= baud rate |
align 4 |
set_rate: |
cmp ebx, RATE_115200 |
ja .fail |
mov [eax+UART.rate], ebx |
mov bx, [divisor+ebx*2] |
mov edx, [eax+UART.base] |
add edx, LCR_REG |
in al, dx |
push eax |
or al, 0x80 |
out dx, al |
sub edx, LCR_REG |
mov al, bl |
out dx, al |
inc edx |
mov al, bh |
out dx, al |
pop eax |
add edx, LCR_REG-1 |
out dx, al |
.fail: |
ret |
; param |
; ebx= uart |
align 4 |
transmit: |
push esi |
push edi |
mov edx, [ebx+UART.base] |
pushfd |
cli |
mov esi, [ebx+UART.xmit_rp] |
mov ecx, [ebx+UART.xmit_count] |
test ecx, ecx |
je .stop |
cmp ecx, 16 |
jbe @F |
mov ecx, 16 |
@@: |
sub [ebx+UART.xmit_count], ecx |
add [ebx+UART.xmit_free], ecx |
cld |
@@: |
lodsb |
out dx, al |
dec ecx |
jnz @B |
cmp esi, [ebx+UART.xmit_top] |
jb @F |
sub esi, 8192 |
@@: |
mov [ebx+UART.xmit_rp], esi |
cmp [ebx+UART.xmit_count], 0 |
je .stop |
mov [ebx+UART.state], UART_TRANSMIT |
jmp @F |
.stop: |
mov [ebx+UART.state], UART_STOP |
@@: |
popfd |
pop edi |
pop esi |
ret |
; param |
; esi= input buffer |
; +0 connection |
; +4 dst buffer |
; +8 dst size |
; edi= output buffer |
; +0 bytes read |
; retval |
; eax= error code |
align 4 |
uart_read: |
mov eax, [esi] |
cmp [eax+APPOBJ.magic], 'CNCT' |
jne .fail |
cmp [eax+APPOBJ.destroy], uart_close.destroy |
jne .fail |
mov eax, [eax+CONNECTION.uart] |
test eax, eax |
jz .fail |
mov ebx, [esi+8] ;dst size |
mov ecx, [eax+UART.rcvr_count] |
cmp ecx, ebx |
jbe @F |
mov ecx, ebx |
@@: |
mov [edi], ecx ;bytes read |
test ecx, ecx |
jz .done |
push ecx |
mov edi, [esi+4] ;dst |
mov esi, [eax+UART.rcvr_rp] |
cld |
rep movsb |
pop ecx |
cmp esi, [eax+UART.rcvr_top] |
jb @F |
sub esi, 8192 |
@@: |
mov [eax+UART.rcvr_rp], esi |
sub [eax+UART.rcvr_count], ecx |
.done: |
xor eax, eax |
ret |
.fail: |
or eax, -1 |
ret |
; param |
; esi= input buffer |
; +0 connection |
; +4 src buffer |
; +8 src size |
; |
; retval |
; eax= error code |
align 4 |
uart_write: |
mov eax, [esi] |
cmp [eax+APPOBJ.magic], 'CNCT' |
jne .fail |
cmp [eax+APPOBJ.destroy], uart_close.destroy |
jne .fail |
mov eax, [eax+CONNECTION.uart] |
test eax, eax |
jz .fail |
mov ebx, [esi+4] |
mov edx, [esi+8] |
; param |
; eax= uart |
; ebx= src |
; edx= count |
align 4 |
.internal: |
mov esi, ebx |
mov edi, [eax+UART.xmit_wp] |
.write: |
test edx, edx |
jz .fail |
.wait: |
cmp [eax+UART.xmit_free], 0 |
jne .fill |
cmp [eax+UART.state], UART_TRANSMIT |
je .wait |
mov ebx, eax |
push edx |
call transmit |
pop edx |
mov eax, ebx |
jmp .write |
.fill: |
mov ecx, [eax+UART.xmit_free] |
cmp ecx, edx |
jbe @F |
mov ecx, edx |
@@: |
push ecx |
cld |
rep movsb |
pop ecx |
sub [eax+UART.xmit_free], ecx |
add [eax+UART.xmit_count], ecx |
sub edx, ecx |
jnz .wait |
.done: |
cmp edi, [eax+UART.xmit_top] |
jb @F |
sub edi, 8192 |
@@: |
mov [eax+UART.xmit_wp], edi |
cmp [eax+UART.state], UART_TRANSMIT |
je @F |
mov ebx, eax |
call transmit |
@@: |
xor eax, eax |
ret |
.fail: |
or eax, -1 |
ret |
align 4 |
com_2_isr: |
mov ebx, [com2] |
jmp com_1_isr.get_info |
align 4 |
com_1_isr: |
mov ebx, [com1] |
.get_info: |
mov edx, [ebx+UART.base] |
add edx, IIR_REG |
in al, dx |
test al, IIR_INTR |
jnz .done |
shr eax, 1 |
and eax, 3 |
call [isr_action+eax*4] |
jmp .get_info |
.done: |
ret |
align 4 |
isr_line: |
mov edx, [ebx+UART.base] |
add edx, LSR_REG |
in al, dx |
ret |
align 4 |
isr_recieve: |
mov esi, [ebx+UART.base] |
add esi, LSR_REG |
mov edi, [ebx+UART.rcvr_wp] |
xor ecx, ecx |
cld |
.read: |
mov edx, esi |
in al, dx |
test eax, LSR_DR |
jz .done |
mov edx, [ebx+UART.base] |
in al, dx |
stosb |
inc ecx |
jmp .read |
.done: |
cmp edi, [ebx+UART.rcvr_top] |
jb @F |
sub edi, 8192 |
@@: |
mov [ebx+UART.rcvr_wp], edi |
add [ebx+UART.rcvr_count], ecx |
ret |
align 4 |
isr_modem: |
mov edx, [ebx+UART.base] |
add edx, MSR_REG |
in al, dx |
ret |
align 4 |
divisor dw 2304, 1536, 1047, 857, 768, 384 |
dw 192, 96, 64, 58, 48, 32 |
dw 24, 16, 12, 6, 3, 2, 1 |
align 4 |
uart_func dd 0 ;SRV_GETVERSION |
dd 0 ;PORT_OPEN |
dd uart_close ;PORT_CLOSE |
dd uart_reset ;PORT_RESET |
dd uart_set_mode ;PORT_SETMODE |
dd 0 ;PORT_GETMODE |
dd uart_set_mcr ;PORT_SETMODEM |
dd 0 ;PORT_GETMODEM |
dd uart_read ;PORT_READ |
dd uart_write ;PORT_WRITE |
isr_action dd isr_modem |
dd transmit |
dd isr_recieve |
dd isr_line |
version dd (5 shl 16) or (UART_VERSION and 0xFFFF) |
sz_uart_srv db 'UART',0 |
align 4 |
com1 rd 1 |
com2 rd 1 |
/kernel/branches/Kolibri-acpi/drivers |
---|
Property changes: |
Added: svn:ignore |
+*.mnt |
+lang.inc |
+*.bat |
+out.txt |
+scin* |
+*.obj |