;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;                                                              ;;
;; Copyright (C) KolibriOS team 2004-2008. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License    ;;
;;                                                              ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

$Revision:1322 $


uglobal
cd_current_pointer_of_input    dd  0
cd_current_pointer_of_input_2  dd  0
cd_mem_location 	       dd  0
cd_counter_block	       dd  0
IDE_Channel_1		       db  0
IDE_Channel_2		       db  0
endg

reserve_cd:

    cli
    cmp   [cd_status],0
    je	  reserve_ok2

    sti
    call  change_task
    jmp   reserve_cd

  reserve_ok2:

    push  eax
    mov   eax,[CURRENT_TASK]
    shl   eax,5
    mov   eax,[eax+CURRENT_TASK+TASKDATA.pid]
    mov   [cd_status],eax
    pop   eax
    sti
    ret

reserve_cd_channel:
    cmp   [ChannelNumber],1
    jne   .IDE_Channel_2
.IDE_Channel_1:
    cli
    cmp   [IDE_Channel_1],0
    je	  .reserve_ok_1
    sti
    call  change_task
    jmp   .IDE_Channel_1
.IDE_Channel_2:
    cli
    cmp   [IDE_Channel_2],0
    je	  .reserve_ok_2
    sti
    call  change_task
    jmp   .IDE_Channel_1
.reserve_ok_1:
    mov [IDE_Channel_1],1
    ret
.reserve_ok_2:
    mov [IDE_Channel_2],1
    ret

free_cd_channel:
    cmp   [ChannelNumber],1
    jne   .IDE_Channel_2
.IDE_Channel_1:
    mov [IDE_Channel_1],0
    ret
.IDE_Channel_2:
    mov [IDE_Channel_2],0
    ret

uglobal
cd_status dd 0
endg

;----------------------------------------------------------------
;
;  fs_CdRead - LFN variant for reading CD disk
;
;  esi  points to filename /dir1/dir2/.../dirn/file,0
;  ebx  pointer to 64-bit number = first wanted byte, 0+
;       may be ebx=0 - start from first byte
;  ecx  number of bytes to read, 0+
;  edx  mem location to return data
;
;  ret ebx = bytes read or 0xffffffff file not found
;      eax = 0 ok read or other = errormsg
;
;--------------------------------------------------------------
fs_CdRead:
    push    edi
    cmp    byte [esi], 0
    jnz    @f
.noaccess:
    pop    edi
.noaccess_2:
    or	  ebx, -1
    mov    eax, ERROR_ACCESS_DENIED
    ret

.noaccess_3:
    pop     eax edx ecx edi
    jmp  .noaccess_2

@@:
    call    cd_find_lfn
    jnc    .found
    pop    edi
    cmp   [DevErrorCode],0
    jne   .noaccess_2
    or	  ebx, -1
    mov    eax, ERROR_FILE_NOT_FOUND
    ret

.found:
    mov    edi,[cd_current_pointer_of_input]
    test   byte [edi+25],10b	; do not allow read directories
    jnz    .noaccess
    test    ebx, ebx
    jz	  .l1
    cmp    dword [ebx+4], 0
    jz	  @f
	xor	ebx, ebx
.reteof:
    mov    eax, 6 ; end of file
    pop    edi
    ret
@@:
    mov    ebx, [ebx]
.l1:
	push	ecx edx
	push	0
	mov	eax, [edi+10] ; �������� ������ �������� ������
	sub	eax, ebx
	jb	.eof
	cmp	eax, ecx
	jae	@f
	mov	ecx, eax
	mov	byte [esp], 6
@@:
     mov    eax,[edi+2]
     mov    [CDSectorAddress],eax
; now eax=cluster, ebx=position, ecx=count, edx=buffer for data
.new_sector:
    test    ecx, ecx
    jz	  .done
    sub    ebx, 2048
    jae    .next
    add    ebx, 2048
    jnz    .incomplete_sector
    cmp    ecx, 2048
    jb	  .incomplete_sector
; we may read and memmove complete sector
    mov  [CDDataBuf_pointer],edx
    call ReadCDWRetr	  ; ������ ������ �����
    cmp   [DevErrorCode],0
    jne   .noaccess_3
    add    edx, 2048
    sub    ecx, 2048
.next:
    inc  dword [CDSectorAddress]
    jmp    .new_sector
.incomplete_sector:
; we must read and memmove incomplete sector
    mov  [CDDataBuf_pointer],CDDataBuf
    call ReadCDWRetr	  ; ������ ������ �����
    cmp   [DevErrorCode],0
    jne   .noaccess_3
    push    ecx
    add    ecx, ebx
    cmp    ecx, 2048
    jbe    @f
    mov    ecx, 2048
@@:
    sub    ecx, ebx
     push edi esi ecx
     mov edi,edx
	lea	esi, [CDDataBuf + ebx]
     cld
     rep movsb
     pop ecx esi edi
    add    edx, ecx
    sub    [esp], ecx
    pop    ecx
    xor    ebx, ebx
    jmp    .next

.done:
	mov	ebx, edx
	pop	eax edx ecx edi
	sub	ebx, edx
	ret
.eof:
	mov	ebx, edx
	pop	eax edx ecx
	sub	ebx, edx
	jmp	.reteof

;----------------------------------------------------------------
;
;  fs_CdReadFolder - LFN variant for reading CD disk folder
;
;  esi  points to filename  /dir1/dir2/.../dirn/file,0
;  ebx  pointer to structure 32-bit number = first wanted block, 0+
;                          & flags (bitfields)
; flags: bit 0: 0=ANSI names, 1=UNICODE names
;  ecx  number of blocks to read, 0+
;  edx  mem location to return data
;
;  ret ebx = blocks read or 0xffffffff folder not found
;      eax = 0 ok read or other = errormsg
;
;--------------------------------------------------------------
fs_CdReadFolder:
	push	edi
	call	cd_find_lfn
	jnc	.found
	pop	edi
	cmp	[DevErrorCode], 0
	jne	.noaccess_1
	or	ebx, -1
	mov	eax, ERROR_FILE_NOT_FOUND
	ret
.found:
	mov	edi, [cd_current_pointer_of_input]
	test	byte [edi+25], 10b    ; do not allow read directories
	jnz	.found_dir
	pop	edi
.noaccess_1:
	or	ebx, -1
	mov	eax, ERROR_ACCESS_DENIED
	ret
.found_dir:
	mov	eax, [edi+2]	; eax=cluster
	mov	[CDSectorAddress], eax
	mov	eax, [edi+10]	; ������ �����������
.doit:
; init header
	push	eax ecx
	mov	edi, edx
	mov	ecx, 32/4
	xor	eax, eax
	rep	stosd
	pop	ecx eax
	mov	byte [edx], 1	; version
	mov	[cd_mem_location], edx
	add	[cd_mem_location], 32
; �������� ���������� ���� � ����
;.mainloop:
	mov	[cd_counter_block], dword 0
	dec	dword [CDSectorAddress]
	push	ecx
.read_to_buffer:
	inc	dword [CDSectorAddress]
	mov	[CDDataBuf_pointer], CDDataBuf
	call	ReadCDWRetr	    ; ������ ������ ����������
	cmp	[DevErrorCode], 0
	jne	.noaccess_1
	call	.get_names_from_buffer
	sub	eax,2048
; ���������� �����������?
	ja	.read_to_buffer
	mov	edi, [cd_counter_block]
	mov	[edx+8], edi
	mov	edi, [ebx]
	sub	[edx+4], edi
	xor	eax, eax
	dec	ecx
	js	@f
	mov	al, ERROR_END_OF_FILE
@@:
	pop	ecx edi
	mov	ebx, [edx+4]
	ret

.get_names_from_buffer:
    mov     [cd_current_pointer_of_input_2],CDDataBuf
    push    eax esi edi edx
.get_names_from_buffer_1:
    call    cd_get_name
    jc	  .end_buffer
    inc    dword [cd_counter_block]
    mov    eax,[cd_counter_block]
    cmp    [ebx],eax
    jae     .get_names_from_buffer_1
    test    ecx, ecx
    jz	  .get_names_from_buffer_1
    mov   edi,[cd_counter_block]
    mov   [edx+4],edi
    dec     ecx
    mov   esi,ebp
    mov   edi,[cd_mem_location]
    add   edi,40
    test   dword [ebx+4], 1 ; 0=ANSI, 1=UNICODE
    jnz    .unicode
;    jmp  .unicode
.ansi:
    cmp   [cd_counter_block],2
    jbe   .ansi_parent_directory
    cld
    lodsw
    xchg ah,al
    call uni2ansi_char
    cld
    stosb
; �������� ����� �����
    mov   ax,[esi]
    cmp   ax,word 3B00h ; ��������� ����� ����� ';'
    je	 .cd_get_parameters_of_file_1
; �������� ��� ������ �� ��������������� �����������
    movzx   eax,byte [ebp-33]
    add   eax,ebp
    sub   eax,34
    cmp   esi,eax
    je	 .cd_get_parameters_of_file_1
; �������� ����� �����
    movzx   eax,byte [ebp-1]
    add   eax,ebp
    cmp   esi,eax
    jb	 .ansi
.cd_get_parameters_of_file_1:
    mov   [edi],byte 0
    call  cd_get_parameters_of_file
    add   [cd_mem_location],304
    jmp   .get_names_from_buffer_1

.ansi_parent_directory:
    cmp   [cd_counter_block],2
    je	  @f
    mov   [edi],byte '.'
    inc   edi
    jmp  .cd_get_parameters_of_file_1
@@:
    mov   [edi],word '..'
    add   edi,2
    jmp  .cd_get_parameters_of_file_1

.unicode:
    cmp   [cd_counter_block],2
    jbe   .unicode_parent_directory
    cld
    movsw
; �������� ����� �����
    mov   ax,[esi]
    cmp   ax,word 3B00h ; ��������� ����� ����� ';'
    je	 .cd_get_parameters_of_file_2
; �������� ��� ������ �� ��������������� �����������
    movzx   eax,byte [ebp-33]
    add   eax,ebp
    sub   eax,34
    cmp   esi,eax
    je	 .cd_get_parameters_of_file_2
; �������� ����� �����
    movzx   eax,byte [ebp-1]
    add   eax,ebp
    cmp   esi,eax
    jb	 .unicode
.cd_get_parameters_of_file_2:
    mov   [edi],word 0
    call  cd_get_parameters_of_file
    add   [cd_mem_location],560
    jmp   .get_names_from_buffer_1

.unicode_parent_directory:
    cmp   [cd_counter_block],2
    je	  @f
    mov   [edi],word 2E00h ; '.'
    add   edi,2
    jmp   .cd_get_parameters_of_file_2
@@:
    mov   [edi],dword 2E002E00h ; '..'
    add   edi,4
    jmp   .cd_get_parameters_of_file_2

.end_buffer:
    pop   edx edi esi eax
    ret

cd_get_parameters_of_file:
    mov   edi,[cd_mem_location]
cd_get_parameters_of_file_1:
; �������� �������� �����
    xor   eax,eax
; ���� �� �������������
    inc   eax
    shl   eax,1
; ��� �������?
    test  [ebp-8],byte 2
    jz	  .file
    inc   eax
.file:
; ����� ���� �� ��� � FAT, � ���� ���� ����������
; ���� �� �������� ���������
    shl   eax,3
; ���� �������� �������? (������� �������������)
    test  [ebp-8],byte 1
    jz	  .hidden
    inc   eax
.hidden:
    shl   eax,1
; ���� ������ ������ ��� ������, ��� ��� ��� CD
    inc   eax
    mov   [edi],eax
; �������� ����� ��� �����
;���
    movzx eax,byte [ebp-12]
    shl   eax,8
;������
    mov   al,[ebp-11]
    shl   eax,8
;�������
    mov   al,[ebp-10]
;����� �������� �����
    mov   [edi+8],eax
;����� ���������� �������
    mov   [edi+16],eax
;����� ��������� ������
    mov   [edi+24],eax
; �������� ���� ��� �����
;���
    movzx eax,byte [ebp-15]
    add   eax,1900
    shl   eax,8
;�����
    mov   al,[ebp-14]
    shl   eax,8
;����
    mov   al,[ebp-13]
;���� �������� �����
    mov   [edi+12],eax
;����� ���������� �������
    mov   [edi+20],eax
;����� ��������� ������
    mov   [edi+28],eax
; �������� ��� ������ �����
    xor   eax,eax
    test   dword [ebx+4], 1 ; 0=ANSI, 1=UNICODE
    jnz    .unicode_1
    mov    [edi+4],eax
    jmp   @f
.unicode_1:
    inc    eax
    mov    [edi+4],eax
@@:
; �������� ������ ����� � ������
    xor   eax,eax
    mov   [edi+32+4],eax
    mov   eax,[ebp-23]
    mov   [edi+32],eax
    ret

;----------------------------------------------------------------
;
;  fs_CdGetFileInfo - LFN variant for CD
;                     get file/directory attributes structure
;
;----------------------------------------------------------------
fs_CdGetFileInfo:
	cmp	byte [esi], 0
	jnz	@f
	mov	eax, 2
	ret
@@:
	push	edi
	call	cd_find_lfn
	pushfd
	cmp	[DevErrorCode], 0
	jz	@f
	popfd
	pop	edi
	mov	eax, 11
	ret
@@:
	popfd
	jnc	@f
	pop	edi
	mov	eax, ERROR_FILE_NOT_FOUND
	ret
@@:

	mov	edi, edx
	push	ebp
	mov	ebp, [cd_current_pointer_of_input]
	add	ebp, 33
	call	cd_get_parameters_of_file_1
	pop	ebp
	and	dword [edi+4], 0
	pop	edi
	xor	eax, eax
	ret

;----------------------------------------------------------------
cd_find_lfn:
  mov	[cd_appl_data],0
; in: esi+ebp -> name
; out: CF=1 - file not found
; else CF=0 and [cd_current_pointer_of_input] direntry
	push eax esi
; 16 ������ ������ ������ ������������ �����

  call	WaitUnitReady
  cmp	[DevErrorCode],0
  jne	.access_denied

  call	prevent_medium_removal
; �������� ������
  mov  [CDSectorAddress],dword 16
  mov  [CDDataBuf_pointer],CDDataBuf
  call	ReadCDWRetr    ;_1
   cmp	 [DevErrorCode],0
  jne	.access_denied

; ���������� ��������� ������
  call WaitUnitReady
  cmp	[DevErrorCode],0
  jne	.access_denied
  call Read_TOC
  mov  ah,[CDDataBuf+4+4]
  mov  al,[CDDataBuf+4+5]
  shl  eax,16
  mov  ah,[CDDataBuf+4+6]
  mov  al,[CDDataBuf+4+7]
  add  eax,15
  mov  [CDSectorAddress],eax
;  mov  [CDSectorAddress],dword 15
  mov  [CDDataBuf_pointer],CDDataBuf

.start:
	inc  dword [CDSectorAddress]
  call	ReadCDWRetr    ;_1
   cmp	 [DevErrorCode],0
  jne	.access_denied

.start_check:
; �������� �� ��������
	cmp  [CDDataBuf+1],dword 'CD00'
	jne  .access_denied
	cmp  [CDDataBuf+5],byte '1'
	jne  .access_denied
; ������ �������� ������������ ����� ������������ �����?
	cmp  [CDDataBuf],byte 0xff
	je  .access_denied
; ������ �������� �������������� � ���������� ������������ ����?
	cmp  [CDDataBuf],byte 0x2
	jne  .start
; ������ �������� �������������� ������������ ����?
	cmp  [CDDataBuf+6],byte 0x1
	jne  .start

; ��������� root �����������
	mov  eax,[CDDataBuf+0x9c+2] ; ������ root �����������
	mov  [CDSectorAddress],eax
	mov  eax,[CDDataBuf+0x9c+10] ; ������ root �����������
	cmp    byte [esi], 0
	jnz    @f
	mov   [cd_current_pointer_of_input],CDDataBuf+0x9c
	jmp   .done
@@:
; �������� �����
.mainloop:
	dec  dword [CDSectorAddress]
.read_to_buffer:
	inc  dword [CDSectorAddress]
	mov  [CDDataBuf_pointer],CDDataBuf
	call ReadCDWRetr	 ; ������ ������ ����������
	cmp   [DevErrorCode],0
	jne   .access_denied
	push	ebp
	call	cd_find_name_in_buffer
	pop	ebp
	jnc	.found
	sub  eax,2048
; ���������� �����������?
	cmp  eax,0
	ja   .read_to_buffer
; ��� �������� �������� �������
.access_denied:
	pop  esi eax
	mov   [cd_appl_data],1
	stc
	ret
; ������� ������� ������� ������
  .found:
; ����� ���� �����
	cmp    byte [esi-1], 0
	jz    .done
  .nested:
	mov    eax,[cd_current_pointer_of_input]
	push	dword [eax+2]
	pop	dword [CDSectorAddress]       ; ������ ����������
	mov    eax,[eax+2+8]  ; ������ ����������
	jmp    .mainloop
; ��������� ����� ������
   .done:
	test	ebp, ebp
	jz	@f
	mov	esi, ebp
	xor	ebp, ebp
	jmp	.nested
@@:
	pop  esi eax
	mov   [cd_appl_data],1
	clc
	ret

cd_find_name_in_buffer:
	mov	[cd_current_pointer_of_input_2],CDDataBuf
.start:
	call	cd_get_name
	jc	.not_found
	call	cd_compare_name
	jc	.start
.found:
	clc
	ret
.not_found:
	stc
	ret

cd_get_name:
	push eax
	mov   ebp,[cd_current_pointer_of_input_2]
	mov   [cd_current_pointer_of_input],ebp
	mov   eax,[ebp]
	test   eax,eax   ; ����� �����������?
	jz    .next_sector
	cmp   ebp,CDDataBuf+2048     ; ����� ����������?
	jae   .next_sector
	movzx eax, byte [ebp]
	add   [cd_current_pointer_of_input_2],eax ; ��������� ���� ��������
	add   ebp,33 ; ��������� ���������� �� ������ �����
	pop   eax
	clc
	ret
.next_sector:
	pop  eax
	stc
	ret

cd_compare_name:
; compares ASCIIZ-names, case-insensitive (cp866 encoding)
; in: esi->name, ebp->name
; out: if names match: ZF=1 and esi->next component of name
;      else: ZF=0, esi is not changed
; destroys eax
    push    esi eax edi
    mov     edi,ebp
.loop:
    cld
    lodsb
    push eax
    call char_todown
    call ansi2uni_char
    xchg ah,al
    scasw
    pop  eax
    je	  .coincides
    call char_toupper
    call ansi2uni_char
    xchg ah,al
    sub  edi,2
    scasw
    jne   .name_not_coincide
.coincides:
    cmp   [esi],byte '/'  ; ����������� ����, ����� ����� �������� ��������
    je	 .done
    cmp   [esi],byte 0	; ����������� ����, ����� ����� �������� ��������
    je	 .done
    jmp   .loop
.name_not_coincide:
    pop    edi eax esi
    stc
    ret
.done:
; �������� ����� �����
    cmp   [edi],word 3B00h ; ��������� ����� ����� ';'
    je	 .done_1
; �������� ��� ������ �� ��������������� �����������
    movzx   eax,byte [ebp-33]
    add   eax,ebp
    sub   eax,34
    cmp   edi,eax
    je	 .done_1
; �������� ����� �����
    movzx   eax,byte [ebp-1]
    add   eax,ebp
    cmp   edi,eax
    jne   .name_not_coincide
.done_1:
    pop   edi eax
    add   esp,4
    inc   esi
    clc
    ret

char_todown:
; convert character to uppercase, using cp866 encoding
; in: al=symbol
; out: al=converted symbol
	cmp	al, 'A'
	jb	.ret
	cmp	al, 'Z'
	jbe	.az
	cmp	al, '�'
	jb	.ret
	cmp	al, '�'
	jb	.rus1
	cmp	al, '�'
	ja	.ret
; 0x90-0x9F -> 0xE0-0xEF
	add	al, '�'-'�'
.ret:
	ret
.rus1:
; 0x80-0x8F -> 0xA0-0xAF
.az:
	add	al, 0x20
	ret

uni2ansi_char:
; convert UNICODE character in al to ANSI character in ax, using cp866 encoding
; in: ax=UNICODE character
; out: al=converted ANSI character
	cmp	ax, 0x80
	jb	.ascii
	cmp	ax, 0x401
	jz	.yo1
	cmp	ax, 0x451
	jz	.yo2
	cmp	ax, 0x410
	jb	.unk
	cmp	ax, 0x440
	jb	.rus1
	cmp	ax, 0x450
	jb	.rus2
.unk:
	mov	al, '_'
	jmp	.doit
.yo1:
	mov	al, '�'
	jmp	.doit
.yo2:
	mov	al, '�'
	jmp	.doit
.rus1:
; 0x410-0x43F -> 0x80-0xAF
	add	al, 0x70
	jmp	.doit
.rus2:
; 0x440-0x44F -> 0xE0-0xEF
	add	al, 0xA0
.ascii:
.doit:
	ret