From edbca7f724d81dc9faff5eb327433ad021e22a70 Mon Sep 17 00:00:00 2001 From: "Sergey Semyonov (Serge)" Date: Sun, 24 Nov 2013 07:02:55 +0000 Subject: [PATCH] kolibri-acpi:update git-svn-id: svn://kolibrios.org@4287 a494cfbc-eb01-0410-851d-a64ba20cac60 --- kernel/branches/Kolibri-acpi/blkdev/disk.inc | 58 +- kernel/branches/Kolibri-acpi/blkdev/fdc.inc | 38 +- .../branches/Kolibri-acpi/blkdev/flp_drv.inc | 357 ++- .../branches/Kolibri-acpi/blkdev/hd_drv.inc | 12 +- kernel/branches/Kolibri-acpi/blkdev/rd.inc | 2433 ++--------------- .../branches/Kolibri-acpi/blkdev/rdsave.inc | 9 +- .../branches/Kolibri-acpi/boot/boot_fat12.asm | 302 -- kernel/branches/Kolibri-acpi/boot/booteng.inc | 101 - kernel/branches/Kolibri-acpi/core/sys32.inc | 4 - kernel/branches/Kolibri-acpi/core/syscall.inc | 36 +- kernel/branches/Kolibri-acpi/data32.inc | 15 +- kernel/branches/Kolibri-acpi/data32et.inc | 1 + kernel/branches/Kolibri-acpi/data32sp.inc | 1 + .../branches/Kolibri-acpi/detect/dev_fd.inc | 1 + .../branches/Kolibri-acpi/detect/vortex86.inc | 17 +- kernel/branches/Kolibri-acpi/drivers/agp.asm | 310 +++ kernel/branches/Kolibri-acpi/drivers/apm.asm | 350 +++ kernel/branches/Kolibri-acpi/drivers/fdo.inc | 453 +++ .../branches/Kolibri-acpi/drivers/usb/urb.inc | 121 - .../branches/Kolibri-acpi/drivers/usb/usb.asm | 435 --- .../branches/Kolibri-acpi/drivers/usbhid.asm | 693 ----- .../Kolibri-acpi/drivers/usbhid/keyboard.inc | 475 ++++ .../Kolibri-acpi/drivers/usbhid/mouse.inc | 155 ++ .../Kolibri-acpi/drivers/usbhid/report.inc | 1442 ++++++++++ .../Kolibri-acpi/drivers/usbhid/sort.inc | 60 + .../Kolibri-acpi/drivers/usbhid/unclaimed.inc | 60 + .../Kolibri-acpi/drivers/usbhid/usbhid.asm | 553 ++++ .../branches/Kolibri-acpi/drivers/vidrdc.asm | 438 +++ .../Kolibri-acpi/fs/{fat32.inc => fat.inc} | 1124 +++++++- kernel/branches/Kolibri-acpi/fs/fat12.inc | 2268 --------------- kernel/branches/Kolibri-acpi/fs/fs-et.inc | 12 - kernel/branches/Kolibri-acpi/fs/fs-sp.inc | 13 - kernel/branches/Kolibri-acpi/fs/fs.inc | 682 ----- kernel/branches/Kolibri-acpi/fs/fs_lfn.inc | 225 +- kernel/branches/Kolibri-acpi/fs/part_set.inc | 436 --- kernel/branches/Kolibri-acpi/gui/char2_et.mt | Bin 0 -> 2560 bytes kernel/branches/Kolibri-acpi/gui/char_et.mt | Bin 0 -> 2304 bytes kernel/branches/Kolibri-acpi/gui/window.inc | 10 +- kernel/branches/Kolibri-acpi/kernel.asm | 70 +- kernel/branches/Kolibri-acpi/kernel32.inc | 6 +- kernel/branches/Kolibri-acpi/memmap.inc | 3 +- .../Kolibri-acpi/readme-ext-loader.txt | 52 + kernel/branches/Kolibri-acpi/skin/base.bmp | Bin 584 -> 0 bytes kernel/branches/Kolibri-acpi/skin/base_1.bmp | Bin 584 -> 0 bytes kernel/branches/Kolibri-acpi/skin/default.asm | 38 - kernel/branches/Kolibri-acpi/skin/left.bmp | Bin 670 -> 0 bytes kernel/branches/Kolibri-acpi/skin/left_1.bmp | Bin 670 -> 0 bytes kernel/branches/Kolibri-acpi/skin/me_skin.inc | 242 -- kernel/branches/Kolibri-acpi/skin/myblue.dtp | Bin 40 -> 0 bytes kernel/branches/Kolibri-acpi/skin/oper.bmp | Bin 2694 -> 0 bytes kernel/branches/Kolibri-acpi/skin/oper_1.bmp | Bin 2694 -> 0 bytes 51 files changed, 6086 insertions(+), 8025 deletions(-) delete mode 100644 kernel/branches/Kolibri-acpi/boot/boot_fat12.asm delete mode 100644 kernel/branches/Kolibri-acpi/boot/booteng.inc create mode 100644 kernel/branches/Kolibri-acpi/drivers/agp.asm create mode 100644 kernel/branches/Kolibri-acpi/drivers/apm.asm create mode 100644 kernel/branches/Kolibri-acpi/drivers/fdo.inc delete mode 100644 kernel/branches/Kolibri-acpi/drivers/usb/urb.inc delete mode 100644 kernel/branches/Kolibri-acpi/drivers/usb/usb.asm delete mode 100644 kernel/branches/Kolibri-acpi/drivers/usbhid.asm create mode 100644 kernel/branches/Kolibri-acpi/drivers/usbhid/keyboard.inc create mode 100644 kernel/branches/Kolibri-acpi/drivers/usbhid/mouse.inc create mode 100644 kernel/branches/Kolibri-acpi/drivers/usbhid/report.inc create mode 100644 kernel/branches/Kolibri-acpi/drivers/usbhid/sort.inc create mode 100644 kernel/branches/Kolibri-acpi/drivers/usbhid/unclaimed.inc create mode 100644 kernel/branches/Kolibri-acpi/drivers/usbhid/usbhid.asm create mode 100644 kernel/branches/Kolibri-acpi/drivers/vidrdc.asm rename kernel/branches/Kolibri-acpi/fs/{fat32.inc => fat.inc} (70%) delete mode 100644 kernel/branches/Kolibri-acpi/fs/fat12.inc delete mode 100644 kernel/branches/Kolibri-acpi/fs/fs-et.inc delete mode 100644 kernel/branches/Kolibri-acpi/fs/fs-sp.inc delete mode 100644 kernel/branches/Kolibri-acpi/fs/fs.inc delete mode 100644 kernel/branches/Kolibri-acpi/fs/part_set.inc create mode 100644 kernel/branches/Kolibri-acpi/gui/char2_et.mt create mode 100644 kernel/branches/Kolibri-acpi/gui/char_et.mt create mode 100644 kernel/branches/Kolibri-acpi/readme-ext-loader.txt delete mode 100644 kernel/branches/Kolibri-acpi/skin/base.bmp delete mode 100644 kernel/branches/Kolibri-acpi/skin/base_1.bmp delete mode 100644 kernel/branches/Kolibri-acpi/skin/default.asm delete mode 100644 kernel/branches/Kolibri-acpi/skin/left.bmp delete mode 100644 kernel/branches/Kolibri-acpi/skin/left_1.bmp delete mode 100644 kernel/branches/Kolibri-acpi/skin/me_skin.inc delete mode 100644 kernel/branches/Kolibri-acpi/skin/myblue.dtp delete mode 100644 kernel/branches/Kolibri-acpi/skin/oper.bmp delete mode 100644 kernel/branches/Kolibri-acpi/skin/oper_1.bmp diff --git a/kernel/branches/Kolibri-acpi/blkdev/disk.inc b/kernel/branches/Kolibri-acpi/blkdev/disk.inc index 8e5832c2ed..64379e9195 100644 --- a/kernel/branches/Kolibri-acpi/blkdev/disk.inc +++ b/kernel/branches/Kolibri-acpi/blkdev/disk.inc @@ -1213,7 +1213,39 @@ fs_dyndisk_next_nomedia: ; ecx = partition number, esi+ebp = ASCIIZ name fs_dyndisk: dec ecx ; convert to zero-based partition index - pop edx edx edx eax ; edx = pointer to DISK, eax = NULL or edx + pop edx edx edx ; edx = pointer to DISK, dword [esp] = NULL or edx +; If the driver does not support insert notifications and we are the only fs +; operation with this disk, ask the driver whether the media +; was inserted/removed/changed. Otherwise, assume that media status is valid. + test byte [edx+DISK.DriverFlags], DISK_NO_INSERT_NOTIFICATION + jz .media_accurate + push ecx esi + mov esi, edx + cmp dword [esp+8], 0 + jz .test_no_media + cmp [esi+DISK.MediaRefCount], 2 + jnz .media_accurate_pop + lea edx, [esi+DISK.MediaInfo] + and [edx+DISKMEDIAINFO.Flags], 0 + mov al, DISKFUNC.querymedia + stdcall disk_call_driver, edx + test eax, eax + jz .media_accurate_pop + stdcall disk_media_dereference ; drop our reference so that disk_media_changed could close the media + stdcall disk_media_changed, esi, 0 + and dword [esp+8], 0 ; no media +.test_no_media: + stdcall disk_media_changed, esi, 1 ; issue fake notification + ; if querymedia() inside disk_media_changed returns error, the notification is ignored + cmp [esi+DISK.MediaInserted], 0 + jz .media_accurate_pop + lock inc [esi+DISK.MediaRefCount] + mov dword [esp+8], esi +.media_accurate_pop: + mov edx, esi + pop esi ecx +.media_accurate: + pop eax test eax, eax jz .nomedia .main: @@ -1252,30 +1284,6 @@ fs_dyndisk: .nomedia: test ecx, ecx jnz .notfound - test byte [edx+DISK.DriverFlags], DISK_NO_INSERT_NOTIFICATION - jz .deverror -; if the driver does not support insert notifications and we are the only fs -; operation with this disk, issue the fake insert notification; if media is -; still not inserted, 'disk_media_changed' will detect this and do nothing - lea ecx, [edx+DISK.MediaLock] - call mutex_lock - cmp [edx+DISK.MediaRefCount], 1 - jnz .noluck - call mutex_unlock - push edx - stdcall disk_media_changed, edx, 1 - pop edx - lea ecx, [edx+DISK.MediaLock] - call mutex_lock - cmp [edx+DISK.MediaInserted], 0 - jz .noluck - lock inc [edx+DISK.MediaRefCount] - call mutex_unlock - xor ecx, ecx - jmp .main -.noluck: - call mutex_unlock -.deverror: mov dword [esp+32], ERROR_DEVICE mov esi, edx call disk_dereference diff --git a/kernel/branches/Kolibri-acpi/blkdev/fdc.inc b/kernel/branches/Kolibri-acpi/blkdev/fdc.inc index 944f71cefb..7f0324cf61 100644 --- a/kernel/branches/Kolibri-acpi/blkdev/fdc.inc +++ b/kernel/branches/Kolibri-acpi/blkdev/fdc.inc @@ -21,40 +21,48 @@ fdc_init: ;start with clean tracks. ret save_image: - call reserve_flp - call restorefatchain + cmp [ramdisk_actual_size], FLOPPY_CAPACITY + jnz .fail pusha - call check_label + mov ecx, floppy_mutex + call mutex_lock + mov [flp_number], bl + call floppy_read_bootsector cmp [FDC_Status], 0 - jne unnecessary_save_image + jne .unnecessary_save_image mov [FDD_Track], 0; Цилиндр mov [FDD_Head], 0; Сторона mov [FDD_Sector], 1; Сектор mov esi, RAMDISK call SeekTrack -save_image_1: - push esi +.save_image_1: call take_data_from_application_1 - pop esi - add esi, 512 call WriteSectWithRetr ; call WriteSector cmp [FDC_Status], 0 - jne unnecessary_save_image + jne .unnecessary_save_image inc [FDD_Sector] cmp [FDD_Sector], 19 - jne save_image_1 + jne .save_image_1 mov [FDD_Sector], 1 inc [FDD_Head] cmp [FDD_Head], 2 - jne save_image_1 + jne .save_image_1 mov [FDD_Head], 0 inc [FDD_Track] call SeekTrack cmp [FDD_Track], 80 - jne save_image_1 -unnecessary_save_image: + jne .save_image_1 +.unnecessary_save_image: + cmp [FDC_Status], 0 + pushf + mov ecx, floppy_mutex + call mutex_unlock + popf popa - mov [flp_status], 0 + jnz .fail + xor eax, eax + ret +.fail: + movi eax, 1 ret - diff --git a/kernel/branches/Kolibri-acpi/blkdev/flp_drv.inc b/kernel/branches/Kolibri-acpi/blkdev/flp_drv.inc index 14ed160b89..0825874023 100644 --- a/kernel/branches/Kolibri-acpi/blkdev/flp_drv.inc +++ b/kernel/branches/Kolibri-acpi/blkdev/flp_drv.inc @@ -1,6 +1,6 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; -;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; +;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; ;; Distributed under terms of the GNU General Public License ;; ;; ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -20,8 +20,7 @@ $Revision$ ; add edi,ecx give_back_application_data_1: mov esi, FDD_BUFF;FDD_DataBuffer ;0x40000 - xor ecx, ecx - mov cx, 128 + mov ecx, 128 cld rep movsd ret @@ -32,8 +31,7 @@ give_back_application_data_1: ; add esi,ecx take_data_from_application_1: mov edi, FDD_BUFF;FDD_DataBuffer ;0x40000 - xor ecx, ecx - mov cx, 128 + mov ecx, 128 cld rep movsd ret @@ -122,6 +120,7 @@ Init_FDC_DMA: ;* AL - выводимый байт. * ;*********************************** FDCDataOutput: +; DEBUGF 1,'K : FDCDataOutput(%x)',al ; pusha push eax ecx edx mov AH, AL ;запомнить байт в AH @@ -137,6 +136,7 @@ FDCDataOutput: je @@OutByteToFDC loop @@TestRS ; Ошибка тайм-аута +; DEBUGF 1,' timeout\n' mov [FDC_Status], FDC_TimeOut jmp @@End_5 ; Вывести байт в порт данных @@ -144,6 +144,7 @@ FDCDataOutput: inc DX mov AL, AH out DX, AL +; DEBUGF 1,' ok\n' @@End_5: ; popa pop edx ecx eax @@ -170,12 +171,14 @@ FDCDataInput: je @@GetByteFromFDC loop @@TestRS_1 ; Ошибка тайм-аута +; DEBUGF 1,'K : FDCDataInput: timeout\n' mov [FDC_Status], FDC_TimeOut jmp @@End_6 ; Ввести байт из порта данных @@GetByteFromFDC: inc DX in AL, DX +; DEBUGF 1,'K : FDCDataInput: %x\n',al @@End_6: pop DX pop ECX @@ -185,6 +188,7 @@ FDCDataInput: ;* ОБРАБОТЧИК ПРЕРЫВАНИЯ ОТ КОНТРОЛЛЕРА НГМД * ;********************************************* FDCInterrupt: +; dbgstr 'FDCInterrupt' ; Установить флаг прерывания mov [FDD_IntFlag], 1 mov al, 1 @@ -207,12 +211,12 @@ WaitFDCInterrupt: jnz @@End_7 ;прерывание произошло mov eax, [timer_ticks] sub eax, [TickCounter] - cmp eax, 50 ;25 ;5 ;ожидать 5 тиков + cmp eax, 200;50 ;25 ;5 ;ожидать 5 тиков jb @@TestRS_2 ; jl @@TestRS_2 ; Ошибка тайм-аута +; dbgstr 'WaitFDCInterrupt: timeout' mov [FDC_Status], FDC_TimeOut -; mov [flp_status],0 @@End_7: popa ret @@ -221,6 +225,7 @@ WaitFDCInterrupt: ;* ВКЛЮЧИТЬ МОТОР ДИСКОВОДА "A:" * ;********************************* FDDMotorON: +; dbgstr 'FDDMotorON' pusha ; cmp [fdd_motor_status],1 ; je fdd_motor_on @@ -252,6 +257,20 @@ FDDMotorON_1: sub eax, [TickCounter] cmp eax, 50 ;10 jb @@dT +; Read results of RESET command + push 4 +; DEBUGF 1,'K : floppy reset results:' +@@: + mov al, 8 + call FDCDataOutput + call FDCDataInput +; DEBUGF 1,' %x',al + call FDCDataInput +; DEBUGF 1,' %x',al + dec dword [esp] + jnz @b +; DEBUGF 1,'\n' + pop eax cmp [flp_number], 1 jne fdd_motor_on_B mov [fdd_motor_status], 1 @@ -275,8 +294,6 @@ save_timer_fdd_motor: ;* ПРОВЕРКА ЗАДЕРЖКИ ВЫКЛЮЧЕНИЯ МОТОРА * ;***************************************** proc check_fdd_motor_status_has_work? - cmp [flp_status], 0 - jnz .yes cmp [fdd_motor_status], 0 jz .no mov eax, [timer_ticks] @@ -303,7 +320,6 @@ check_fdd_motor_status: call FDDMotorOFF mov [fdd_motor_status], 0 end_check_fdd_motor_status_1: - mov [flp_status], 0 end_check_fdd_motor_status: ret @@ -311,6 +327,7 @@ end_check_fdd_motor_status: ;* ВЫКЛЮЧИТЬ МОТОР ДИСКОВОДА * ;********************************** FDDMotorOFF: +; dbgstr 'FDDMotorOFF' push AX push DX cmp [flp_number], 1 @@ -323,8 +340,8 @@ FDDMotorOFF_2: pop DX pop AX ; сброс флагов кеширования в связи с устареванием информации - mov [root_read], 0 - mov [flp_fat], 0 + or [floppy_media_flags+0], FLOPPY_MEDIA_NEED_RESCAN + or [floppy_media_flags+1], FLOPPY_MEDIA_NEED_RESCAN ret FDDMotorOFF_A: @@ -343,8 +360,11 @@ FDDMotorOFF_B: ;* РЕКАЛИБРОВКА ДИСКОВОДА "A:" * ;******************************* RecalibrateFDD: +; dbgstr 'RecalibrateFDD' pusha call save_timer_fdd_motor +; Сбросить флаг прерывания + mov [FDD_IntFlag], 0 ; Подать команду "Рекалибровка" mov AL, 07h call FDCDataOutput @@ -352,10 +372,18 @@ RecalibrateFDD: call FDCDataOutput ; Ожидать завершения операции call WaitFDCInterrupt -; cmp [FDC_Status],0 -; je no_fdc_status_error -; mov [flp_status],0 -;no_fdc_status_error: + cmp [FDC_Status], 0 + jne .fail +; Read results of RECALIBRATE command +; DEBUGF 1,'K : floppy recalibrate results:' + mov al, 8 + call FDCDataOutput + call FDCDataInput +; DEBUGF 1,' %x',al + call FDCDataInput +; DEBUGF 1,' %x',al +; DEBUGF 1,'\n' +.fail: call save_timer_fdd_motor popa ret @@ -368,6 +396,7 @@ RecalibrateFDD: ;* Результат операции заносится в FDC_Status. * ;***************************************************** SeekTrack: +; dbgstr 'SeekTrack' pusha call save_timer_fdd_motor ; Сбросить флаг прерывания @@ -402,17 +431,20 @@ SeekTrack: cmp AL, [FDD_Track] jne @@Err ; Номер головки совпадает с заданным? - mov AL, [FDC_ST0] - and AL, 100b - shr AL, 2 - cmp AL, [FDD_Head] - jne @@Err +; The H bit (Head Address) in ST0 will always return a "0" (c) 82077AA datasheet, +; description of SEEK command. So we can not verify the proper head. +; mov AL, [FDC_ST0] +; and AL, 100b +; shr AL, 2 +; cmp AL, [FDD_Head] +; jne @@Err ; Операция завершена успешно +; dbgstr 'SeekTrack: FDC_Normal' mov [FDC_Status], FDC_Normal jmp @@Exit @@Err: ; Трек не найден +; dbgstr 'SeekTrack: FDC_TrackNotFound' mov [FDC_Status], FDC_TrackNotFound -; mov [flp_status],0 @@Exit: call save_timer_fdd_motor popa @@ -429,6 +461,7 @@ SeekTrack: ;* содержимое сектора будет занесено в FDD_DataBuffer. * ;******************************************************* ReadSector: +; dbgstr 'ReadSector' pushad call save_timer_fdd_motor ; Сбросить флаг прерывания @@ -468,11 +501,12 @@ ReadSector: call GetStatusInfo test [FDC_ST0], 11011000b jnz @@Err_1 +; dbgstr 'ReadSector: FDC_Normal' mov [FDC_Status], FDC_Normal jmp @@Exit_1 @@Err_1: +; dbgstr 'ReadSector: FDC_SectorNotFound' mov [FDC_Status], FDC_SectorNotFound -; mov [flp_status],0 @@Exit_1: call save_timer_fdd_motor popad @@ -511,12 +545,10 @@ ReadSectWithRetr: inc [RecalRepCounter] cmp [RecalRepCounter], 3 jb @@TryAgain -; mov [flp_status],0 @@Exit_2: popa ret @@Err_3: - mov [flp_status], 0 popa ret @@ -531,6 +563,7 @@ ReadSectWithRetr: ;* содержимое FDD_DataBuffer будет занесено в сектор. * ;******************************************************* WriteSector: +; dbgstr 'WriteSector' pushad call save_timer_fdd_motor ; Сбросить флаг прерывания @@ -616,7 +649,6 @@ WriteSectWithRetr: popa ret @@Err_4: - mov [flp_status], 0 popa ret @@ -642,3 +674,276 @@ GetStatusInfo: pop AX ret +; Interface for disk subsystem. +; Assume fixed capacity for 1.44M. +FLOPPY_CAPACITY = 2880 ; in sectors + +iglobal +align 4 +floppy_functions: + dd .size + dd 0 ; no close() function + dd 0 ; no closemedia() function + dd floppy_querymedia + dd floppy_read + dd floppy_write + dd 0 ; no flush() function + dd 0 ; no adjust_cache_size() function +.size = $ - floppy_functions +endg + +uglobal +floppy_media_flags rb 2 +n_sector dd 0 ; temporary save for sector value +flp_number db 0 ; 1- Floppy A, 2-Floppy B +old_track db 0 ; old value track +flp_label rb 15*2 ; Label and ID of inserted floppy disk +align 4 +; Hardware does not allow to work with two floppies in parallel, +; so there is one mutex guarding access to any floppy. +floppy_mutex MUTEX +endg +; Meaning of bits in floppy_media_flags +FLOPPY_MEDIA_PRESENT = 1 ; media was present when last asked +FLOPPY_MEDIA_NEED_RESCAN = 2 ; media was possibly changed, need to rescan +FLOPPY_MEDIA_LABEL_CHANGED = 4 ; temporary state + +iglobal +floppy1_name db 'fd',0 +floppy2_name db 'fd2',0 +endg + +; This function is called in boot process. +; It creates filesystems /fd and/or /fd2, if the system has one/two floppy drives. +proc floppy_init + mov ecx, floppy_mutex + call mutex_init +; First floppy is present if [DRIVE_DATA] and 0xF0 is nonzero. + test byte [DRIVE_DATA], 0xF0 + jz .no1 + stdcall disk_add, floppy_functions, floppy1_name, 1, DISK_NO_INSERT_NOTIFICATION +.no1: +; Second floppy is present if [DRIVE_DATA] and 0x0F is nonzero. + test byte [DRIVE_DATA], 0x0F + jz .no2 + stdcall disk_add, floppy_functions, floppy2_name, 2, DISK_NO_INSERT_NOTIFICATION +.no2: + ret +endp + +; Returns information about disk media. +; Floppy drives do not support insert notifications, +; DISK_NO_INSERT_NOTIFICATION is set, +; the disk subsystem calls this function before each filesystem operation. +; If the media has changed, return error for the first call as signal +; to finalize work with old media and the true geometry for the second call. +; Assume that media is (possibly) changed anytime when motor is off. +proc floppy_querymedia + virtual at esp+4 + .userdata dd ? + .info dd ? + end virtual +; 1. Acquire the global lock. + mov ecx, floppy_mutex + call mutex_lock + mov edx, [.userdata] ; 1 for /fd, 2 for /fd2 +; 2. If the media was reported and has been changed, forget it and report an error. + mov al, [floppy_media_flags+edx-1] + and al, FLOPPY_MEDIA_PRESENT + FLOPPY_MEDIA_NEED_RESCAN + cmp al, FLOPPY_MEDIA_PRESENT + FLOPPY_MEDIA_NEED_RESCAN + jnz .not_reported +.no_media: + mov [floppy_media_flags+edx-1], 0 +.return_no_media: + mov ecx, floppy_mutex + call mutex_unlock + mov eax, DISK_STATUS_NO_MEDIA + retn 8 +.not_reported: +; 3. If we are in the temporary state LABEL_CHANGED, this is the second call +; after intermediate DISK_STATUS_NO_MEDIA due to media change; +; clear the flag and return the current geometry without rereading the bootsector. + cmp [floppy_media_flags+edx-1], FLOPPY_MEDIA_LABEL_CHANGED + jz .report_geometry +; 4. Try to read the bootsector. + mov [flp_number], dl + mov [FDC_Status], 0 + call floppy_read_bootsector +; 5. If reading bootsector failed, assume that media is not present. + mov edx, [.userdata] + cmp [FDC_Status], 0 + jnz .no_media +; 6. Check whether the previous status is "present". If not, go to 10. + push esi edi + imul edi, edx, 15 + add edi, flp_label-15 + mov esi, FDD_BUFF+39 + mov ecx, 15 + test [floppy_media_flags+edx-1], FLOPPY_MEDIA_PRESENT + jz .set_label +; 7. Compare the old label with the current one. + rep cmpsb +; 8. If the label has not changed, go to 11. + jz .ok +; 9. If the label has changed, store it, enter temporary state LABEL_CHANGED +; and report DISK_STATUS_NO_MEDIA. +; dbgstr 'floppy label changed' + add esi, ecx + add edi, ecx + mov ecx, 15 + sub esi, ecx + sub edi, ecx + rep movsb + mov [floppy_media_flags+edx-1], FLOPPY_MEDIA_LABEL_CHANGED + pop edi esi + jmp .return_no_media +.set_label: +; 10. The previous state was "not present". Copy the label. + rep movsb +.ok: + pop edi esi +.report_geometry: +; 11. Fill DISKMEDIAINFO structure. + mov ecx, [.info] + and [ecx+DISKMEDIAINFO.Flags], 0 + mov [ecx+DISKMEDIAINFO.SectorSize], 512 + mov dword [ecx+DISKMEDIAINFO.Capacity], FLOPPY_CAPACITY + and dword [ecx+DISKMEDIAINFO.Capacity+4], 0 +; 12. Update state: media is present, data are actual. + mov [floppy_media_flags+edx-1], FLOPPY_MEDIA_PRESENT +; 13. Release the global lock and return successful status. + mov ecx, floppy_mutex + call mutex_unlock + xor eax, eax + retn 8 +endp + +proc floppy_read_bootsector + pushad + mov [FDD_Track], 0; Цилиндр + mov [FDD_Head], 0; Сторона + mov [FDD_Sector], 1; Сектор + call FDDMotorON + call RecalibrateFDD + cmp [FDC_Status], 0 + jne .nothing + call SeekTrack + cmp [FDC_Status], 0 + jne .nothing + call ReadSectWithRetr +.nothing: + popad + ret +endp + +read_chs_sector: + call calculate_chs + call ReadSectWithRetr + ret + +save_chs_sector: + call calculate_chs + call WriteSectWithRetr + ret + +calculate_chs: + mov bl, [FDD_Track] + mov [old_track], bl + mov ebx, 18 + xor edx, edx + div ebx + inc edx + mov [FDD_Sector], dl + mov edx, eax + shr eax, 1 + and edx, 1 + mov [FDD_Track], al + mov [FDD_Head], dl + mov dl, [old_track] + cmp dl, [FDD_Track] + je no_seek_track_1 + call SeekTrack +no_seek_track_1: + ret + +; Writes one or more sectors to the device. +proc floppy_write + mov dl, 1 + jmp floppy_read_write +endp + +; Reads one or more sectors from the device. +proc floppy_read + mov dl, 0 +endp + +; Common part of floppy_read and floppy_write. +proc floppy_read_write userdata:dword, buffer:dword, start_sector:qword, numsectors_ptr:dword +virtual at ebp-8 +.sectors_todo dd ? +.operation db ? +end virtual + push edx ; save operation code to [.operation] +; 1. Get number of sectors to read/write +; and zero number of sectors that were actually read/written. + mov eax, [numsectors_ptr] + push dword [eax] ; initialize [.sectors_todo] + and dword [eax], 0 + push ebx esi edi ; save used registers to be stdcall +; 2. Acquire the global lock. + mov ecx, floppy_mutex + call mutex_lock +; 3. Set floppy number for this operation. + mov edx, [userdata] + mov [flp_number], dl +; 4. Read/write sector-by-sector. +.operation_loop: +; 4a. Check that the sector is inside the media. + cmp dword [start_sector+4], 0 + jnz .end_of_media + mov eax, dword [start_sector] + cmp eax, FLOPPY_CAPACITY + jae .end_of_media +; 4b. For read operation, call read_chs_sector and then move data from FDD_BUFF to [buffer]. +; For write operation, move data from [buffer] to FDD_BUFF and then call save_chs_sector. + cmp [.operation], 0 + jz .read + mov esi, [buffer] + mov edi, FDD_BUFF + mov ecx, 512/4 + rep movsd + mov [buffer], esi + call save_chs_sector + jmp @f +.read: + call read_chs_sector + mov esi, FDD_BUFF + mov edi, [buffer] + mov ecx, 512/4 + rep movsd + mov [buffer], edi +@@: +; 4c. If there was an error, propagate it to the caller. + cmp [FDC_Status], 0 + jnz .fail +; 4d. Otherwise, increment number of sectors processed and continue the loop. + mov eax, [numsectors_ptr] + inc dword [eax] + inc dword [start_sector] + dec [.sectors_todo] + jnz .operation_loop +; 5. Release the global lock and return with the correct status. + push 0 +.return: + mov ecx, floppy_mutex + call mutex_unlock + pop eax + pop edi esi ebx ; restore used registers to be stdcall + ret ; this translates to leave/retn N and purges local variables +.fail: + push -1 + jmp .return +.end_of_media: + push DISK_STATUS_END_OF_MEDIA + jmp .return +endp diff --git a/kernel/branches/Kolibri-acpi/blkdev/hd_drv.inc b/kernel/branches/Kolibri-acpi/blkdev/hd_drv.inc index 562c406cf2..227969880c 100644 --- a/kernel/branches/Kolibri-acpi/blkdev/hd_drv.inc +++ b/kernel/branches/Kolibri-acpi/blkdev/hd_drv.inc @@ -47,6 +47,10 @@ hd0_data HD_DATA ?, 0, 1 hd1_data HD_DATA ?, 0x10, 2 hd2_data HD_DATA ?, 0, 3 hd3_data HD_DATA ?, 0x10, 4 + +hd_address_table: + dd 0x1f0, 0x00, 0x1f0, 0x10 + dd 0x170, 0x00, 0x170, 0x10 endg uglobal @@ -645,14 +649,6 @@ hd_write_error: end if ret ;----------------------------------------------------------------------------- -hd_lba_error: - if lang eq sp - DEBUGF 1,"K : FS - HD error en LBA\n" - else - DEBUGF 1,"K : FS - HD LBA error\n" - end if - jmp LBA_read_ret -;----------------------------------------------------------------------------- align 4 wait_for_hd_idle: push eax edx diff --git a/kernel/branches/Kolibri-acpi/blkdev/rd.inc b/kernel/branches/Kolibri-acpi/blkdev/rd.inc index 79af12ba0b..12496fcbe9 100644 --- a/kernel/branches/Kolibri-acpi/blkdev/rd.inc +++ b/kernel/branches/Kolibri-acpi/blkdev/rd.inc @@ -1,2296 +1,195 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; -;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; +;; Copyright (C) KolibriOS team 2013. All rights reserved. ;; ;; Distributed under terms of the GNU General Public License ;; ;; ;; ;; RAMDISK functions ;; -;; (C) 2004 Ville Turjanmaa, License: GPL ;; -;; Addings by M.Lisovin ;; -;; LFN support by diamond ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; $Revision$ - -; calculate fat chain - -calculatefatchain: - - pushad - - mov esi, RAMDISK+512 - mov edi, RAMDISK_FAT - - fcnew: - mov eax, dword [esi] - mov ebx, dword [esi+4] - mov ecx, dword [esi+8] - mov edx, ecx - shr edx, 4;8 ok - shr dx, 4;7 ok - xor ch, ch - shld ecx, ebx, 20;6 ok - shr cx, 4;5 ok - shld ebx, eax, 12 - and ebx, 0x0fffffff;4 ok - shr bx, 4;3 ok - shl eax, 4 - and eax, 0x0fffffff;2 ok - shr ax, 4;1 ok - mov dword [edi], eax - mov dword [edi+4], ebx - mov dword [edi+8], ecx - mov dword [edi+12], edx - add edi, 16 - add esi, 12 - - cmp edi, RAMDISK_FAT+2856*2;2849 clusters - jnz fcnew - - popad - ret - - -restorefatchain: ; restore fat chain - - pushad - - mov esi, RAMDISK_FAT - mov edi, RAMDISK+512 - - fcnew2: - mov eax, dword [esi] - mov ebx, dword [esi+4] - shl ax, 4 - shl eax, 4 - shl bx, 4 - shr ebx, 4 - shrd eax, ebx, 8 - shr ebx, 8 - mov dword [edi], eax - mov word [edi+4], bx - add edi, 6 - add esi, 8 - - cmp edi, RAMDISK+512+4278;4274 bytes - all used FAT - jb fcnew2 - - mov esi, RAMDISK+512 ; duplicate fat chain - mov edi, RAMDISK+512+0x1200 - mov ecx, 1069;4274/4 - cld - rep movsd - - popad - ret - - -ramdisk_free_space: -;--------------------------------------------- -; -; returns free space in edi -; rewr.by Mihasik -;--------------------------------------------- - - push eax ebx ecx - - mov edi, RAMDISK_FAT;start of FAT - xor ax, ax;Free cluster=0x0000 in FAT - xor ebx, ebx;counter - mov ecx, 2849;2849 clusters - cld - rdfs1: - repne scasw - jnz rdfs2 ;if last cluster not 0 - inc ebx - test ecx, ecx - jnz rdfs1 - rdfs2: - shl ebx, 9;free clusters*512 - mov edi, ebx - - pop ecx ebx eax - ret - - -expand_filename: -;--------------------------------------------- -; -; exapand filename with '.' to 11 character -; eax - pointer to filename -;--------------------------------------------- - - push esi edi ebx - - mov edi, esp ; check for '.' in the name - add edi, 12+8 - - mov esi, eax - - mov eax, edi - mov [eax+0], dword ' ' - mov [eax+4], dword ' ' - mov [eax+8], dword ' ' - - flr1: - - cmp [esi], byte '.' - jne flr2 - mov edi, eax - add edi, 7 - jmp flr3 - - flr2: - - mov bl, [esi] - mov [edi], bl - - flr3: - - inc esi - inc edi - - mov ebx, eax - add ebx, 11 - - cmp edi, ebx - jbe flr1 - - pop ebx edi esi - ret - -fileread: -;---------------------------------------------------------------- -; -; fileread - sys floppy -; -; eax points to filename 11 chars -; ebx first wanted block ; 1+ ; if 0 then set to 1 -; ecx number of blocks to read ; 1+ ; if 0 then set to 1 -; edx mem location to return data -; esi length of filename 12*X 0=root -; -; ret ebx = size or 0xffffffff file not found -; eax = 0 ok read or other = errormsg -; -;-------------------------------------------------------------- - test ebx, ebx;if ebx=0 - set to 1 - jnz frfl5 - inc ebx - frfl5: - test ecx, ecx;if ecx=0 - set to 1 - jnz frfl6 - inc ecx - frfl6: - test esi, esi ; return ramdisk root - jnz fr_noroot ;if not root - cmp ebx, 14 ;14 clusters=root dir - ja oorr - cmp ecx, 14 - ja oorr - jmp fr_do - oorr: - mov eax, 5 ;out of root range (fnf) - xor ebx, ebx - dec ebx ;0xffffffff - ret - - fr_do: ;reading rootdir - mov edi, edx - dec ebx - push edx - mov edx, ecx - add edx, ebx - cmp edx, 15 ;ebx+ecx=14+1 - pushf - jbe fr_do1 - sub edx, 14 - sub ecx, edx - fr_do1: - shl ebx, 9 - mov esi, RAMDISK+512*19 - add esi, ebx - shl ecx, 7 - cld - rep movsd - popf - pop edx - jae fr_do2 - xor eax, eax; ok read - xor ebx, ebx - ret - fr_do2: ;if last cluster - mov eax, 6;end of file - xor ebx, ebx - ret - - fr_noroot: - - sub esp, 32 - call expand_filename - - dec ebx - - push eax - - push eax ebx ecx edx esi edi - call rd_findfile - je fifound - add esp, 32+28 ;if file not found - ret - - fifound: - - mov ebx, [edi-11+28] ;file size - mov [esp+20], ebx - mov [esp+24], ebx - add edi, 0xf - movzx eax, word [edi] - mov edi, eax ;edi=cluster - - frnew: - - add eax, 31 ;bootsector+2*fat+filenames - shl eax, 9 ;*512 - add eax, RAMDISK ;image base - mov ebx, [esp+8] - mov ecx, 512 ;[esp+4] - - cmp [esp+16], dword 0 ; wanted cluster ? - jne frfl7 - call memmove - add [esp+8], dword 512 - dec dword [esp+12] ; last wanted cluster ? - je frnoread - jmp frfl8 - frfl7: - dec dword [esp+16] - frfl8: - movzx eax, word [edi*2+RAMDISK_FAT] ; find next cluster from FAT - mov edi, eax - cmp edi, 4095 ;eof - cluster - jz frnoread2 - - cmp [esp+24], dword 512 ;eof - size - jb frnoread - sub [esp+24], dword 512 - - jmp frnew - - frnoread2: - - cmp [esp+16], dword 0 ; eof without read ? - je frnoread - - pop edi esi edx ecx - add esp, 4 - pop ebx ; ebx <- eax : size of file - add esp, 36 - mov eax, 6 ; end of file - ret - - frnoread: - - pop edi esi edx ecx - add esp, 4 - pop ebx ; ebx <- eax : size of file - add esp, 36 - xor eax, eax;read ok - ret - - - - rd_findfile: - ;by Mihasik - ;IN: eax - pointer to filename OUT: filestring+11 in edi or notZero in flags and fnf in eax,ebx - - mov edi, RAMDISK+512*18+512;Point at directory - cld - rd_newsearch: - mov esi, eax - mov ecx, 11 - rep cmpsb - je rd_ff - add cl, 21 - add edi, ecx - cmp edi, RAMDISK+512*33 - jb rd_newsearch - mov eax, 5 ;if file not found - eax=5 - xor ebx, ebx - dec ebx ;ebx=0xffffffff and zf=0 - rd_ff: - ret - -; \begin{diamond} - -uni2ansi_str: -; convert UNICODE zero-terminated string to ASCII-string (codepage 866) -; in: esi->source, edi->buffer (may be esi=edi) -; destroys: eax,esi,edi - lodsw - test ax, ax - jz .done - 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, 0xF0 ; 'Ё' - jmp .doit -.yo2: - mov al, 0xF1 ; 'ё' - jmp .doit -.rus1: -; 0x410-0x43F -> 0x80-0xAF - add al, 0x70 - jmp .doit -.rus2: -; 0x440-0x44F -> 0xE0-0xEF - add al, 0xA0 -.ascii: -.doit: - stosb - jmp uni2ansi_str -.done: - mov byte [edi], 0 - ret - -ansi2uni_char: -; convert ANSI character in al to UNICODE character in ax, using cp866 encoding - mov ah, 0 -; 0x00-0x7F - trivial map - cmp al, 0x80 - jb .ret -; 0x80-0xAF -> 0x410-0x43F - cmp al, 0xB0 - jae @f - add ax, 0x410-0x80 -.ret: - ret -@@: -; 0xE0-0xEF -> 0x440-0x44F - cmp al, 0xE0 - jb .unk - cmp al, 0xF0 - jae @f - add ax, 0x440-0xE0 - ret -; 0xF0 -> 0x401 -; 0xF1 -> 0x451 -@@: - cmp al, 0xF0 ; 'Ё' - jz .yo1 - cmp al, 0xF1 ; 'ё' - jz .yo2 -.unk: - mov al, '_' ; ah=0 - ret -.yo1: - mov ax, 0x401 - ret -.yo2: - mov ax, 0x451 - ret - -char_toupper: -; 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, 0xF1 ; 'ё' - jz .yo1 - cmp al, 0xA0 ; 'а' - jb .ret - cmp al, 0xE0 ; 'р' - jb .rus1 - cmp al, 0xEF ; 'я' - ja .ret -; 0xE0-0xEF -> 0x90-0x9F - sub al, 0xE0-0x90 -.ret: - ret -.rus1: -; 0xA0-0xAF -> 0x80-0x8F -.az: - and al, not 0x20 - ret -.yo1: -; 0xF1 -> 0xF0 - dec ax - ret - -fat_get_name: -; in: edi->FAT entry -; out: CF=1 - no valid entry -; else CF=0 and ebp->ASCIIZ-name -; (maximum length of filename is 255 (wide) symbols without trailing 0, -; but implementation requires buffer 261 words) -; destroys eax - cmp byte [edi], 0 - jz .no - cmp byte [edi], 0xE5 - jnz @f -.no: - stc - ret -@@: - cmp byte [edi+11], 0xF - jz .longname - test byte [edi+11], 8 - jnz .no - push ecx - push edi ebp - test byte [ebp-4], 1 - jnz .unicode_short - - mov eax, [edi] - mov ecx, [edi+4] - mov [ebp], eax - mov [ebp+4], ecx - - mov ecx, 8 -@@: - cmp byte [ebp+ecx-1], ' ' - loope @b - - mov eax, [edi+8] - cmp al, ' ' - je .done - shl eax, 8 - mov al, '.' - - lea ebp, [ebp+ecx+1] - mov [ebp], eax - mov ecx, 3 -@@: - rol eax, 8 - cmp al, ' ' - jne .done - loop @b - dec ebp -.done: - and byte [ebp+ecx+1], 0 ; CF=0 - pop ebp edi ecx - ret -.unicode_short: - mov ecx, 8 - push ecx -@@: - mov al, [edi] - inc edi - call ansi2uni_char - mov [ebp], ax - inc ebp - inc ebp - loop @b - pop ecx -@@: - cmp word [ebp-2], ' ' - jnz @f - dec ebp - dec ebp - loop @b -@@: - mov word [ebp], '.' - inc ebp - inc ebp - mov ecx, 3 - push ecx -@@: - mov al, [edi] - inc edi - call ansi2uni_char - mov [ebp], ax - inc ebp - inc ebp - loop @b - pop ecx -@@: - cmp word [ebp-2], ' ' - jnz @f - dec ebp - dec ebp - loop @b - dec ebp - dec ebp -@@: - and word [ebp], 0 ; CF=0 - pop ebp edi ecx - ret -.longname: -; LFN - mov al, byte [edi] - and eax, 0x3F - dec eax - cmp al, 20 - jae .no ; ignore invalid entries - mov word [ebp+260*2], 0 ; force null-terminating for orphans - imul eax, 13*2 - add ebp, eax - test byte [edi], 0x40 - jz @f - mov word [ebp+13*2], 0 -@@: - push eax -; now copy name from edi to ebp ... - mov eax, [edi+1] - mov [ebp], eax ; symbols 1,2 - mov eax, [edi+5] - mov [ebp+4], eax ; 3,4 - mov eax, [edi+9] - mov [ebp+8], ax ; 5 - mov eax, [edi+14] - mov [ebp+10], eax ; 6,7 - mov eax, [edi+18] - mov [ebp+14], eax ; 8,9 - mov eax, [edi+22] - mov [ebp+18], eax ; 10,11 - mov eax, [edi+28] - mov [ebp+22], eax ; 12,13 -; ... done - pop eax - sub ebp, eax - test eax, eax - jz @f -; if this is not first entry, more processing required - stc - ret -@@: -; if this is first entry: - test byte [ebp-4], 1 - jnz .ret -; buffer at ebp contains UNICODE name, convert it to ANSI - push esi edi - mov esi, ebp - mov edi, ebp - call uni2ansi_str - pop edi esi -.ret: - clc - ret - -fat_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 ebp esi -.loop: - mov al, [ebp] - inc ebp - call char_toupper - push eax - lodsb - call char_toupper - cmp al, [esp] - jnz .done - pop eax - test al, al - jnz .loop - dec esi - pop eax - pop ebp - xor eax, eax ; set ZF flag - ret -.done: - cmp al, '/' - jnz @f - cmp byte [esp], 0 - jnz @f - mov [esp+4], esi -@@: - pop eax - pop esi ebp - ret - -fat_time_to_bdfe: -; in: eax=FAT time -; out: eax=BDFE time - push ecx edx - mov ecx, eax - mov edx, eax - shr eax, 11 - shl eax, 16 ; hours - and edx, 0x1F - add edx, edx - mov al, dl ; seconds - shr ecx, 5 - and ecx, 0x3F - mov ah, cl ; minutes - pop edx ecx - ret - -fat_date_to_bdfe: - push ecx edx - mov ecx, eax - mov edx, eax - shr eax, 9 - add ax, 1980 - shl eax, 16 ; year - and edx, 0x1F - mov al, dl ; day - shr ecx, 5 - and ecx, 0xF - mov ah, cl ; month - pop edx ecx - ret - -bdfe_to_fat_time: - push edx - mov edx, eax - shr eax, 16 - and dh, 0x3F - shl eax, 6 - or al, dh - shr dl, 1 - and dl, 0x1F - shl eax, 5 - or al, dl - pop edx - ret - -bdfe_to_fat_date: - push edx - mov edx, eax - shr eax, 16 - sub ax, 1980 - and dh, 0xF - shl eax, 4 - or al, dh - and dl, 0x1F - shl eax, 5 - or al, dl - pop edx - ret - -fat_entry_to_bdfe: -; convert FAT entry at edi to BDFE (block of data of folder entry) at esi, advance esi -; destroys eax - mov eax, [ebp-4] - mov [esi+4], eax ; ASCII/UNICODE name -fat_entry_to_bdfe2: - movzx eax, byte [edi+11] - mov [esi], eax ; attributes - movzx eax, word [edi+14] - call fat_time_to_bdfe - mov [esi+8], eax ; creation time - movzx eax, word [edi+16] - call fat_date_to_bdfe - mov [esi+12], eax ; creation date - and dword [esi+16], 0 ; last access time is not supported on FAT - movzx eax, word [edi+18] - call fat_date_to_bdfe - mov [esi+20], eax ; last access date - movzx eax, word [edi+22] - call fat_time_to_bdfe - mov [esi+24], eax ; last write time - movzx eax, word [edi+24] - call fat_date_to_bdfe - mov [esi+28], eax ; last write date - mov eax, [edi+28] - mov [esi+32], eax ; file size (low dword) - xor eax, eax - mov [esi+36], eax ; file size (high dword) - test ebp, ebp - jz .ret - push ecx edi - lea edi, [esi+40] - mov esi, ebp - test byte [esi-4], 1 - jz .ansi - mov ecx, 260/2 - rep movsd - mov [edi-2], ax -@@: - mov esi, edi - pop edi ecx -.ret: - ret -.ansi: - mov ecx, 264/4 - rep movsd - mov [edi-1], al - jmp @b - -bdfe_to_fat_entry: -; convert BDFE at edx to FAT entry at edi -; destroys eax -; attributes byte - test byte [edi+11], 8 ; volume label? - jnz @f - mov al, [edx] - and al, 0x27 - and byte [edi+11], 0x10 - or byte [edi+11], al -@@: - mov eax, [edx+8] - call bdfe_to_fat_time - mov [edi+14], ax ; creation time - mov eax, [edx+12] - call bdfe_to_fat_date - mov [edi+16], ax ; creation date - mov eax, [edx+20] - call bdfe_to_fat_date - mov [edi+18], ax ; last access date - mov eax, [edx+24] - call bdfe_to_fat_time - mov [edi+22], ax ; last write time - mov eax, [edx+28] - call bdfe_to_fat_date - mov [edi+24], ax ; last write date - ret - -ramdisk_root_first: - mov edi, RAMDISK+512*19 - clc - ret -ramdisk_root_next: - add edi, 0x20 - cmp edi, RAMDISK+512*33 - cmc - ret - -ramdisk_root_extend_dir: - stc - ret - -uglobal -; this is for delete support -rd_prev_sector dd ? -rd_prev_prev_sector dd ? +iglobal +align 4 +ramdisk_functions: + dd .size + dd 0 ; no close() function + dd 0 ; no closemedia() function + dd ramdisk_querymedia + dd ramdisk_read + dd ramdisk_write + dd 0 ; no flush() function + dd ramdisk_adjust_cache_size +.size = $ - ramdisk_functions endg -ramdisk_notroot_next: - add edi, 0x20 - test edi, 0x1FF - jz ramdisk_notroot_next_sector - ret ; CF=0 -ramdisk_notroot_next_sector: - push ecx - mov ecx, [eax] - push [rd_prev_sector] - pop [rd_prev_prev_sector] - mov [rd_prev_sector], ecx - mov ecx, [ecx*2+RAMDISK_FAT] - and ecx, 0xFFF - cmp ecx, 2849 - jae ramdisk_notroot_first.err2 - mov [eax], ecx - pop ecx -ramdisk_notroot_first: - mov eax, [eax] - cmp eax, 2 - jb .err - cmp eax, 2849 - jae .err - shl eax, 9 - lea edi, [eax+(31 shl 9)+RAMDISK] - clc - ret -.err2: - pop ecx -.err: - stc - ret -ramdisk_notroot_next_write: - test edi, 0x1FF - jz ramdisk_notroot_next_sector -ramdisk_root_next_write: - ret - -ramdisk_notroot_extend_dir: - pusha - xor eax, eax - mov edi, RAMDISK_FAT - mov ecx, 2849 - repnz scasw - jnz .notfound - mov word [edi-2], 0xFFF - sub edi, RAMDISK_FAT - shr edi, 1 - dec edi - mov eax, [esp+28] - mov ecx, [eax] - mov [RAMDISK_FAT+ecx*2], di - mov [eax], edi - shl edi, 9 - add edi, (31 shl 9)+RAMDISK - mov [esp], edi - xor eax, eax - mov ecx, 128 - rep stosd - popa - clc - ret -.notfound: - popa - stc - ret - -rd_find_lfn: -; in: esi+ebp -> name -; out: CF=1 - file not found -; else CF=0 and edi->direntry - push esi edi - push 0 - push ramdisk_root_first - push ramdisk_root_next -.loop: - call fat_find_lfn - jc .notfound - cmp byte [esi], 0 - jz .found -.continue: - test byte [edi+11], 10h - jz .notfound - movzx eax, word [edi+26] - mov [esp+8], eax - mov dword [esp+4], ramdisk_notroot_first - mov dword [esp], ramdisk_notroot_next - test eax, eax - jnz .loop - mov dword [esp+4], ramdisk_root_first - mov dword [esp], ramdisk_notroot_next - jmp .loop -.notfound: - add esp, 12 - pop edi esi - stc - ret -.found: - test ebp, ebp - jz @f - mov esi, ebp - xor ebp, ebp - jmp .continue -@@: - mov eax, [esp+8] - add esp, 16 ; CF=0 - pop esi - ret - -;---------------------------------------------------------------- -; -; fs_RamdiskRead - LFN variant for reading sys floppy -; -; esi points to filename -; 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_RamdiskRead: - cmp byte [esi], 0 - jnz @f - or ebx, -1 - mov eax, 10 ; access denied - ret -@@: - push edi - call rd_find_lfn - jnc .found - pop edi - or ebx, -1 - mov eax, 5 ; file not found - ret -.found: - test ebx, ebx - jz .l1 - cmp dword [ebx+4], 0 - jz @f - xor ebx, ebx -.reteof: - mov eax, 6 ; EOF - pop edi - ret -@@: - mov ebx, [ebx] -.l1: - push ecx edx - push 0 - mov eax, [edi+28] - sub eax, ebx - jb .eof - cmp eax, ecx - jae @f - mov ecx, eax - mov byte [esp], 6 ; EOF -@@: - movzx edi, word [edi+26] ; cluster -.new: - jecxz .done - test edi, edi - jz .eof - cmp edi, 0xFF8 - jae .eof - lea eax, [edi+31] ; bootsector+2*fat+filenames - shl eax, 9 ; *512 - add eax, RAMDISK ; image base -; now eax points to data of cluster - sub ebx, 512 - jae .skip - lea eax, [eax+ebx+512] - neg ebx - push ecx - cmp ecx, ebx - jbe @f - mov ecx, ebx -@@: - mov ebx, edx - call memmove - add edx, ecx - sub [esp], ecx - pop ecx - xor ebx, ebx -.skip: - movzx edi, word [edi*2+RAMDISK_FAT] ; find next cluster from FAT - jmp .new -.eof: - mov ebx, edx - pop eax edx ecx - sub ebx, edx - jmp .reteof -.done: - mov ebx, edx - pop eax edx ecx edi - sub ebx, edx - ret - -;---------------------------------------------------------------- -; -; fs_RamdiskReadFolder - LFN variant for reading sys floppy folder -; -; esi points to filename; only root is folder on ramdisk -; ebx pointer to structure 32-bit number = first wanted block -; & 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 = size or 0xffffffff file not found -; eax = 0 ok read or other = errormsg -; -;-------------------------------------------------------------- -fs_RamdiskReadFolder: - push edi - cmp byte [esi], 0 - jz .root - call rd_find_lfn - jnc .found - pop edi - or ebx, -1 - mov eax, ERROR_FILE_NOT_FOUND - ret -.found: - test byte [edi+11], 0x10 - jnz .found_dir - pop edi - or ebx, -1 - mov eax, ERROR_ACCESS_DENIED - ret -.found_dir: - movzx eax, word [edi+26] - add eax, 31 - push 0 - jmp .doit -.root: - mov eax, 19 - push 14 -.doit: - push esi ecx ebp - sub esp, 262*2 ; reserve space for LFN - mov ebp, esp - push dword [ebx+4] ; for fat_get_name: read ANSI/UNICODE names - mov ebx, [ebx] -; init header - push eax ecx - mov edi, edx - mov ecx, 32/4 - xor eax, eax - rep stosd - mov byte [edx], 1 ; version - pop ecx eax - mov esi, edi ; esi points to block of data of folder entry (BDFE) -.main_loop: - mov edi, eax - shl edi, 9 - add edi, RAMDISK - push eax -.l1: - call fat_get_name - jc .l2 - cmp byte [edi+11], 0xF - jnz .do_bdfe - add edi, 0x20 - test edi, 0x1FF - jnz .do_bdfe - pop eax - inc eax - dec byte [esp+262*2+16] - jz .done - jns @f -; read next sector from FAT - mov eax, [(eax-31-1)*2+RAMDISK_FAT] - and eax, 0xFFF - cmp eax, 0xFF8 - jae .done - add eax, 31 - mov byte [esp+262*2+16], 0 -@@: - mov edi, eax - shl edi, 9 - add edi, RAMDISK - push eax -.do_bdfe: - inc dword [edx+8] ; new file found - dec ebx - jns .l2 - dec ecx - js .l2 - inc dword [edx+4] ; new file block copied - call fat_entry_to_bdfe -.l2: - add edi, 0x20 - test edi, 0x1FF - jnz .l1 - pop eax - inc eax - dec byte [esp+262*2+16] - jz .done - jns @f -; read next sector from FAT - mov eax, [(eax-31-1)*2+RAMDISK_FAT] - and eax, 0xFFF - cmp eax, 0xFF8 - jae .done - add eax, 31 - mov byte [esp+262*2+16], 0 -@@: - jmp .main_loop -.done: - add esp, 262*2+4 - pop ebp - mov ebx, [edx+4] - xor eax, eax - dec ecx - js @f - mov al, ERROR_END_OF_FILE -@@: - pop ecx esi edi edi - ret +; See memmap.inc. +; Currently size of memory allocated for the ramdisk is fixed. +; This should be revisited when/if memory map would become more dynamic. +RAMDISK_CAPACITY = 2880 ; in sectors iglobal -label fat_legal_chars byte -; 0 = not allowed -; 1 = allowed only in long names -; 3 = allowed - times 32 db 0 -; ! " # $ % & ' ( ) * + , - . / - db 1,3,0,3,3,3,3,3,3,3,0,1,1,3,3,0 -; 0 1 2 3 4 5 6 7 8 9 : ; < = > ? - db 3,3,3,3,3,3,3,3,3,3,0,1,0,1,0,0 -; @ A B C D E F G H I J K L M N O - db 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 -; P Q R S T U V W X Y Z [ \ ] ^ _ - db 3,3,3,3,3,3,3,3,3,3,3,1,0,1,3,3 -; ` a b c d e f g h i j k l m n o - db 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 -; p q r s t u v w x y z { | } ~ - db 3,3,3,3,3,3,3,3,3,3,3,3,0,3,3,0 +align 4 +ramdisk_actual_size dd RAMDISK_CAPACITY endg -fat_name_is_legal: -; in: esi->(long) name -; out: CF set <=> legal -; destroys eax - push esi - xor eax, eax -@@: - lodsb - test al, al - jz .done - cmp al, 80h - jae .big - test [fat_legal_chars+eax], 1 - jnz @b -.err: - pop esi - clc - ret -.big: -; 0x80-0xAF, 0xE0-0xEF - cmp al, 0xB0 - jb @b - cmp al, 0xE0 - jb .err - cmp al, 0xF0 - jb @b - jmp .err -.done: - sub esi, [esp] - cmp esi, 257 - pop esi - ret - -fat_next_short_name: -; in: edi->8+3 name -; out: name corrected -; CF=1 <=> error - pushad - mov ecx, 8 - mov al, '~' - std - push edi - add edi, 7 - repnz scasb - pop edi - cld - jz .tilde -; tilde is not found, insert "~1" at end - add edi, 6 - cmp word [edi], ' ' - jnz .insert_tilde -@@: - dec edi - cmp byte [edi], ' ' - jz @b - inc edi -.insert_tilde: - mov word [edi], '~1' - popad - clc - ret -.tilde: - push edi - add edi, 7 +; This function is called early in boot process. +; It creates filesystem /rd/1 based on raw image data loaded by somebody before +; to memory named as RAMDISK with max size RAMDISK_CAPACITY, may be less. +proc ramdisk_init +iglobal +ramdisk_name db 'rd',0 +endg + push ebx esi ; save used registers to be stdcall +; 1. Register the device and the (always inserted) media in the disk subsystem. + stdcall disk_add, ramdisk_functions, ramdisk_name, 0, 0 + test eax, eax + jz .fail + mov ebx, eax + stdcall disk_media_changed, eax, 1 +; 2. We don't know actual size of loaded image, +; so try to calculate it using partition structure, +; assuming that file systems fill the real size based on contents of the partition. +; 2a. Prepare for loop over partitions. xor ecx, ecx -@@: -; after tilde may be only digits and trailing spaces - cmp byte [edi], '~' - jz .break - cmp byte [edi], ' ' - jz .space - cmp byte [edi], '9' - jnz .found - dec edi - jmp @b -.space: - dec edi - inc ecx - jmp @b -.found: - inc byte [edi] - add dword [esp], 8 - jmp .zerorest -.break: - jecxz .noplace - inc edi - mov al, '1' -@@: - xchg al, [edi] - inc edi - cmp al, ' ' - mov al, '0' - jnz @b -.succ: - pop edi - popad - clc - ret -.noplace: - dec edi - cmp edi, [esp] - jz .err - add dword [esp], 8 - mov word [edi], '~1' - inc edi - inc edi -@@: - mov byte [edi], '0' -.zerorest: - inc edi - cmp edi, [esp] - jb @b - pop edi - popad - ;clc ; automatically - ret -.err: - pop edi - popad - stc - ret - -fat_gen_short_name: -; in: esi->long name -; edi->buffer (8+3=11 chars) -; out: buffer filled - pushad - mov eax, ' ' - push edi - stosd - stosd - stosd - pop edi - xor eax, eax - movi ebx, 8 - lea ecx, [edi+8] -.loop: - lodsb - test al, al - jz .done - call char_toupper - cmp al, ' ' - jz .space - cmp al, 80h - ja .big - test [fat_legal_chars+eax], 2 - jnz .symbol -.inv_symbol: - mov al, '_' - or bh, 1 -.symbol: - cmp al, '.' - jz .dot -.normal_symbol: - dec bl - jns .store - mov bl, 0 -.space: - or bh, 1 - jmp .loop -.store: - stosb - jmp .loop -.big: - cmp al, 0xB0 - jb .normal_symbol - cmp al, 0xE0 - jb .inv_symbol - cmp al, 0xF0 - jb .normal_symbol - jmp .inv_symbol -.dot: - test bh, 2 - jz .firstdot - pop ebx - add ebx, edi - sub ebx, ecx - push ebx - cmp ebx, ecx + xor edx, edx +; 2b. Check that at least one partition was recognized. + cmp [ebx+DISK.NumPartitions], ecx + jz .fail +; 2c. Loop over partitions. +.partitions: +; For every partition, set edx to maximum between edx and end of partition. + mov esi, [ebx+DISK.Partitions] + mov esi, [esi+ecx*4] + mov eax, dword [esi+PARTITION.FirstSector] + add eax, dword [esi+PARTITION.Length] + cmp eax, edx jb @f - pop ebx - push ecx -@@: - cmp edi, ecx - jbe .skip -@@: - dec edi - mov al, [edi] - dec ebx - mov [ebx], al - mov byte [edi], ' ' - cmp edi, ecx - ja @b -.skip: - mov bh, 3 - jmp @f -.firstdot: - cmp bl, 8 - jz .space - push edi - or bh, 2 -@@: - mov edi, ecx - mov bl, 3 - jmp .loop -.done: - test bh, 2 - jz @f - pop edi -@@: - lea edi, [ecx-8] - test bh, 1 - jz @f - call fat_next_short_name -@@: - popad - ret - -;---------------------------------------------------------------- -; -; fs_RamdiskRewrite - LFN variant for writing ramdisk -; fs_RamdiskCreateFolder - create folder on ramdisk -; -; esi points to file/folder name -; ebx ignored (reserved) -; ecx number of bytes to write, 0+ (ignored for folders) -; edx mem location to data (ignored for folders) -; -; ret ebx = number of written bytes -; eax = 0 ok read or other = errormsg -; -;-------------------------------------------------------------- -@@: - mov eax, ERROR_ACCESS_DENIED - xor ebx, ebx - ret - -fs_RamdiskCreateFolder: - mov al, 1 ; create folder - jmp fs_RamdiskRewrite.common - -fs_RamdiskRewrite: - xor eax, eax ; create file -.common: - cmp byte [esi], 0 - jz @b - pushad - xor edi, edi - push esi - test ebp, ebp - jz @f - mov esi, ebp -@@: - lodsb - test al, al - jz @f - cmp al, '/' - jnz @b - lea edi, [esi-1] - jmp @b -@@: - pop esi - test edi, edi - jnz .noroot - test ebp, ebp - jnz .hasebp - push ramdisk_root_extend_dir - push ramdisk_root_next_write - push edi - push ramdisk_root_first - push ramdisk_root_next - jmp .common1 -.hasebp: - mov eax, ERROR_ACCESS_DENIED - cmp byte [ebp], 0 - jz .ret1 - push ebp - xor ebp, ebp - call rd_find_lfn - pop esi - jc .notfound0 - jmp .common0 -.noroot: - mov eax, ERROR_ACCESS_DENIED - cmp byte [edi+1], 0 - jz .ret1 -; check existence - mov byte [edi], 0 - push edi - call rd_find_lfn - pop esi - mov byte [esi], '/' - jnc @f -.notfound0: - mov eax, ERROR_FILE_NOT_FOUND -.ret1: - mov [esp+28], eax - popad - xor ebx, ebx - ret -@@: - inc esi -.common0: - test byte [edi+11], 0x10 ; must be directory - mov eax, ERROR_ACCESS_DENIED - jz .ret1 - movzx ebp, word [edi+26] ; ebp=cluster - mov eax, ERROR_FAT_TABLE - cmp ebp, 2 - jb .ret1 - cmp ebp, 2849 - jae .ret1 - push ramdisk_notroot_extend_dir - push ramdisk_notroot_next_write - push ebp - push ramdisk_notroot_first - push ramdisk_notroot_next -.common1: - call fat_find_lfn - jc .notfound -; found - test byte [edi+11], 10h - jz .exists_file -; found directory; if we are creating directory, return OK, -; if we are creating file, say "access denied" - add esp, 20 - popad - test al, al - mov eax, ERROR_ACCESS_DENIED - jz @f - mov al, 0 -@@: - xor ebx, ebx - ret -.exists_file: -; found file; if we are creating directory, return "access denied", -; if we are creating file, delete existing file and continue - cmp byte [esp+20+28], 0 - jz @f - add esp, 20 - popad - mov eax, ERROR_ACCESS_DENIED - xor ebx, ebx - ret -@@: -; delete FAT chain - push edi - xor eax, eax - mov dword [edi+28], eax ; zero size - xchg ax, word [edi+26] ; start cluster - test eax, eax - jz .done1 -@@: - cmp eax, 0xFF8 - jae .done1 - lea edi, [RAMDISK_FAT + eax*2] ; position in FAT - xor eax, eax - xchg ax, [edi] - jmp @b -.done1: - pop edi - call get_time_for_file - mov [edi+22], ax - call get_date_for_file - mov [edi+24], ax - mov [edi+18], ax - or byte [edi+11], 20h ; set 'archive' attribute - jmp .doit -.notfound: -; file is not found; generate short name - call fat_name_is_legal - jc @f - add esp, 20 - popad - mov eax, ERROR_FILE_NOT_FOUND - xor ebx, ebx - ret -@@: - sub esp, 12 - mov edi, esp - call fat_gen_short_name -.test_short_name_loop: - push esi edi ecx - mov esi, edi - lea eax, [esp+12+12+8] - mov [eax], ebp - call dword [eax-4] - jc .found -.test_short_name_entry: - cmp byte [edi+11], 0xF - jz .test_short_name_cont - mov ecx, 11 - push esi edi - repz cmpsb - pop edi esi - jz .short_name_found -.test_short_name_cont: - lea eax, [esp+12+12+8] - call dword [eax-8] - jnc .test_short_name_entry - jmp .found -.short_name_found: - pop ecx edi esi - call fat_next_short_name - jnc .test_short_name_loop -.disk_full: - add esp, 12+20 - popad - mov eax, ERROR_DISK_FULL - xor ebx, ebx - ret -.found: - pop ecx edi esi -; now find space in directory -; we need to save LFN <=> LFN is not equal to short name <=> generated name contains '~' - mov al, '~' - push ecx edi - mov ecx, 8 - repnz scasb - movi eax, 1 ; 1 entry - jnz .notilde -; we need ceil(strlen(esi)/13) additional entries = floor((strlen(esi)+12+13)/13) total - xor eax, eax -@@: - cmp byte [esi], 0 - jz @f - inc esi - inc eax - jmp @b -@@: - sub esi, eax - add eax, 12+13 - mov ecx, 13 - push edx - cdq - div ecx - pop edx -.notilde: - push -1 - push -1 -; find successive entries in directory - xor ecx, ecx - push eax - lea eax, [esp+12+8+12+8] - mov [eax], ebp - call dword [eax-4] - pop eax -.scan_dir: - cmp byte [edi], 0 - jz .free - cmp byte [edi], 0xE5 - jz .free - xor ecx, ecx -.scan_cont: - push eax - lea eax, [esp+12+8+12+8] - call dword [eax-8] - pop eax - jnc .scan_dir - push eax - lea eax, [esp+12+8+12+8] - call dword [eax+8] ; extend directory - pop eax - jnc .scan_dir - add esp, 8+8+12+20 - popad - mov eax, ERROR_DISK_FULL - xor ebx, ebx - ret -.free: - test ecx, ecx - jnz @f - mov [esp], edi - mov ecx, [esp+8+8+12+8] - mov [esp+4], ecx - xor ecx, ecx + mov edx, eax @@: inc ecx - cmp ecx, eax - jb .scan_cont -; found! -; If creating a directory, allocate one data cluster now and fail immediately -; if this is impossible. This prevents from creating an invalid directory entry -; on a full disk. -; yup, the argument is quite non-intuitive... but what should I do if -; the entire function uses such arguments? BTW, it refers to al from pushad, -; which in turn is filled with 0 in fs_RamdiskRewrite and 1 in fs_RamdiskCreateFolder. - push esi ecx - cmp byte [esp+24+12+20+28], 0 - jz .no.preallocate.folder.data - mov ecx, 2849 - mov edi, RAMDISK_FAT - xor eax, eax - repnz scasw - jz @f - add esp, 24 - jmp .disk_full + cmp ecx, [ebx+DISK.NumPartitions] + jb .partitions +; 3. Reclaim unused memory, if any. + mov [ramdisk_actual_size], edx + add edx, 7 ; aligning up + shr edx, 3 ; 512-byte sectors -> 4096-byte pages + mov esi, RAMDISK_CAPACITY / 8 ; aligning down + sub esi, edx + jbe .no_reclaim + shl edx, 12 + add edx, RAMDISK - OS_BASE @@: - mov [esp+24+12+20+20], edi ; store the cluster somewhere -.no.preallocate.folder.data: -; calculate name checksum - mov esi, [esp+8+8] - mov ecx, 11 - xor eax, eax -@@: - ror al, 1 - add al, [esi] - inc esi - loop @b - pop ecx esi - pop edi - pop dword [esp+8+12+8] -; edi points to last entry in free chunk - dec ecx - jz .nolfn - push esi - push eax - mov al, 40h -.writelfn: - or al, cl - mov esi, [esp+4] - push ecx - dec ecx - imul ecx, 13 - add esi, ecx - stosb - mov cl, 5 - call .read_symbols - mov ax, 0xF - stosw - mov al, [esp+4] - stosb - mov cl, 6 - call .read_symbols - xor eax, eax - stosw - mov cl, 2 - call .read_symbols - pop ecx - lea eax, [esp+8+8+12+8] - call dword [eax+4] ; next write - xor eax, eax - loop .writelfn - pop eax - pop esi -.nolfn: - xchg esi, [esp] - mov ecx, 11 - rep movsb - mov word [edi], 20h ; attributes - sub edi, 11 - pop esi ecx - add esp, 12 - mov byte [edi+13], 0 ; tenths of a second at file creation time - call get_time_for_file - mov [edi+14], ax ; creation time - mov [edi+22], ax ; last write time - call get_date_for_file - mov [edi+16], ax ; creation date - mov [edi+24], ax ; last write date - mov [edi+18], ax ; last access date - and word [edi+20], 0 ; high word of cluster - and word [edi+26], 0 ; low word of cluster - to be filled - and dword [edi+28], 0 ; file size - to be filled - cmp byte [esp+20+28], 0 - jz .doit -; create directory - mov byte [edi+11], 10h ; attributes: folder - mov ecx, 32*2 - mov edx, edi - push edx - push ecx - push edi - add edi, 26 ; edi points to low word of cluster - push edi - mov edi, [esp+16+20+20] - jmp .doit2 -.doit: - push edx - push ecx - push edi - add edi, 26 ; edi points to low word of cluster - push edi - jecxz .done - mov ecx, 2849 - mov edi, RAMDISK_FAT -.write_loop: -; allocate new cluster - xor eax, eax - repnz scasw - jnz .disk_full2 -.doit2: - dec edi - dec edi - - ; lea eax, [edi-(RAMDISK_FAT)] - - mov eax, edi - sub eax, RAMDISK_FAT - - shr eax, 1 ; eax = cluster - mov word [edi], 0xFFF ; mark as last cluster - xchg edi, [esp] - stosw - pop edi - push edi - inc ecx -; write data - cmp byte [esp+16+20+28], 0 - jnz .writedir - shl eax, 9 - add eax, RAMDISK+31*512 -.writefile: - mov ebx, edx - xchg eax, ebx - push ecx - mov ecx, 512 - cmp dword [esp+12], ecx - jae @f - mov ecx, [esp+12] -@@: - call memmove - add edx, ecx - sub [esp+12], ecx - pop ecx - jnz .write_loop -.done: - mov ebx, edx - pop edi edi ecx edx - sub ebx, edx - mov [edi+28], ebx - add esp, 20 - mov [esp+16], ebx - popad - xor eax, eax - ret -.disk_full2: - mov ebx, edx - pop edi edi ecx edx - sub ebx, edx - mov [edi+28], ebx - add esp, 20 - mov [esp+16], ebx - popad - movi eax, ERROR_DISK_FULL - ret -.writedir: - mov edi, eax - shl edi, 9 - add edi, RAMDISK+31*512 - mov esi, edx - mov ecx, 32/4 - push ecx - rep movsd - mov dword [edi-32], '. ' - mov dword [edi-32+4], ' ' - mov dword [edi-32+8], ' ' - mov byte [edi-32+11], 10h - mov word [edi-32+26], ax - mov esi, edx - pop ecx - rep movsd - mov dword [edi-32], '.. ' - mov dword [edi-32+4], ' ' - mov dword [edi-32+8], ' ' - mov byte [edi-32+11], 10h - mov eax, [esp+16+8] - mov word [edi-32+26], ax - xor eax, eax - mov ecx, (512-32*2)/4 - rep stosd - pop edi edi ecx edx - add esp, 20 - popad - xor eax, eax - xor ebx, ebx - ret - -.read_symbol: - or ax, -1 - test esi, esi - jz .retFFFF - lodsb - test al, al - jnz ansi2uni_char - xor eax, eax - xor esi, esi -.retFFFF: - ret - -.read_symbols: - call .read_symbol - stosw - loop .read_symbols - ret - -;---------------------------------------------------------------- -; -; fs_RamdiskWrite - LFN variant for writing to sys floppy -; -; esi points to filename -; ebx pointer to 64-bit number = first wanted byte, 0+ -; may be ebx=0 - start from first byte -; ecx number of bytes to write, 0+ -; edx mem location to data -; -; ret ebx = bytes written (maybe 0) -; eax = 0 ok write or other = errormsg -; -;-------------------------------------------------------------- -@@: - push ERROR_ACCESS_DENIED -fs_RamdiskWrite.ret0: - pop eax - xor ebx, ebx - ret - -fs_RamdiskWrite: - cmp byte [esi], 0 - jz @b - pushad - call rd_find_lfn - jnc .found - popad - push ERROR_FILE_NOT_FOUND - jmp .ret0 -.found: -; must not be directory - test byte [edi+11], 10h - jz @f - popad - push ERROR_ACCESS_DENIED - jmp .ret0 -@@: -; FAT does not support files larger than 4GB - test ebx, ebx - jz .l1 - cmp dword [ebx+4], 0 - jz @f -.eof: - popad - push ERROR_END_OF_FILE - jmp .ret0 -@@: - mov ebx, [ebx] -.l1: -; now edi points to direntry, ebx=start byte to write, -; ecx=number of bytes to write, edx=data pointer - call fat_update_datetime - -; extend file if needed - add ecx, ebx - jc .eof ; FAT does not support files larger than 4GB - push 0 ; return value=0 - cmp ecx, [edi+28] - jbe .length_ok - cmp ecx, ebx - jz .length_ok - call ramdisk_extend_file - jnc .length_ok -; ramdisk_extend_file can return two error codes: FAT table error or disk full. -; First case is fatal error, in second case we may write some data - mov [esp], eax - cmp al, ERROR_DISK_FULL - jz .disk_full - pop eax - mov [esp+28], eax - popad - xor ebx, ebx - ret -.disk_full: -; correct number of bytes to write - mov ecx, [edi+28] - cmp ecx, ebx - ja .length_ok -.ret: - pop eax - mov [esp+28], eax ; eax=return value - sub edx, [esp+20] - mov [esp+16], edx ; ebx=number of written bytes - popad - ret -.length_ok: -; now ebx=start pos, ecx=end pos, both lie inside file - sub ecx, ebx - jz .ret - movzx edi, word [edi+26] ; starting cluster -.write_loop: - sub ebx, 0x200 - jae .next_cluster - push ecx - neg ebx - cmp ecx, ebx - jbe @f - mov ecx, ebx -@@: - mov eax, edi - shl eax, 9 - add eax, RAMDISK+31*512+0x200 - sub eax, ebx - mov ebx, eax mov eax, edx - call memmove - xor ebx, ebx - add edx, ecx - sub [esp], ecx - pop ecx - jz .ret -.next_cluster: - movzx edi, word [edi*2+RAMDISK_FAT] - jmp .write_loop + call free_page + add edx, 0x1000 + dec esi + jnz @b +.no_reclaim: + pop esi ebx ; restore used registers to be stdcall + ret +.fail: + dbgstr 'Failed to initialize ramdisk' + pop esi ebx ; restore used registers to be stdcall + ret +endp -ramdisk_extend_file.zero_size: +; Returns information about disk media. +proc ramdisk_querymedia + virtual at esp+4 + .userdata dd ? + .info dd ? + end virtual +; Media is always present, sector size is always 512 bytes. + mov edx, [.userdata] + mov ecx, [.info] + mov [ecx+DISKMEDIAINFO.Flags], 0 + mov [ecx+DISKMEDIAINFO.SectorSize], 512 + mov eax, [ramdisk_actual_size] + mov dword [ecx+DISKMEDIAINFO.Capacity], eax + mov dword [ecx+DISKMEDIAINFO.Capacity+4], 0 +; Return zero as an indicator of success. xor eax, eax - jmp ramdisk_extend_file.start_extend + retn 8 +endp -; extends file on ramdisk to given size, new data area is filled by 0 -; in: edi->direntry, ecx=new size -; out: CF=0 => OK, eax=0 -; CF=1 => error, eax=code (ERROR_FAT_TABLE or ERROR_DISK_FULL) -ramdisk_extend_file: - push ecx -; find the last cluster of file - movzx eax, word [edi+26] ; first cluster - mov ecx, [edi+28] - jecxz .zero_size -@@: - sub ecx, 0x200 - jbe @f - mov eax, [eax*2+RAMDISK_FAT] - and eax, 0xFFF - jz .fat_err - cmp eax, 0xFF8 - jb @b -.fat_err: - pop ecx - movi eax, ERROR_FAT_TABLE - stc - ret -@@: - push eax - mov eax, [eax*2+RAMDISK_FAT] - and eax, 0xFFF - cmp eax, 0xFF8 - pop eax - jb .fat_err -; set length to full number of sectors and make sure that last sector is zero-padded - sub [edi+28], ecx - push eax edi - mov edi, eax - shl edi, 9 - lea edi, [edi+RAMDISK+31*512+0x200+ecx] - neg ecx - xor eax, eax - rep stosb - pop edi eax -.start_extend: - pop ecx -; now do extend - push edx esi - mov esi, RAMDISK_FAT+2*2 ; start scan from cluster 2 - mov edx, 2847 ; number of clusters to scan -.extend_loop: - cmp [edi+28], ecx - jae .extend_done -; add new sector - push ecx - mov ecx, edx - push edi - mov edi, esi - jecxz .disk_full - push eax - xor eax, eax - repnz scasw - pop eax - jnz .disk_full - mov word [edi-2], 0xFFF - mov esi, edi - mov edx, ecx - sub edi, RAMDISK_FAT - shr edi, 1 - dec edi ; now edi=new cluster - test eax, eax - jz .first_cluster - mov [RAMDISK_FAT+eax*2], di - jmp @f -.first_cluster: - pop eax ; eax->direntry - push eax - mov [eax+26], di -@@: - push edi - shl edi, 9 - add edi, RAMDISK+31*512 - xor eax, eax - mov ecx, 512/4 - rep stosd - pop eax ; eax=new cluster - pop edi ; edi->direntry - pop ecx ; ecx=required size - add dword [edi+28], 0x200 - jmp .extend_loop -.extend_done: - mov [edi+28], ecx - pop esi edx - xor eax, eax ; CF=0 - ret -.disk_full: - pop edi ecx - pop esi edx - stc - movi eax, ERROR_DISK_FULL - ret - -fat_update_datetime: - call get_time_for_file - mov [edi+22], ax ; last write time - call get_date_for_file - mov [edi+24], ax ; last write date - mov [edi+18], ax ; last access date - ret - -;---------------------------------------------------------------- -; -; fs_RamdiskSetFileEnd - set end of file on ramdisk -; -; esi points to filename -; ebx points to 64-bit number = new file size -; ecx ignored (reserved) -; edx ignored (reserved) -; -; ret eax = 0 ok or other = errormsg -; -;-------------------------------------------------------------- -fs_RamdiskSetFileEnd: - cmp byte [esi], 0 - jnz @f -.access_denied: - push ERROR_ACCESS_DENIED - jmp .ret -@@: - push edi - call rd_find_lfn - jnc @f - pop edi - push ERROR_FILE_NOT_FOUND -.ret: - pop eax - ret -@@: -; must not be directory - test byte [edi+11], 10h - jz @f - pop edi - jmp .access_denied -@@: -; file size must not exceed 4Gb - cmp dword [ebx+4], 0 - jz @f - pop edi - push ERROR_END_OF_FILE - jmp .ret -@@: -; set file modification date/time to current - call fat_update_datetime - mov eax, [ebx] - cmp eax, [edi+28] - jb .truncate - ja .expand - pop edi - xor eax, eax - ret -.expand: - push ecx +; Common procedure for reading and writing. +; operation = 0 for reading, operation = 1 for writing. +; Arguments of ramdisk_read and ramdisk_write are the same. +macro ramdisk_read_write operation +{ + push esi edi ; save used registers to be stdcall + 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 RAMDISK_CAPACITY. +; If so, calculate number of sectors between [start_sector] and RAMDISK_CAPACITY. +; Otherwise, the actual number of sectors is zero. + cmp dword [start_sector+4], ecx + jnz .got_number + mov eax, [ramdisk_actual_size] + 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 - call ramdisk_extend_file - pop ecx - pop edi - ret -.truncate: - mov [edi+28], eax - push ecx - movzx ecx, word [edi+26] - test eax, eax - jz .zero_size -; find new last sector -@@: - sub eax, 0x200 - jbe @f - movzx ecx, word [RAMDISK_FAT+ecx*2] - jmp @b -@@: -; zero data at the end of last sector - push ecx - mov edi, ecx - shl edi, 9 - lea edi, [edi+RAMDISK+31*512+eax+0x200] - mov ecx, eax - neg ecx +.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 - rep stosb - pop ecx -; terminate FAT chain - lea ecx, [RAMDISK_FAT+ecx+ecx] - push dword [ecx] - mov word [ecx], 0xFFF - pop ecx - and ecx, 0xFFF - jmp .delete -.zero_size: - and word [edi+26], 0 -.delete: -; delete FAT chain starting with ecx -; mark all clusters as free - cmp ecx, 0xFF8 - jae .deleted - lea ecx, [RAMDISK_FAT+ecx+ecx] - push dword [ecx] - and word [ecx], 0 - pop ecx - and ecx, 0xFFF - jmp .delete -.deleted: - pop ecx - pop edi - xor eax, eax - ret - -fs_RamdiskGetFileInfo: - cmp byte [esi], 0 - jnz @f - mov eax, 2 ; unsupported - ret -@@: - push edi - call rd_find_lfn -fs_GetFileInfo_finish: - jnc @f - pop edi - mov eax, ERROR_FILE_NOT_FOUND - ret -@@: - push esi ebp - xor ebp, ebp - mov esi, edx - and dword [esi+4], 0 - call fat_entry_to_bdfe2 - pop ebp esi - pop edi - xor eax, eax - ret - -fs_RamdiskSetFileInfo: - cmp byte [esi], 0 - jnz @f - mov eax, 2 ; unsupported - ret -@@: - push edi - call rd_find_lfn - jnc @f - pop edi - mov eax, ERROR_FILE_NOT_FOUND - ret -@@: - call bdfe_to_fat_entry - pop edi - xor eax, eax - ret - -;---------------------------------------------------------------- -; -; fs_RamdiskDelete - delete file or empty folder from ramdisk -; -; esi points to filename -; -; ret eax = 0 ok or other = errormsg -; -;-------------------------------------------------------------- -fs_RamdiskDelete: - cmp byte [esi], 0 - jnz @f -; cannot delete root! -.access_denied: - push ERROR_ACCESS_DENIED -.pop_ret: - pop eax - ret -@@: - and [rd_prev_sector], 0 - and [rd_prev_prev_sector], 0 - push edi - call rd_find_lfn - jnc .found - pop edi - push ERROR_FILE_NOT_FOUND - jmp .pop_ret -.found: - cmp dword [edi], '. ' - jz .access_denied2 - cmp dword [edi], '.. ' - jz .access_denied2 - test byte [edi+11], 10h - jz .dodel -; we can delete only empty folders! - movzx eax, word [edi+26] - push ebx - mov ebx, eax - shl ebx, 9 - add ebx, RAMDISK + 31*0x200 + 2*0x20 -.checkempty: - cmp byte [ebx], 0 - jz .empty - cmp byte [ebx], 0xE5 - jnz .notempty - add ebx, 0x20 - test ebx, 0x1FF - jnz .checkempty - movzx eax, word [RAMDISK_FAT + eax*2] - test eax, eax - jz .empty - mov ebx, eax - shl ebx, 9 - add ebx, RAMDISK + 31*0x200 - jmp .checkempty -.notempty: - pop ebx -.access_denied2: - pop edi - jmp .access_denied -.empty: - pop ebx -.dodel: - movzx eax, word [edi+26] -; delete folder entry - mov byte [edi], 0xE5 -; delete LFN (if present) -.lfndel: - test edi, 0x1FF - jnz @f - cmp [rd_prev_sector], 0 + cmp ecx, [edi] jz @f - cmp [rd_prev_sector], -1 - jz .lfndone - mov edi, [rd_prev_sector] - push [rd_prev_prev_sector] - pop [rd_prev_sector] - or [rd_prev_prev_sector], -1 - shl edi, 9 - add edi, RAMDISK + 31*0x200 + 0x200 + mov al, DISK_STATUS_END_OF_MEDIA @@: - sub edi, 0x20 - cmp byte [edi], 0xE5 - jz .lfndone - cmp byte [edi+11], 0xF - jnz .lfndone - mov byte [edi], 0xE5 - jmp .lfndel -.lfndone: -; delete FAT chain - cmp eax, 2 - jb .done - cmp eax, 0xFF8 - jae .done - lea eax, [RAMDISK_FAT + eax*2] - push dword [eax] - and word [eax], 0 - pop eax - and eax, 0xFFF - jmp .lfndone -.done: - pop edi - xor eax, eax - ret +; 3. Store the actual number of sectors. + mov [edi], ecx +; 4. Calculate source and destination addresses. +if operation = 0 ; reading? + mov esi, dword [start_sector] + shl esi, 9 + add esi, RAMDISK + mov edi, [buffer] +else ; writing? + mov edi, dword [start_sector] + shl edi, 9 + add edi, RAMDISK + mov esi, [buffer] +end if +; 5. Calculate number of dwords to be transferred. + shl ecx, 9-2 +; 6. Copy data. + rep movsd +; 7. Return. The value in eax was calculated in step 2. + pop edi esi ; restore used registers to be stdcall +} -; \end{diamond} +; Reads one or more sectors from the device. +proc ramdisk_read userdata:dword, buffer:dword, start_sector:qword, numsectors_ptr:dword + ramdisk_read_write 0 + ret +endp + +; Writes one or more sectors to the device. +proc ramdisk_write userdata:dword, buffer:dword, start_sector:qword, numsectors_ptr:dword + ramdisk_read_write 1 + 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 ramdisk_adjust_cache_size + virtual at esp+4 + .userdata dd ? + .suggested_size dd ? + end virtual +; Since ramdisk does not need cache, just return 0. + xor eax, eax + retn 8 +endp diff --git a/kernel/branches/Kolibri-acpi/blkdev/rdsave.inc b/kernel/branches/Kolibri-acpi/blkdev/rdsave.inc index a5c5022fc5..23f7f06316 100644 --- a/kernel/branches/Kolibri-acpi/blkdev/rdsave.inc +++ b/kernel/branches/Kolibri-acpi/blkdev/rdsave.inc @@ -13,16 +13,19 @@ saverd_fileinfo: dd 2 ; subfunction: write dd 0 ; (reserved) dd 0 ; (reserved) - dd 1440*1024 ; size 1440 Kb +.size: + dd 0 dd RAMDISK db 0 .name: dd ? endg sysfn_saveramdisk: ; 18.6 = SAVE FLOPPY IMAGE (HD version only) - call restorefatchain mov ebx, saverd_fileinfo - mov [saverd_fileinfo.name], ecx + mov [ebx+21], ecx + mov eax, [ramdisk_actual_size] + shl eax, 9 + mov [ebx+12], eax pushad call file_system_lfn_protected ;in ebx popad diff --git a/kernel/branches/Kolibri-acpi/boot/boot_fat12.asm b/kernel/branches/Kolibri-acpi/boot/boot_fat12.asm deleted file mode 100644 index 4d6219f41e..0000000000 --- a/kernel/branches/Kolibri-acpi/boot/boot_fat12.asm +++ /dev/null @@ -1,302 +0,0 @@ -; FAT12 boot sector for Kolibri OS -; -; Copyright (C) Alex Nogueira Teixeira -; Copyright (C) Diamond -; Copyright (C) Dmitry Kartashov aka shurf -; -; Distributed under GPL, see file COPYING for details -; -; Version 1.0 - -lf equ 0ah -cr equ 0dh - -pos_read_tmp equ 0700h ;position for temporary read -boot_program equ 07c00h ;position for boot code -seg_read_kernel equ 01000h ;segment to kernel read - - jmp start_program - nop - -; Boot Sector and BPB Structure - BS_OEMName db 'KOLIBRI ' ; db 8 - BPB_BytsPerSec dw 512 ; bytes per sector - BPB_SecPerClus db 1 ; sectors per cluster - BPB_RsvdSecCnt dw 1 ; number of reserver sectors - BPB_NumFATs db 2 ; count of FAT data structures - BPB_RootEntCnt dw 224 ; count of 32-byte dir. entries (224*32 = 14 sectors) - BPB_TotSec16 dw 2880 ; count of sectors on the volume (2880 for 1.44 mbytes disk) - BPB_Media db 0f0h ; f0 - used for removable media - BPB_FATSz16 dw 9 ; count of sectors by one copy of FAT - BPB_SecPerTrk dw 18 ; sectors per track - BPB_NumHeads dw 2 ; number of heads - BPB_HiddSec dd 0 ; count of hidden sectors - BPB_TotSec32 dd 0 ; count of sectors on the volume (if > 65535) - BS_DrvNum db 0 ; int 13h drive number - BS_Reserved db 0 ; reserved - BS_BootSig db 29h ; Extended boot signature - BS_VolID dd 0 ; Volume serial number - BS_VolLab db 'KOLIBRI ' ; Volume label (db 11) - BS_FilSysType db 'FAT12 ' ; file system type (db 8) - -start_program: - - xor ax,ax - mov ss,ax - mov sp,boot_program - push ss - pop ds - - ; print loading string - mov si,loading+boot_program -loop_loading: - lodsb - or al,al - jz read_root_directory - mov ah,0eh - mov bx,7 - int 10h - jmp loop_loading - -read_root_directory: - push ss - pop es - - ; calculate some disk parameters - ; - beginning sector of RootDir - mov ax,word [BPB_FATSz16+boot_program] - xor cx,cx - mov cl,byte [BPB_NumFATs+boot_program] - mul cx - add ax,word [BPB_RsvdSecCnt+boot_program] - mov word [FirstRootDirSecNum+boot_program],ax ; 19 - mov si,ax - - ; - count of sectors in RootDir - mov bx,word [BPB_BytsPerSec+boot_program] - mov cl,5 ; divide ax by 32 - shr bx,cl ; bx = directory entries per sector - mov ax,word [BPB_RootEntCnt+boot_program] - xor dx,dx - div bx - mov word [RootDirSecs+boot_program],ax ; 14 - - ; - data start - add si,ax ; add beginning sector of RootDir and count sectors in RootDir - mov word [data_start+boot_program],si ; 33 - ; reading root directory - ; al=count root dir sectrors !!!! TODO: al, max 255 sectors !!!! - mov ah,2 ; read - push ax - - mov ax,word [FirstRootDirSecNum+boot_program] - call conv_abs_to_THS ; convert abs sector (AX) to BIOS T:H:S (track:head:sector) - pop ax - mov bx,pos_read_tmp ; es:bx read buffer - call read_sector - - mov si,bx ; read buffer address: es:si - mov ax,[RootDirSecs+boot_program] - mul word [BPB_BytsPerSec+boot_program] - add ax,si ; AX = end of root dir. in buffer pos_read_tmp - - ; find kernel file in root directory -loop_find_dir_entry: - push si - mov cx,11 - mov di,kernel_name+boot_program - rep cmpsb ; compare es:si and es:di, cx bytes long - pop si - je found_kernel_file - add si,32 ; next dir. entry - cmp si,ax ; end of directory - jb loop_find_dir_entry - -file_error_message: - mov si,error_message+boot_program - -loop_error_message: - lodsb - or al,al - jz freeze_pc - mov ah,0eh - mov bx,7 - int 10h - jmp loop_error_message - -freeze_pc: - jmp $ ; endless loop - - ; === KERNEL FOUND. LOADING... === - -found_kernel_file: - mov bp,[si+01ah] ; first cluster of kernel file - ; - mov [cluster1st+boot_program],bp ; starting cluster of kernel file - ; <\diamond> - - ; reading first FAT table - mov ax,word [BPB_RsvdSecCnt+boot_program] ; begin first FAT abs sector number - call conv_abs_to_THS ; convert abs sector (AX) to BIOS T:H:S (track:head:sector) - mov bx,pos_read_tmp ; es:bx read position - mov ah,2 ; ah=2 (read) - mov al, byte [BPB_FATSz16+boot_program] ; FAT size in sectors (TODO: max 255 sectors) - call read_sector - jc file_error_message ; read error - - mov ax,seg_read_kernel - mov es,ax - xor bx,bx ; es:bx = 1000h:0000h - - - ; reading kernel file -loop_obtains_kernel_data: - ; read one cluster of file - call obtain_cluster - jc file_error_message ; read error - - ; add one cluster length to segment:offset - push bx - mov bx,es - mov ax,word [BPB_BytsPerSec+boot_program] ;\ - movsx cx,byte [BPB_SecPerClus+boot_program] ; | !!! TODO: !!! - mul cx ; | out this from loop !!! - shr ax,4 ;/ - add bx,ax - mov es,bx - pop bx - - mov di,bp - shr di,1 - pushf - add di,bp ; di = bp * 1.5 - add di,pos_read_tmp - mov ax,[di] ; read next entry from FAT-chain - popf - jc move_4_right - and ax,0fffh - jmp verify_end_sector -move_4_right: - mov cl,4 - shr ax,cl -verify_end_sector: - cmp ax,0ff8h ; last cluster - jae execute_kernel - mov bp,ax - jmp loop_obtains_kernel_data - -execute_kernel: - ; - mov ax,'KL' - push 0 - pop ds - mov si,loader_block+boot_program - ; - push word seg_read_kernel - push word 0 - retf ; jmp far 1000:0000 - - -;------------------------------------------ - ; loading cluster from file to es:bx -obtain_cluster: - ; bp - cluster number to read - ; carry = 0 -> read OK - ; carry = 1 -> read ERROR - - ; print one dot - push bx - mov ax,0e2eh ; ah=0eh (teletype), al='.' - xor bh,bh - int 10h - pop bx - -writesec: - ; convert cluster number to sector number - mov ax,bp ; data cluster to read - sub ax,2 - xor dx,dx - mov dl,byte [BPB_SecPerClus+boot_program] - mul dx - add ax,word [data_start+boot_program] - - call conv_abs_to_THS ; convert abs sector (AX) to BIOS T:H:S (track:head:sector) -patchhere: - mov ah,2 ; ah=2 (read) - mov al,byte [BPB_SecPerClus+boot_program] ; al=(one cluster) - call read_sector - retn -;------------------------------------------ - -;------------------------------------------ - ; read sector from disk -read_sector: - push bp - mov bp,20 ; try 20 times -newread: - dec bp - jz file_error_message - push ax bx cx dx - int 13h - pop dx cx bx ax - jc newread - pop bp - retn -;------------------------------------------ - ; convert abs. sector number (AX) to BIOS T:H:S - ; sector number = (abs.sector%BPB_SecPerTrk)+1 - ; pre.track number = (abs.sector/BPB_SecPerTrk) - ; head number = pre.track number%BPB_NumHeads - ; track number = pre.track number/BPB_NumHeads - ; Return: cl - sector number - ; ch - track number - ; dl - drive number (0 = a:) - ; dh - head number -conv_abs_to_THS: - push bx - mov bx,word [BPB_SecPerTrk+boot_program] - xor dx,dx - div bx - inc dx - mov cl, dl ; cl = sector number - mov bx,word [BPB_NumHeads+boot_program] - xor dx,dx - div bx - ; !!!!!!! ax = track number, dx = head number - mov ch,al ; ch=track number - xchg dh,dl ; dh=head number - mov dl,0 ; dl=0 (drive 0 (a:)) - pop bx - retn -;------------------------------------------ - -loading db cr,lf,'Starting system ',00h -error_message db 13,10 -kernel_name db 'KERNEL MNT ?',cr,lf,00h -FirstRootDirSecNum dw ? -RootDirSecs dw ? -data_start dw ? - -; -write1st: - push cs - pop ds - mov byte [patchhere+1+boot_program], 3 ; change ah=2 to ah=3 - mov bp,[cluster1st+boot_program] - push 1000h - pop es - xor bx,bx - call writesec - mov byte [patchhere+1+boot_program], 2 ; change back ah=3 to ah=2 - retf -cluster1st dw ? -loader_block: - db 1 - dw 0 - dw write1st+boot_program - dw 0 -; <\diamond> - -times 0x1fe-$ db 00h - - db 55h,0aah ;boot signature diff --git a/kernel/branches/Kolibri-acpi/boot/booteng.inc b/kernel/branches/Kolibri-acpi/boot/booteng.inc deleted file mode 100644 index 1deb508b63..0000000000 --- a/kernel/branches/Kolibri-acpi/boot/booteng.inc +++ /dev/null @@ -1,101 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; ;; -;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; -;; Distributed under terms of the GNU General Public License ;; -;; ;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;====================================================================== -; -; BOOT DATA -; -;====================================================================== - -$Revision$ - - -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 -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 - -ask_bd db "Add disks visible by BIOS emulated in V86-mode? [1-yes, 2-no]: ",0 - -if defined extended_primary_loader -bdev db "Load ramdisk from [1-floppy; 2-kolibri.img]: ",0 -else -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 -end if - -prnotfnd db "Fatal - Videomode not found.",0 - -not386 db "Fatal - CPU 386+ required.",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 [abcd] 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 - -preboot_device_msg db " [c] Floppy image: ",0 - -if defined extended_primary_loader -preboot_device_msgs dw 0,pdm1,pdm2,0 -pdm1 db "real floppy",13,10,0 -pdm2 db "C:\kolibri.img (FAT32)",13,10,0 -else -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 -end if - -loading_msg db "Loading KolibriOS...",0 - -if ~ defined extended_primary_loader -save_quest db "Remember current settings? [y/n]: ",0 -loader_block_error db "Bootloader data invalid, I cannot continue. Stopped.",0 -end if - -_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 the system does not boot, try to disable the item [b].",0 -remarks dw remark1, remark2 -num_remarks = 2 diff --git a/kernel/branches/Kolibri-acpi/core/sys32.inc b/kernel/branches/Kolibri-acpi/core/sys32.inc index 7c9853c85b..759798b7c8 100644 --- a/kernel/branches/Kolibri-acpi/core/sys32.inc +++ b/kernel/branches/Kolibri-acpi/core/sys32.inc @@ -659,10 +659,6 @@ terminate: ; terminate application jnz @f call free_cd_channel and [cd_status], 0 -@@: - cmp [flp_status], esi - jnz @f - and [flp_status], 0 @@: pop esi cmp [bgrlockpid], esi diff --git a/kernel/branches/Kolibri-acpi/core/syscall.inc b/kernel/branches/Kolibri-acpi/core/syscall.inc index 8aa8f61cf3..b720e4baf0 100644 --- a/kernel/branches/Kolibri-acpi/core/syscall.inc +++ b/kernel/branches/Kolibri-acpi/core/syscall.inc @@ -7,20 +7,6 @@ $Revision$ -; Old style system call converter -align 16 -cross_order: - ; load all registers in crossed order - mov eax, ebx - mov ebx, ecx - mov ecx, edx - mov edx, esi - mov esi, edi - movzx edi, byte[esp+28 + 4] - sub edi, 53 - call dword [servetable+edi*4] - ret - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; ;; SYSENTER ENTRY ;; @@ -109,24 +95,6 @@ iglobal ;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; SYSTEM FUNCTIONS TABLE ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - align 4 - servetable: - dd 0 - dd 0 - dd 0 - dd 0 - dd 0 - dd file_system ; 58-Common file system interface - dd 0 - dd 0 - dd 0 - dd 0 - dd 0 - - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - ;; NEW SYSTEM FUNCTIONS TABLE ;; - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; align 4 servetable2: @@ -136,7 +104,7 @@ iglobal dd sys_clock ; 3-GetTime dd syscall_writetext ; 4-WriteText dd delay_hs_unprotected ; 5-DelayHs - dd syscall_openramdiskfile ; 6-OpenRamdiskFile + dd undefined_syscall ; 6-deprecated OpenRamdiskFile dd syscall_putimage ; 7-PutImage dd syscall_button ; 8-DefineButton dd sys_cpuusage ; 9-GetProcessInfo @@ -188,7 +156,7 @@ iglobal dd sound_interface ; 55-Sound interface dd undefined_syscall ; 56-reserved dd sys_pcibios ; 57-PCI BIOS32 - dd cross_order ; 58-Common file system interface + dd undefined_syscall ; 58-deprecated Common file system interface dd undefined_syscall ; 59-reserved dd sys_IPC ; 60-Inter Process Communication dd sys_gs ; 61-Direct graphics access diff --git a/kernel/branches/Kolibri-acpi/data32.inc b/kernel/branches/Kolibri-acpi/data32.inc index 485711f3d4..6bfc67cfcc 100644 --- a/kernel/branches/Kolibri-acpi/data32.inc +++ b/kernel/branches/Kolibri-acpi/data32.inc @@ -51,7 +51,7 @@ keymap_alt: if lang eq ru boot_initirq cp866 'Инициализация IRQ',0 boot_picinit cp866 'Инициализация PIC',0 - boot_v86machine cp866 'Инициализация системы V86 машины',0 + boot_v86machine cp866 'Инициализация системной V86 машины',0 boot_inittimer cp866 'Инициализация системного таймера (IRQ0)',0 boot_initapic cp866 'Попытка инициализации APIC',0 boot_enableirq cp866 'Включить прерывания 2, 13',0 @@ -69,6 +69,7 @@ if lang eq ru boot_cpuid cp866 'Чтение CPUIDs',0 ; boot_devices cp866 'Поиск устройств',0 boot_timer cp866 'Установка таймера',0 + boot_initramdisk cp866 'Инициализация рамдиска',0 boot_irqs cp866 'Переопределение IRQ',0 boot_setmouse cp866 'Установка мыши',0 boot_windefs cp866 'Установка настроек окон по умолчанию',0 @@ -98,6 +99,7 @@ else boot_picinit db 'Initialize PIC',0 boot_v86machine db 'Initialize system V86 machine',0 boot_inittimer db 'Initialize system timer (IRQ0)',0 + boot_initramdisk db 'Initialize ramdisk',0 boot_initapic db 'Try to initialize APIC',0 boot_enableirq db 'Enable interrupts 2, 13',0 boot_disabling_ide db 'Disable interrupts in IDE controller',0 @@ -172,7 +174,13 @@ end if vmode db '/sys/drivers/VMODE.MDR',0 ;vrr_m db 'VRR_M',0 -kernel_file db 'KERNEL MNT' +kernel_file_load: +; load kernel.mnt to 0x7000:0 + dd 0 ; subfunction + dq 0 ; offset in file + dd 0x30000 ; number of bytes to read + dd OS_BASE + 0x70000 ; buffer for data + db '/RD/1/KERNEL.MNT',0 dev_data_path db '/RD/1/DRIVERS/DEVICES.DAT',0 @@ -570,8 +578,7 @@ end if org (OS_BASE+0x0100000) RAMDISK: rb 2880*512 -RAMDISK_FAT: rb 2856*2 -FLOPPY_FAT: rb 2856*2 + rb 2856*4 ; not used _CLEAN_ZONE: diff --git a/kernel/branches/Kolibri-acpi/data32et.inc b/kernel/branches/Kolibri-acpi/data32et.inc index ceb3ce3d55..63d9573f25 100644 --- a/kernel/branches/Kolibri-acpi/data32et.inc +++ b/kernel/branches/Kolibri-acpi/data32et.inc @@ -2,6 +2,7 @@ boot_picinit latin1 'Algväärtustan PIC',0 boot_v86machine latin1 'Algväärtustan süsteemi V86 masinat',0 boot_inittimer latin1 'Algväärtustan süsteemi taimerit (IRQ0)',0 + boot_initramdisk latin1 'Initialize ramdisk',0 boot_initapic latin1 'Proovin Algväärtustada APIC',0 boot_enableirq latin1 'Luban katkestused 2, 13',0 boot_disabling_ide latin1 'Keelan IDE kontrolleri katkestused',0 diff --git a/kernel/branches/Kolibri-acpi/data32sp.inc b/kernel/branches/Kolibri-acpi/data32sp.inc index 040b151619..a0b25b4e97 100644 --- a/kernel/branches/Kolibri-acpi/data32sp.inc +++ b/kernel/branches/Kolibri-acpi/data32sp.inc @@ -2,6 +2,7 @@ boot_picinit: cp850 'Inicializar PIC',0 boot_v86machine: cp850 'Inicializar sistema V86',0 boot_inittimer: cp850 'Inicializar reloj del sistema (IRQ0)',0 + boot_initramdisk cp850 'Initialize ramdisk',0 boot_initapic: cp850 'Prueba inicializar APIC',0 boot_enableirq: cp850 'Habilitar interrupciones 2, 13',0 boot_disabling_ide:cp850 'Habiliar interrupciones en controladores IDE',0 diff --git a/kernel/branches/Kolibri-acpi/detect/dev_fd.inc b/kernel/branches/Kolibri-acpi/detect/dev_fd.inc index fdd2b21979..2d34b110fd 100644 --- a/kernel/branches/Kolibri-acpi/detect/dev_fd.inc +++ b/kernel/branches/Kolibri-acpi/detect/dev_fd.inc @@ -33,5 +33,6 @@ wait_cmos: stdcall attach_int_handler, 6, FDCInterrupt, 0 DEBUGF 1, "K : Set IDE IRQ6 return code %x\n", eax + call floppy_init @@: diff --git a/kernel/branches/Kolibri-acpi/detect/vortex86.inc b/kernel/branches/Kolibri-acpi/detect/vortex86.inc index 06aa9d3c94..a94ae96313 100644 --- a/kernel/branches/Kolibri-acpi/detect/vortex86.inc +++ b/kernel/branches/Kolibri-acpi/detect/vortex86.inc @@ -36,14 +36,20 @@ Vortex86SoClist: ; List of Vortex86 CPUs known today. Add Vortex86SoCnum = ($ - Vortex86SoClist) / 4 ; Calculate the total number of known Vortex86 CPUs (if id=Vortex86SoCnum+1 --> unknown SoC) endg +; When in debug mode, perform SoC detection regardless of the actual CPU vendor (even for vendors other than DMP) +; When in normal (not debug) mode, check the CPU vendor first, and perform SoC detection only if vendor is 'Vortex86 SoC' +if ~ VORTEX86DEBUG + cmp [cpu_vendor], 'Vort' + jnz .Vortex86end ; If the CPU vendor is not 'Vortex86 SoC', skip the SoC detection +end if + mov dx, 0xcf8 ; CF8h = Vortex86 PCI Configuration Address port mov eax, 0x80000090 ; 0x80000090 = Starting PCI address to read from (32-bit register - accessed as DWORD) out dx, eax ; Send request to PCI address port to retrieve data from this address mov dx, 0xcfc ; CFCh = Vortex86 PCI Configuration Data port in eax, dx ; Read data (SoC type) from PCI data port -if VORTEX86DEBUG -; // Used for debug purposes: testing in emulator and in non-Vortex86 CPU computers +if VORTEX86DEBUG ; When in debug mode, pretend that we received port output equal to "VORTEX86DEBUGVALUE" mov eax, VORTEX86DEBUGVALUE end if @@ -55,10 +61,9 @@ end if cmp ax, 4d44h ; Check whether it's Vortex86 family (all Vortex86 SoC have ID in form of "0xNN504d44") jnz .notVortex86 shr eax, 16 ; Discard lower word in EAX which is always 4d44h in Vortex86 family - cmp al, 50h ; The 3rd byte is always 50h in Vortex86 SoC + cmp al, 50h ; The 3rd byte is always 50h in Vortex86 SoC (if this is the case, we need just the highest byte) jnz .notVortex86 - shr ax, 8 ; Discard 3rd byte in EAX, the highest byte determines the SoC type - mov bl, al ; Copy SoC type to BL since EAX (that contains AL) is used implicitly in "LODSD" command below + mov bl, ah ; Copy SoC type to BL since EAX (that includes AH) is used implicitly in "LODSD" command below mov esi, Vortex86SoClist ; ESI points to the start of Vortex86SoClist (used implicitly in "LODSD" command below) xor ecx, ecx ; Zero ECX (it is used as counter) cld ; Clears the DF flag in the EFLAGS register (DF=0 --> String operations increment ESI) @@ -83,7 +88,7 @@ end if .unknownVortex86: mov [Vortex86CPUid], cl ; Save the CPUid (Vortex86SoCnum+1=Unknown Vortex86) - DEBUGF 1, "unknown Vortex86 CPU (has id=%d, last known is %d)\n", [Vortex86CPUid]:1, Vortex86SoCnum + DEBUGF 1, "unknown Vortex86 CPU (id=%d, last known is %d)\n", [Vortex86CPUid]:1, Vortex86SoCnum jmp .Vortex86end .notVortex86: ; In case this register is used by other CPUs for other purpose, it's interesting what it contains diff --git a/kernel/branches/Kolibri-acpi/drivers/agp.asm b/kernel/branches/Kolibri-acpi/drivers/agp.asm new file mode 100644 index 0000000000..9764da85ba --- /dev/null +++ b/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 ? + diff --git a/kernel/branches/Kolibri-acpi/drivers/apm.asm b/kernel/branches/Kolibri-acpi/drivers/apm.asm new file mode 100644 index 0000000000..3c68ed58fe --- /dev/null +++ b/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: diff --git a/kernel/branches/Kolibri-acpi/drivers/fdo.inc b/kernel/branches/Kolibri-acpi/drivers/fdo.inc new file mode 100644 index 0000000000..4cb60e0c46 --- /dev/null +++ b/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 + 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 + 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 + if ~_hex eq eax + mov eax, _hex + end if + mov edx, 8 + else if _hex in + if ~_hex eq ax + movzx eax, _hex + end if + if (_num eq) + mov edx, 4 + end if + else if _hex in + 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 +} diff --git a/kernel/branches/Kolibri-acpi/drivers/usb/urb.inc b/kernel/branches/Kolibri-acpi/drivers/usb/urb.inc deleted file mode 100644 index 471aae6553..0000000000 --- a/kernel/branches/Kolibri-acpi/drivers/usb/urb.inc +++ /dev/null @@ -1,121 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; ;; -;; Copyright (C) KolibriOS team 2007-2011. All rights reserved. ;; -;; Distributed under terms of the GNU General Public License ;; -;; ;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -struc URB -{ - .fd dd ? - .bk dd ? - .dev dd ? ; pointer to associated device - .pipe dd ? ; pipe information - .status dd ? ; non-ISO status - .transfer_flags dd ? ; URB_SHORT_NOT_OK | ... - .transfer_buffer dd ? ; associated data buffer - .transfer_dma dd ? ; dma addr for transfer_buffer - .transfer_buffer_length dd ? ; data buffer length - .actual_length dd ? ; actual transfer length - .setup_packet dd ? ; setup packet (control only) - .setup_dma dd ? ; dma addr for setup_packet - .start_frame dd ? ; start frame (ISO) - .number_of_packets dd ? ; number of ISO packets - .interval dd ? ; transfer interval - - .error_count dd ? ; number of ISO errors - .context dd ? ; context for completion - .complete dd ? ; (in) completion routine - .iso_frame_desc: -} - -virtual at 0 - URB URB -end virtual - - -struc REQ ;usb request -{ - .request_type db ? - .request db ? - .value dw ? - .index dw ? - .length dw ? -} - -virtual at 0 - REQ REQ -end virtual - -align 4 -proc usb_control_msg stdcall, dev:dword, pipe:dword, request:dword,\ - requesttype:dword, value:dword, index:dword,\ - data:dword, size:dword, timeout:dword - - locals - req REQ - endl - - lea eax, [req] - mov ecx, [request] - mov ebx, [requesttupe] - mov edx, [value] - mov esi, [index] - mov edi, [size] - - mov [eax+REQ.request_type], bl - mov [eax+REQ.request], cl - mov [eax+REQ.value], dx - mov [eax+REQ.index], si - mov [eax+REQ.length], di - - stdcall usb_internal_control_msg, [dev], [pipe], \ - eax, [data], [size], [timeout] - - ret -endp - - -; returns status (negative) or length (positive) -static int usb_internal_control_msg(struct usb_device *usb_dev, - unsigned int pipe, - struct usb_ctrlrequest *cmd, - void *data, int len, int timeout) -{ - struct urb *urb; - int retv; - int length; - - urb = usb_alloc_urb(0, GFP_NOIO); - if (!urb) - return -ENOMEM; - usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char *)cmd, data, - len, usb_api_blocking_completion, NULL); - - retv = usb_start_wait_urb(urb, timeout, &length); - if (retv < 0) - return retv; - else - return length; -} - - -;void usb_fill_control_urb (struct urb *urb, -; struct usb_device *dev, -; unsigned int pipe, -; unsigned char *setup_packet, -; void *transfer_buffer, -; int buffer_length, -; usb_complete_t complete_fn, -; void *context) -;{ -; -; urb->dev = dev; -; urb->pipe = pipe; -; urb->setup_packet = setup_packet; -; urb->transfer_buffer = transfer_buffer; -; urb->transfer_buffer_length = buffer_length; -; urb->complete = complete_fn; -; urb->context = context; -;} -; diff --git a/kernel/branches/Kolibri-acpi/drivers/usb/usb.asm b/kernel/branches/Kolibri-acpi/drivers/usb/usb.asm deleted file mode 100644 index 88e4679782..0000000000 --- a/kernel/branches/Kolibri-acpi/drivers/usb/usb.asm +++ /dev/null @@ -1,435 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; ;; -;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; -;; Distributed under terms of the GNU General Public License ;; -;; ;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;driver sceletone - -format MS COFF - -API_VERSION equ 0 ;debug - -include '../proc32.inc' -include '../imports.inc' -include 'urb.inc' - -struc UHCI -{ - .bus dd ? - .devfn dd ? - .io_base dd ? - .mm_base dd ? - .irq dd ? - .flags dd ? - .reset dd ? - .start dd ? - .stop dd ? - - .port_c_suspend dd ? - .resuming_ports dd ? - .rh_state dd ? - .rh_numports dd ? - .is_stopped dd ? - .dead dd ? - - .sizeof: -} - -virtual at 0 - UHCI UHCI -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 - -struc TD ;transfer descriptor -{ - .link dd ? - .status dd ? - .token dd ? - .buffer dd ? - - .addr dd ? - .frame dd ? - .fd dd ? - .bk dd ? - .sizeof: -} - -virtual at 0 - TD TD -end virtual - -public START -public service_proc -public version - -DEBUG equ 1 - -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 - - call init - - 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 ? - 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, 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: - mov eax, UHCI.sizeof - call Kmalloc - test eax, eax - jz .mem_fail - - mov ebx, [bus] - mov [eax+UHCI.bus], ebx - - mov ecx, [devfn] - mov [eax+UHCI.devfn], ecx - ret -.mem_fail: - if DEBUG - mov esi, msgMemFail - call SysMsgBoardStr - end if -.err: - xor eax, eax - ret -endp - -PCI_BASE equ 0x20 -USB_LEGKEY equ 0xC0 - -align 4 -proc init - locals - uhci dd ? - endl - - call detect - test eax, eax - jz .fail - - mov [uhci], eax - - stdcall PciRead32, [eax+UHCI.bus], [eax+UHCI.devfn], PCI_BASE - and eax, 0xFFC0 - mov esi, [uhci] - mov [esi+UHCI.io_base], eax - - stdcall uhci_reset, esi - - stdcall finish_reset, [uhci] - -.fail: - if DEBUG - mov esi, msgDevNotFound - call SysMsgBoardStr - end if - ret -endp - -UHCI_USBINTR equ 4 ; interrupt register - -UHCI_USBLEGSUP_RWC equ 0x8f00 ; the R/WC bits -UHCI_USBLEGSUP_RO equ 0x5040 ; R/O and reserved bits - -UHCI_USBCMD_RUN equ 0x0001 ; RUN/STOP bit -UHCI_USBCMD_HCRESET equ 0x0002 ; Host Controller reset -UHCI_USBCMD_EGSM equ 0x0008 ; Global Suspend Mode -UHCI_USBCMD_CONFIGURE equ 0x0040 ; Config Flag -UHCI_USBINTR_RESUME equ 0x0002 ; Resume interrupt enable - -PORTSC0 equ 0x10 -PORTSC1 equ 0x12 - - -UHCI_RH_RESET equ 0 -UHCI_RH_SUSPENDED equ 1 -UHCI_RH_AUTO_STOPPED equ 2 -UHCI_RH_RESUMING equ 3 - -; In this state the HC changes from running to halted -; so it can legally appear either way. -UHCI_RH_SUSPENDING equ 4 - -; In the following states it's an error if the HC is halted. -; These two must come last. -UHCI_RH_RUNNING equ 5 ; The normal state -UHCI_RH_RUNNING_NODEVS equ 6 ; Running with no devices - -UHCI_IS_STOPPED equ 9999 - -align 4 -proc uhci_reset stdcall, uhci:dword - mov esi, [uhci] - stdcall PciRead16, [esi+UHCI.bus], [esi+UHCI.devfn], USB_LEGKEY - test eax, not (UHCI_USBLEGSUP_RO or UHCI_USBLEGSUP_RWC) - jnz .reset - - mov edx, [esi+UHCI.io_base] - in ax, dx - test ax, UHCI_USBCMD_RUN - jnz .reset - - test ax, UHCI_USBCMD_CONFIGURE - jz .reset - - test ax, UHCI_USBCMD_EGSM - jz .reset - - add edx, UHCI_USBINTR - in ax, dx - test ax, not UHCI_USBINTR_RESUME - jnz .reset - ret -.reset: - stdcall PciWrite16, [esi+UHCI.bus], [esi+UHCI.devfn], USB_LEGKEY, UHCI_USBLEGSUP_RWC - - mov edx, [esi+UHCI.io_base] - mov ax, UHCI_USBCMD_HCRESET - out dx, ax - - xor eax, eax - out dx, ax - add edx, UHCI_USBINTR - out dx, ax - ret -endp - -proc finish_reset stdcall, uhci:dword - - mov esi, [uhci] - mov edx, [esi+UHCI.io_base] - add edx, PORTSC0 - xor eax, eax - out dx, ax - add edx, (PORTSC1-PORTSC0) - out dx, ax - - mov [esi+UHCI.port_c_suspend], eax - mov [esi+UHCI.resuming_ports], eax - mov [esi+UHCI.rh_state], UHCI_RH_RESET - mov [esi+UHCI.rh_numports], 2 - - mov [esi+UHCI.is_stopped], UHCI_IS_STOPPED - ; mov [ uhci_to_hcd(uhci)->state = HC_STATE_HALT; - ; uhci_to_hcd(uhci)->poll_rh = 0; - - mov [esi+UHCI.dead], eax ; Full reset resurrects the controller - - ret -endp - -proc insert_td stdcall, td:dword, frame:dword - - mov edi, [td] - mov eax, [frame] - and eax, -1024 - mov [edi+TD.frame], eax - - mov ebx, [framelist] - mov edx, [dma_framelist] - shl eax, 5 - - mov ecx, [eax+ebx] - test ecx, ecx - jz .empty - - mov ecx, [ecx+TD.bk] ;last TD - - mov edx, [ecx+TD.fd] - mov [edi+TD.fd], edx - mov [edi+TD.bk], ecx - mov [ecx+TD.fd], edi - mov [edx+TD.bk], edi - - mov eax, [ecx+TD.link] - mov [edi+TD.link], eax - mov ebx, [edi+TD.addr] - mov [ecx+TD.link], ebx - ret -.empty: - mov ecx, [eax+edx] - mov [edi+TD.link], ecx - mov [ebx+eax], edi - mov ecx, [edi+TD.addr] - mov [eax+edx], ecx - ret -endp - - -align 4 -proc usb_get_descriptor stdcall, dev:dword, type:dword, index:dword,\ - buf:dword, size:dword - - locals - count dd ? - endl - - mov esi, [buf] - mov ecx, [size] - xor eax, eax - cld - rep stosb - - mov [count], 3 -@@: - mov eax, [type] - shl eax, 8 - add eax, [index] - stdcall usb_control_msg, [dev], pipe, USB_REQ_GET_DESCRIPTOR, \ - USB_DIR_IN, eax,0,[buf], [size],\ - USB_CTRL_GET_TIMEOUT - test eax, eax - jz .next - cmp eax, -1 - je .next - jmp. ok -.next: - dec [count] - jnz @B - mov eax, -1 -.ok: - ret -endp - -DEVICE_ID equ 0x24D2 ; pci device id -VENDOR_ID equ 0x8086 ; device vendor id -QEMU_USB equ 0x7020 - -;all initialized data place here - -align 4 -devices dd (DEVICE_ID shl 16)+VENDOR_ID - dd (QEMU_USB shl 16)+VENDOR_ID - dd 0 ;terminator - -version dd (5 shl 16) or (API_VERSION and 0xFFFF) - -my_service db 'UHCI',0 ;max 16 chars include zero - -msgInit db 'detect hardware...',13,10,0 -msgPCI db 'PCI accsess not supported',13,10,0 -msgDevNotFound db 'device not found',13,10,0 -msgMemFail db 'Kmalloc failed', 10,10,0 -;msgFail db 'device not found',13,10,0 - -section '.data' data readable writable align 16 - -;all uninitialized data place here - diff --git a/kernel/branches/Kolibri-acpi/drivers/usbhid.asm b/kernel/branches/Kolibri-acpi/drivers/usbhid.asm deleted file mode 100644 index 76c7f2ae4b..0000000000 --- a/kernel/branches/Kolibri-acpi/drivers/usbhid.asm +++ /dev/null @@ -1,693 +0,0 @@ -; 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' - -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 - -; Driver data for all devices -virtual at 0 -device_data: -.type dd ? ; 1 = keyboard, 2 = mouse -.intpipe dd ? ; interrupt pipe handle -.packetsize dd ? -.packet rb 8 ; packet with data from device -.control rb 8 ; control packet to device -.sizeof: -end virtual - -; Driver data for mouse -virtual at device_data.sizeof -mouse_data: -; no additional data -.sizeof: -end virtual - -; Driver data for keyboard -virtual at device_data.sizeof -keyboard_data: -.handle dd ? ; keyboard handle from RegKeyboard -.configpipe dd ? ; config pipe handle -.prevpacket rb 8 ; previous packet with data from device -.timer dd ? ; auto-repeat timer handle -.repeatkey db ? ; auto-repeat key code -.ledstate db ? ; state of LEDs - align 4 -.sizeof: -end virtual - -section '.flat' code readable align 16 -; The start procedure. -START: -; 1. Test whether the procedure is called with the argument DRV_ENTRY. -; If not, return 0. - xor eax, eax ; initialize return value - cmp dword [esp+4], 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 - -; This procedure is called when new HID device is detected. -; It initializes the device. -AddDevice: -; Arguments are addressed through esp. In this point of the function, -; [esp+4] = a handle of the config pipe, [esp+8] points to config_descr -; structure, [esp+12] points to interface_descr structure. -; 1. Check device type. Currently only mice and keyboards with -; boot protocol 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 edx, [esp+12] - push ebx ; save used register to be stdcall - mov cx, word [edx+interface_descr.bInterfaceSubClass] -; 1b. For boot protocol, subclass must be 1 and protocol must be either 1 for -; a keyboard or 2 for a mouse. Check. - cmp cx, 0x0101 - jz .keyboard - cmp cx, 0x0201 - jz .mouse -; 1c. If the device is neither a keyboard nor a mouse, print a message and -; go to 6c. - DEBUGF 1,'K : unknown HID device\n' - jmp .nothing -; 1d. If the device is a keyboard or a mouse, print a message and continue -; configuring. -.keyboard: - DEBUGF 1,'K : USB keyboard detected\n' - push keyboard_data.sizeof - jmp .common -.mouse: - DEBUGF 1,'K : USB mouse detected\n' - push mouse_data.sizeof -.common: -; 2. Allocate memory for device data. - pop eax ; get size of device data -; 2a. Call the kernel, saving and restoring register edx. - push edx - call Kmalloc - pop edx -; 2b. Check result. If failed, say a message and go to 6c. - test eax, eax - jnz @f - DEBUGF 1,'K : no memory\n' - jmp .nothing -@@: - xchg eax, ebx -; 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. -; 3. Get the upper bound of all descriptors' data. - mov eax, [esp+8+4] ; configuration descriptor - movzx ecx, [eax+config_descr.wTotalLength] - add eax, 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 endpoint descriptor found. -; 4a. Loop start: eax points to the interface descriptor. -.lookep: -; 4b. Get next descriptor. - movzx ecx, byte [edx] ; the first byte of all descriptors is length - add edx, ecx -; 4c. Check that at least two bytes are readable. The opposite is an error. - inc edx - cmp edx, eax - jae .errorep - dec edx -; 4d. Check that this descriptor is not interface descriptor. The opposite is -; an error. - cmp byte [edx+endpoint_descr.bDescriptorType], INTERFACE_DESCR_TYPE - jz .errorep -; 4e. Test whether this descriptor is an endpoint descriptor. If not, continue -; the loop. - cmp byte [edx+endpoint_descr.bDescriptorType], ENDPOINT_DESCR_TYPE - jnz .lookep -; 5. Check that the descriptor contains all required data and all data are -; readable. If so, proceed to 7. - cmp byte [edx+endpoint_descr.bLength], endpoint_descr.sizeof - jb .errorep - sub eax, endpoint_descr.sizeof - cmp edx, eax - jbe @f -; 6. An error occured during processing endpoint descriptor. -.errorep: -; 6a. Print a message. - DEBUGF 1,'K : error: invalid endpoint descriptor\n' -; 6b. Free memory allocated for device data. -.free: - xchg eax, ebx - call Kfree -.nothing: -; 6c. Return an error. - xor eax, eax - pop ebx - ret 12 -@@: -; 7. Check that the endpoint is IN interrupt endpoint. If not, go to 6. - test [edx+endpoint_descr.bEndpointAddress], 80h - jz .errorep - mov cl, [edx+endpoint_descr.bmAttributes] - and cl, 3 - cmp cl, INTERRUPT_PIPE - jnz .errorep -; 8. Open pipe for the endpoint. -; 8a. Load parameters from the descriptor. - movzx ecx, [edx+endpoint_descr.bEndpointAddress] - movzx eax, [edx+endpoint_descr.bInterval] - movzx edx, [edx+endpoint_descr.wMaxPacketSize] -; 8b. Call the kernel, saving and restoring edx. - push edx - stdcall USBOpenPipe, [esp+4+24], ecx, edx, INTERRUPT_PIPE, eax - pop edx -; 8c. Check result. If failed, go to 6b. - test eax, eax - jz .free -; We use 12 bytes for device type, interrupt pipe and interrupt packet size, -; 8 bytes for a packet and 8 bytes for previous packet, used by a keyboard. -; 9. Initialize device data. - mov [ebx+device_data.intpipe], eax - movi ecx, 8 - cmp edx, ecx - jb @f - mov edx, ecx -@@: - xor eax, eax - mov [ebx+device_data.packetsize], edx - mov dword [ebx+device_data.packet], eax - mov dword [ebx+device_data.packet+4], eax - mov edx, [esp+12+4] ; interface descriptor - movzx ecx, [edx+interface_descr.bInterfaceProtocol] - mov [ebx+device_data.type], ecx - cmp ecx, 1 - jnz @f - mov [ebx+keyboard_data.handle], eax - mov [ebx+keyboard_data.timer], eax - mov [ebx+keyboard_data.repeatkey], al - mov dword [ebx+keyboard_data.prevpacket], eax - mov dword [ebx+keyboard_data.prevpacket+4], eax - mov eax, [esp+4+4] - mov [ebx+keyboard_data.configpipe], eax -@@: -; 10. Send the control packet SET_PROTOCOL(Boot Protocol) to the interface. - lea eax, [ebx+device_data.control] - mov dword [eax], 21h + (0Bh shl 8) + (0 shl 16) ; class request to interface + SET_PROTOCOL + Boot protocol - and dword [eax+4], 0 - mov dl, [edx+interface_descr.bInterfaceNumber] - mov [eax+4], dl -; Callback function is mouse_configured for mice and keyboard_configured1 for keyboards. - mov edx, keyboard_configured1 - cmp ecx, 1 - jz @f - mov edx, mouse_configured -@@: - stdcall USBControlTransferAsync, [esp+4+28], eax, 0, 0, edx, ebx, 0 -; 11. Return with pointer to device data as returned value. - xchg eax, ebx - pop ebx - ret 12 - -; This function is called when SET_PROTOCOL command for keyboard is done, -; either successful or unsuccessful. -keyboard_configured1: - xor edx, edx -; 1. Check the status of the transfer. -; If the transfer was failed, go to the common error handler. - cmp dword [esp+8], edx ; status is zero? - jnz keyboard_data_ready.error -; 2. Send the control packet SET_IDLE(infinity). HID auto-repeat is not useful. - mov eax, [esp+20] - push edx ; flags for USBControlTransferAsync - push eax ; userdata for USBControlTransferAsync - add eax, device_data.control - mov dword [eax], 21h + (0Ah shl 8) + (0 shl 24) ; class request to interface + SET_IDLE + no autorepeat - stdcall USBControlTransferAsync, dword [eax+keyboard_data.configpipe-device_data.control], \ - eax, edx, edx, keyboard_configured2; , , -; 3. Return. - ret 20 - -; This function is called when SET_IDLE command for keyboard is done, -; either successful or unsuccessful. -keyboard_configured2: -; Check the status of the transfer and go to the corresponding label -; in the main handler. - cmp dword [esp+8], 0 - jnz keyboard_data_ready.error - mov edx, [esp+20] - push edx - stdcall RegKeyboard, usbkbd_functions, edx - pop edx - mov [edx+keyboard_data.handle], eax - jmp keyboard_data_ready.next - -; This function is called when another interrupt packet arrives, -; processed either successfully or unsuccessfully. -; It should parse the packet and initiate another transfer with -; the same callback function. -keyboard_data_ready: -; 1. Check the status of the transfer. - mov eax, [esp+8] - test eax, eax - jnz .error -; Parse the packet, comparing with the previous packet. -; For boot protocol, USB keyboard packet consists of the first byte -; with status keys that are currently pressed. The second byte should -; be ignored, and other 5 bytes denote keys that are currently pressed. - push esi ebx ; save used registers to be stdcall -; 2. Process control keys. -; 2a. Initialize before loop for control keys. edx = mask for control bits -; that were changed. - mov ebx, [esp+20+8] - movzx edx, byte [ebx+device_data.packet] ; get state of control keys - xor dl, byte [ebx+keyboard_data.prevpacket] ; compare with previous state -; 2b. If state of control keys has not changed, advance to 3. - jz .nocontrol -; 2c. Otherwise, loop over control keys; esi = bit number. - xor esi, esi -.controlloop: -; 2d. Skip bits that have not changed. - bt edx, esi - jnc .controlnext - push edx ; save register which is possibly modified by API -; The state of the current control key has changed. -; 2e. For extended control keys, send the prefix 0xE0. - mov al, [control_keys+esi] - test al, al - jns @f - push eax - mov ecx, 0xE0 - call SetKeyboardData - pop eax - and al, 0x7F -@@: -; 2f. If the current state of the control key is "pressed", send normal -; scancode. Otherwise, the key is released, so set the high bit in scancode. - movzx ecx, al - bt dword [ebx+device_data.packet], esi - jc @f - or cl, 0x80 -@@: - call SetKeyboardData - pop edx ; restore register which was possibly modified by API -.controlnext: -; 2g. We have 8 control keys. - inc esi - cmp esi, 8 - jb .controlloop -.nocontrol: -; 3. Initialize before loop for normal keys. esi = index. - movi esi, 2 -.normalloop: -; 4. Process one key which was pressed in the previous packet. -; 4a. Get the next pressed key from the previous packet. - movzx eax, byte [ebx+esi+keyboard_data.prevpacket] -; 4b. Ignore special codes. - cmp al, 3 - jbe .normalnext1 -; 4c. Ignore keys that are still pressed in the current packet. - lea ecx, [ebx+device_data.packet] - call haskey - jz .normalnext1 -; 4d. Say warning about keys with strange codes. - cmp eax, normal_keys_number - jae .badkey1 - movzx ecx, [normal_keys+eax] - jecxz .badkey1 -; 4e. For extended keys, send the prefix 0xE0. - push ecx ; save keycode - test cl, cl - jns @f - push ecx - mov ecx, 0xE0 - call SetKeyboardData - pop ecx -@@: -; 4f. Send the release event. - or cl, 0x80 - call SetKeyboardData -; 4g. If this key is autorepeating, stop the timer. - pop ecx ; restore keycode - cmp cl, [ebx+keyboard_data.repeatkey] - jnz .normalnext1 - mov eax, [ebx+keyboard_data.timer] - test eax, eax - jz .normalnext1 - stdcall CancelTimerHS, eax - and [ebx+keyboard_data.timer], 0 - jmp .normalnext1 -.badkey1: - DEBUGF 1,'K : unknown keycode: %x\n',al -.normalnext1: -; 5. Process one key which is pressed in the current packet. -; 5a. Get the next pressed key from the current packet. - movzx eax, byte [ebx+esi+device_data.packet] -; 5b. Ignore special codes. - cmp al, 3 - jbe .normalnext2 -; 5c. Ignore keys that were already pressed in the previous packet. - lea ecx, [ebx+keyboard_data.prevpacket] - call haskey - jz .normalnext2 -; 5d. Say warning about keys with strange codes. - cmp eax, normal_keys_number - jae .badkey2 - movzx ecx, [normal_keys+eax] - jecxz .badkey2 -; 5e. For extended keys, send the prefix 0xE0. - push ecx ; save keycode - test cl, cl - jns @f - push ecx - mov ecx, 0xE0 - call SetKeyboardData - pop ecx -@@: -; 5f. Send the press event. - and cl, not 0x80 - call SetKeyboardData -; 5g. Stop the current auto-repeat timer, if present. - mov eax, [ebx+keyboard_data.timer] - test eax, eax - jz @f - stdcall CancelTimerHS, eax -@@: -; 5h. Start the auto-repeat timer. - pop ecx ; restore keycode - mov [ebx+keyboard_data.repeatkey], cl - stdcall TimerHS, 25, 5, autorepeat_timer, ebx - mov [ebx+keyboard_data.timer], eax - jmp .normalnext2 -.badkey2: - DEBUGF 1,'K : unknown keycode: %x\n',al -.normalnext2: -; 6. Advance to next key. - inc esi - cmp esi, 8 - jb .normalloop -; 7. Save the packet data for future reference. - mov eax, dword [ebx+device_data.packet] - mov dword [ebx+keyboard_data.prevpacket], eax - mov eax, dword [ebx+device_data.packet+4] - mov dword [ebx+keyboard_data.prevpacket+4], eax - pop ebx esi ; restore registers to be stdcall -.next: -; 8. Initiate transfer on the interrupt pipe. - mov eax, [esp+20] - push 1 ; flags for USBNormalTransferAsync - push eax ; userdata for USBNormalTransferAsync - add eax, device_data.packet - stdcall USBNormalTransferAsync, dword [eax+device_data.intpipe-device_data.packet], \ - eax, dword [eax+device_data.packetsize-device_data.packet], \ - keyboard_data_ready;, , -; 9. Return. -.nothing: - ret 20 -.error: -; An error has occured. -; 10. If an error is caused by the disconnect, do nothing, it is handled -; in DeviceDisconnected. Otherwise, say a message. - cmp eax, 16 - jz @f - push esi - mov esi, errormsgkbd - call SysMsgBoardStr - pop esi -@@: - ret 20 - -; Auxiliary procedure for keyboard_data_ready. -haskey: - movi edx, 2 -@@: - cmp byte [ecx+edx], al - jz @f - inc edx - cmp edx, 7 - jbe @b -@@: - ret - -; Timer function for auto-repeat. -autorepeat_timer: - mov eax, [esp+4] - movzx ecx, [eax+keyboard_data.repeatkey] - test cl, cl - jns @f - push ecx - mov ecx, 0xE0 - call SetKeyboardData - pop ecx - and cl, not 0x80 -@@: - call SetKeyboardData - ret 4 - -; This function is called to update LED state on the keyboard. -SetKeyboardLights: - mov eax, [esp+4] - add eax, device_data.control - mov dword [eax], 21h + (9 shl 8) + (2 shl 24) - ; class request to interface + SET_REPORT + Output zero report - mov byte [eax+6], 1 - mov edx, [esp+8] - shr dl, 1 - jnc @f - or dl, 4 -@@: - lea ecx, [eax+keyboard_data.ledstate-device_data.control] - mov [ecx], dl - stdcall USBControlTransferAsync, dword [eax+keyboard_data.configpipe-device_data.control], \ - eax, ecx, 1, keyboard_data_ready.nothing, 0, 0 - ret 8 - -; This function is called when it is safe to free keyboard data. -CloseKeyboard: - mov eax, [esp+4] - push ebx - call Kfree - pop ebx - ret 4 - -; This function is called when SET_PROTOCOL command for mouse is done, -; either successful or unsuccessful. -mouse_configured: -; Check the status of the transfer and go to the corresponding label -; in the main handler. - cmp dword [esp+8], 0 - jnz mouse_data_ready.error - mov eax, [esp+20] - add eax, device_data.packet - jmp mouse_data_ready.next - -; This function is called when another interrupt packet arrives, -; processed either successfully or unsuccessfully. -; It should parse the packet and initiate another transfer with -; the same callback function. -mouse_data_ready: -; 1. Check the status of the transfer. - mov eax, [esp+8] - test eax, eax - jnz .error - mov edx, [esp+16] -; 2. Parse the packet. -; For boot protocol, USB mouse packet consists of at least 3 bytes. -; The first byte is state of mouse buttons, the next two bytes are -; x and y movements. -; Normal mice do not distinguish between boot protocol and report protocol; -; in this case, scroll data are also present. Advanced mice, however, -; support two different protocols, boot protocol is used for compatibility -; and does not contain extended buttons or scroll data. - mov eax, [esp+12] ; buffer - push eax - xor ecx, ecx - cmp edx, 4 - jbe @f - movsx ecx, byte [eax+4] -@@: - push ecx - xor ecx, ecx - cmp edx, 3 - jbe @f - movsx ecx, byte [eax+3] - neg ecx -@@: - push ecx - xor ecx, ecx - cmp edx, 2 - jbe @f - movsx ecx, byte [eax+2] - neg ecx -@@: - push ecx - movsx ecx, byte [eax+1] - push ecx - movzx ecx, byte [eax] - push ecx - call SetMouseData - pop eax -.next: -; 3. Initiate transfer on the interrupt pipe. - stdcall USBNormalTransferAsync, dword [eax+device_data.intpipe-device_data.packet], \ - eax, dword [eax+device_data.packetsize-device_data.packet], mouse_data_ready, eax, 1 -; 4. Return. - ret 20 -.error: -; An error has occured. -; 5. If an error is caused by the disconnect, do nothing, it is handled -; in DeviceDisconnected. Otherwise, say a message. - cmp eax, 16 - jz @f - push esi - mov esi, errormsgmouse - call SysMsgBoardStr - pop esi -@@: - ret 20 - -; This function is called when the device is disconnected. -DeviceDisconnected: - push ebx ; save used register to be stdcall -; 1. Say a message. Use different messages for keyboards and mice. - mov ebx, [esp+4+4] - push esi - mov esi, disconnectmsgk - cmp byte [ebx+device_data.type], 1 - jz @f - mov esi, disconnectmsgm -@@: - stdcall SysMsgBoardStr - pop esi -; 2. If device is keyboard, then we must unregister it as a keyboard and -; possibly stop the auto-repeat timer. - cmp byte [ebx+device_data.type], 1 - jnz .nokbd - mov eax, [ebx+keyboard_data.timer] - test eax, eax - jz @f - stdcall CancelTimerHS, eax -@@: - mov ecx, [ebx+keyboard_data.handle] - jecxz .nokbd - stdcall DelKeyboard, ecx -; If keyboard is registered, then we should free data in CloseKeyboard, not here. - jmp .nothing -.nokbd: -; 3. Free the device data. - xchg eax, ebx - call Kfree -; 4. Return. -.nothing: - pop ebx ; restore used register to be stdcall - ret 4 ; purge one dword argument to be stdcall - -; strings -my_driver db 'usbhid',0 -errormsgmouse db 'K : USB transfer error, disabling mouse',10,0 -errormsgkbd db 'K : USB transfer error, disabling keyboard',10,0 -disconnectmsgm db 'K : USB mouse disconnected',10,0 -disconnectmsgk db 'K : USB keyboard disconnected',10,0 - -; data for keyboard: correspondence between HID usage keys and PS/2 scancodes. -EX = 80h -label control_keys byte - db 1Dh, 2Ah, 38h, 5Bh+EX, 1Dh+EX, 36h, 38h+EX, 5Ch+EX -label normal_keys byte - db 00h, 00h, 00h, 00h, 1Eh, 30h, 2Eh, 20h, 12h, 21h, 22h, 23h, 17h, 24h, 25h, 26h ; 0x - db 32h, 31h, 18h, 19h, 10h, 13h, 1Fh, 14h, 16h, 2Fh, 11h, 2Dh, 15h, 2Ch, 02h, 03h ; 1x - db 04h, 05h, 06h, 07h, 08h, 09h, 0Ah, 0Bh, 1Ch, 01h, 0Eh, 0Fh, 39h, 0Ch, 0Dh, 1Ah ; 2x - db 1Bh, 2Bh, 2Bh, 27h, 28h, 29h, 33h, 34h, 35h, 3Ah, 3Bh, 3Ch, 3Dh, 3Eh, 3Fh, 40h ; 3x - db 41h, 42h, 43h, 44h, 57h, 58h,37h+EX,46h,0,52h+EX,47h+EX,49h+EX,53h+EX,4Fh+EX,51h+EX,4Dh+EX ; 4x - db 4Bh+EX,50h+EX,48h+EX,45h,35h+EX,37h,4Ah,4Eh,1Ch+EX,4Fh,50h,51h,4Bh,4Ch,4Dh,47h ; 5x - db 48h, 49h, 52h, 53h, 56h,5Dh+EX,5Eh+EX,59h,64h,65h,66h, 67h, 68h, 69h, 6Ah, 6Bh ; 6x - db 6Ch, 6Dh, 6Eh, 76h, 00h, 00h, 00h, 00h, 00h, 00h, 00h, 00h, 00h, 00h, 00h, 00h ; 7x - db 00h, 00h, 00h, 00h, 00h, 7Eh, 00h, 73h, 70h, 7Dh, 79h, 7Bh, 5Ch, 00h, 00h, 00h ; 8x - db 0F2h,0F1h,78h, 77h, 76h -normal_keys_number = $ - normal_keys - -; Exported variable: kernel API version. -align 4 -version dd 50005h -; Structure with callback functions. -usb_functions: - dd 12 - dd AddDevice - dd DeviceDisconnected - -; Structure with callback functions for keyboards. -usbkbd_functions: - dd 12 - dd CloseKeyboard - dd SetKeyboardLights - -; for DEBUGF macro -include_debug_strings - -; for uninitialized data -section '.data' data readable writable align 16 diff --git a/kernel/branches/Kolibri-acpi/drivers/usbhid/keyboard.inc b/kernel/branches/Kolibri-acpi/drivers/usbhid/keyboard.inc new file mode 100644 index 0000000000..b859d449b5 --- /dev/null +++ b/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 diff --git a/kernel/branches/Kolibri-acpi/drivers/usbhid/mouse.inc b/kernel/branches/Kolibri-acpi/drivers/usbhid/mouse.inc new file mode 100644 index 0000000000..845cf1a659 --- /dev/null +++ b/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 diff --git a/kernel/branches/Kolibri-acpi/drivers/usbhid/report.inc b/kernel/branches/Kolibri-acpi/drivers/usbhid/report.inc new file mode 100644 index 0000000000..7b0d590904 --- /dev/null +++ b/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] +} diff --git a/kernel/branches/Kolibri-acpi/drivers/usbhid/sort.inc b/kernel/branches/Kolibri-acpi/drivers/usbhid/sort.inc new file mode 100644 index 0000000000..baa8c3db5c --- /dev/null +++ b/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 diff --git a/kernel/branches/Kolibri-acpi/drivers/usbhid/unclaimed.inc b/kernel/branches/Kolibri-acpi/drivers/usbhid/unclaimed.inc new file mode 100644 index 0000000000..f325de742f --- /dev/null +++ b/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 diff --git a/kernel/branches/Kolibri-acpi/drivers/usbhid/usbhid.asm b/kernel/branches/Kolibri-acpi/drivers/usbhid/usbhid.asm new file mode 100644 index 0000000000..75e24a0d3e --- /dev/null +++ b/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 diff --git a/kernel/branches/Kolibri-acpi/drivers/vidrdc.asm b/kernel/branches/Kolibri-acpi/drivers/vidrdc.asm new file mode 100644 index 0000000000..02ce61a804 --- /dev/null +++ b/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 \ No newline at end of file diff --git a/kernel/branches/Kolibri-acpi/fs/fat32.inc b/kernel/branches/Kolibri-acpi/fs/fat.inc similarity index 70% rename from kernel/branches/Kolibri-acpi/fs/fat32.inc rename to kernel/branches/Kolibri-acpi/fs/fat.inc index e0b7ccb75c..aa9f4b8a68 100644 --- a/kernel/branches/Kolibri-acpi/fs/fat32.inc +++ b/kernel/branches/Kolibri-acpi/fs/fat.inc @@ -5,7 +5,7 @@ ;; ;; ;; FAT32.INC ;; ;; ;; -;; FAT16/32 functions for KolibriOS ;; +;; FAT functions for KolibriOS ;; ;; ;; ;; Copyright 2002 Paolo Minazzi, paolo.minazzi@inwind.it ;; ;; ;; @@ -44,7 +44,7 @@ ;; ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -$Revision$ +$Revision: 4273 $ cache_max equ 1919 ; max. is 1919*512+0x610000=0x6ffe00 @@ -94,7 +94,16 @@ longname_sec2 dd 0 ; directory sectors for delete long filename fat_in_cache dd -1 -fat_cache rb 512 +; For FAT16/FAT32, this points to 512-byte buffer for the current sector of FAT. +; For FAT12, the entire FAT structure is read +; and unpacked from 12bit per cluster to word per cluster. +; +; Note: work with unpacked copy of FAT12 means +; additional memory and additional code for packing/unpacking. +; I'm not sure that the economy justifies the cost, but anyway, +; there is how work was done before my edits, and I'm just keeping the principle. +fat_cache_ptr dd ? +fat12_unpacked_ptr dd ? buffer rb 512 fsinfo_buffer rb 512 ends @@ -120,7 +129,7 @@ endg iglobal align 4 fat_user_functions: - dd free + dd fat_free dd (fat_user_functions_end - fat_user_functions - 4) / 4 dd fat_Read dd fat_ReadFolder @@ -214,30 +223,42 @@ fat_create_partition: movzx eax, byte [ebx+0x10] ; number of fats mov [ebp+FAT.NUMBER_OF_FATS], eax - imul eax, [ebp+FAT.SECTORS_PER_FAT] + mul [ebp+FAT.SECTORS_PER_FAT] + test edx, edx + jnz .free_return0 add eax, [ebp+FAT.FAT_START] + jc .free_return0 mov [ebp+FAT.ROOT_START], eax ; rootdir = fat_start + fat_size * fat_count add eax, [ebp+FAT.ROOT_SECTORS] ; rootdir sectors should be 0 on fat32 + jc .free_return0 mov [ebp+FAT.DATA_START], eax ; data area = rootdir + rootdir_size movzx eax, word [ebx+0x13] ; total sector count <65536 test eax, eax jnz @f mov eax, [ebx+0x20] ; total sector count +@@: +; total sector count must not exceed partition size + cmp dword [ebp+FAT.Length+4], 0 + jnz @f + cmp eax, dword [ebp+FAT.Length] + ja .free_return0 @@: mov dword [ebp+FAT.Length], eax and dword [ebp+FAT.Length+4], 0 sub eax, [ebp+FAT.DATA_START] ; eax = count of data sectors + jc .free_return0 xor edx, edx div [ebp+FAT.SECTORS_PER_CLUSTER] inc eax mov [ebp+FAT.LAST_CLUSTER], eax dec eax ; cluster count + jz .free_return0 mov [ebp+FAT.fatStartScan], 2 ; limits by Microsoft Hardware White Paper v1.03 cmp eax, 4085 ; 0xff5 - jb .free_return0 ; fat12 not supported + jb .fat12 cmp eax, 65525 ; 0xfff5 jb .fat16 .fat32: @@ -261,7 +282,14 @@ fat_create_partition: mov [ebp+FAT.fatEND], 0x0FFFFFF8 mov [ebp+FAT.fatMASK], 0x0FFFFFFF mov al, 32 +.fat_not_12_finalize: mov [ebp+FAT.fs_type], al +; For FAT16 and FAT32, allocate 512 bytes for FAT cache. + mov eax, 512 + call malloc + test eax, eax + jz .free_return0 + mov [ebp+FAT.fat_cache_ptr], eax mov eax, ebp pop ebp ret @@ -272,11 +300,445 @@ fat_create_partition: mov [ebp+FAT.fatEND], 0x0000FFF8 mov [ebp+FAT.fatMASK], 0x0000FFFF mov al, 16 + jmp .fat_not_12_finalize +.fat12: + and [ebp+FAT.ROOT_CLUSTER], 0 + mov [ebp+FAT.fatRESERVED], 0xFF6 + mov [ebp+FAT.fatBAD], 0xFF7 + mov [ebp+FAT.fatEND], 0xFFF + mov [ebp+FAT.fatMASK], 0xFFF + mov al, 12 mov [ebp+FAT.fs_type], al +; For FAT12, allocate&read data for entire table: +; calculate A = ALIGN_UP(NUM_CLUSTERS, 8), +; calculatefatchain/restorefatchain will process A items, +; allocate ALIGN_UP(A*3/2, 512) bytes for FAT table plus A*2 bytes for unpacked data. + mov eax, [ebp+FAT.LAST_CLUSTER] + and eax, not 7 + add eax, 8 + mov edx, eax + lea eax, [eax*3] + add eax, 512*2-1 + shr eax, 10 + shl eax, 9 + lea eax, [eax+edx*2] + call malloc + test eax, eax + jz .free_return0 +; Read ALIGN_UP(NUM_CLUSTERS*3/2, 512) bytes. +; Note that this can be less than allocated, this is ok, +; overallocation simplifies calculatefatchain/restorefatchain. + push ebx + mov [ebp+FAT.fat_cache_ptr], eax + mov edx, [ebp+FAT.LAST_CLUSTER] + lea edx, [(edx+1)*3 + 512*2-1] + shr edx, 10 + xchg eax, ebx + xor eax, eax +.read_fat: + push eax + add eax, [ebp+FAT.FAT_START] + call fs_read32_sys + test eax, eax + pop eax + jz @f + dbgstr 'Failed to read FAT table' + mov eax, [ebp+FAT.fat_cache_ptr] + call free + pop ebx + jmp .free_return0 +@@: + add ebx, 512 + inc eax + cmp eax, edx + jb .read_fat + mov [ebp+FAT.fat12_unpacked_ptr], ebx + call calculatefatchain + pop ebx mov eax, ebp pop ebp ret +fat_free: + push eax + mov eax, [eax+FAT.fat_cache_ptr] + call free + pop eax + jmp free + +calculatefatchain: + + pushad + + mov esi, [ebp+FAT.fat_cache_ptr] + mov edi, [ebp+FAT.fat12_unpacked_ptr] + + mov edx, [ebp+FAT.LAST_CLUSTER] + and edx, not 7 + lea edx, [edi+(edx+8)*2] + push edx + + fcnew: + mov eax, dword [esi] + mov ebx, dword [esi+4] + mov ecx, dword [esi+8] + mov edx, ecx + shr edx, 4;8 ok + shr dx, 4;7 ok + xor ch, ch + shld ecx, ebx, 20;6 ok + shr cx, 4;5 ok + shld ebx, eax, 12 + and ebx, 0x0fffffff;4 ok + shr bx, 4;3 ok + shl eax, 4 + and eax, 0x0fffffff;2 ok + shr ax, 4;1 ok + mov dword [edi], eax + mov dword [edi+4], ebx + mov dword [edi+8], ecx + mov dword [edi+12], edx + add edi, 16 + add esi, 12 + + cmp edi, [esp] + jnz fcnew + pop eax + + popad + ret + + +restorefatchain: ; restore fat chain + + pushad + + mov esi, [ebp+FAT.fat12_unpacked_ptr] + mov edi, [ebp+FAT.fat_cache_ptr] + + mov edx, [ebp+FAT.LAST_CLUSTER] + and edx, not 7 + lea edx, [esi+(edx+8)*2] + + fcnew2: + mov eax, dword [esi] + mov ebx, dword [esi+4] + shl ax, 4 + shl eax, 4 + shl bx, 4 + shr ebx, 4 + shrd eax, ebx, 8 + shr ebx, 8 + mov dword [edi], eax + mov word [edi+4], bx + add edi, 6 + add esi, 8 + + cmp esi, edx + jb fcnew2 + + mov esi, [ebp+FAT.NUMBER_OF_FATS] + mov edx, [ebp+FAT.LAST_CLUSTER] + lea edx, [(edx+1)*3 + 512*2-1] + shr edx, 10 + push [ebp+FAT.FAT_START] + +.write_fats: + xor eax, eax + mov ebx, [ebp+FAT.fat_cache_ptr] +.loop1: + push eax + add eax, [esp+4] + call fs_write32_sys + test eax, eax + pop eax + jnz .fail + add ebx, 512 + inc eax + cmp eax, edx + jb .loop1 + pop eax + add eax, [ebp+FAT.SECTORS_PER_FAT] + push eax + dec esi + jnz .write_fats + pop eax + + popad + ret +.fail: + dbgstr 'Failed to save FAT' + popad + ret + +iglobal +label fat_legal_chars byte +; 0 = not allowed +; 1 = allowed only in long names +; 3 = allowed + times 32 db 0 +; ! " # $ % & ' ( ) * + , - . / + db 1,3,0,3,3,3,3,3,3,3,0,1,1,3,3,0 +; 0 1 2 3 4 5 6 7 8 9 : ; < = > ? + db 3,3,3,3,3,3,3,3,3,3,0,1,0,1,0,0 +; @ A B C D E F G H I J K L M N O + db 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 +; P Q R S T U V W X Y Z [ \ ] ^ _ + db 3,3,3,3,3,3,3,3,3,3,3,1,0,1,3,3 +; ` a b c d e f g h i j k l m n o + db 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 +; p q r s t u v w x y z { | } ~ + db 3,3,3,3,3,3,3,3,3,3,3,3,0,3,3,0 +endg + +fat_name_is_legal: +; in: esi->(long) name +; out: CF set <=> legal +; destroys eax + push esi + xor eax, eax +@@: + lodsb + test al, al + jz .done + cmp al, 80h + jae .big + test [fat_legal_chars+eax], 1 + jnz @b +.err: + pop esi + clc + ret +.big: +; 0x80-0xAF, 0xE0-0xEF + cmp al, 0xB0 + jb @b + cmp al, 0xE0 + jb .err + cmp al, 0xF0 + jb @b + jmp .err +.done: + sub esi, [esp] + cmp esi, 257 + pop esi + ret + +fat_next_short_name: +; in: edi->8+3 name +; out: name corrected +; CF=1 <=> error + pushad + mov ecx, 8 + mov al, '~' + std + push edi + add edi, 7 + repnz scasb + pop edi + cld + jz .tilde +; tilde is not found, insert "~1" at end + add edi, 6 + cmp word [edi], ' ' + jnz .insert_tilde +@@: + dec edi + cmp byte [edi], ' ' + jz @b + inc edi +.insert_tilde: + mov word [edi], '~1' + popad + clc + ret +.tilde: + push edi + add edi, 7 + xor ecx, ecx +@@: +; after tilde may be only digits and trailing spaces + cmp byte [edi], '~' + jz .break + cmp byte [edi], ' ' + jz .space + cmp byte [edi], '9' + jnz .found + dec edi + jmp @b +.space: + dec edi + inc ecx + jmp @b +.found: + inc byte [edi] + add dword [esp], 8 + jmp .zerorest +.break: + jecxz .noplace + inc edi + mov al, '1' +@@: + xchg al, [edi] + inc edi + cmp al, ' ' + mov al, '0' + jnz @b +.succ: + pop edi + popad + clc + ret +.noplace: + dec edi + cmp edi, [esp] + jz .err + add dword [esp], 8 + mov word [edi], '~1' + inc edi + inc edi +@@: + mov byte [edi], '0' +.zerorest: + inc edi + cmp edi, [esp] + jb @b + pop edi + popad + ;clc ; automatically + ret +.err: + pop edi + popad + stc + ret + +fat_gen_short_name: +; in: esi->long name +; edi->buffer (8+3=11 chars) +; out: buffer filled + pushad + mov eax, ' ' + push edi + stosd + stosd + stosd + pop edi + xor eax, eax + movi ebx, 8 + lea ecx, [edi+8] +.loop: + lodsb + test al, al + jz .done + call char_toupper + cmp al, ' ' + jz .space + cmp al, 80h + ja .big + test [fat_legal_chars+eax], 2 + jnz .symbol +.inv_symbol: + mov al, '_' + or bh, 1 +.symbol: + cmp al, '.' + jz .dot +.normal_symbol: + dec bl + jns .store + mov bl, 0 +.space: + or bh, 1 + jmp .loop +.store: + stosb + jmp .loop +.big: + cmp al, 0xB0 + jb .normal_symbol + cmp al, 0xE0 + jb .inv_symbol + cmp al, 0xF0 + jb .normal_symbol + jmp .inv_symbol +.dot: + test bh, 2 + jz .firstdot + pop ebx + add ebx, edi + sub ebx, ecx + push ebx + cmp ebx, ecx + jb @f + pop ebx + push ecx +@@: + cmp edi, ecx + jbe .skip +@@: + dec edi + mov al, [edi] + dec ebx + mov [ebx], al + mov byte [edi], ' ' + cmp edi, ecx + ja @b +.skip: + mov bh, 3 + jmp @f +.firstdot: + cmp bl, 8 + jz .space + push edi + or bh, 2 +@@: + mov edi, ecx + mov bl, 3 + jmp .loop +.done: + test bh, 2 + jz @f + pop edi +@@: + lea edi, [ecx-8] + test bh, 1 + jz @f + call fat_next_short_name +@@: + popad + ret + +fat12_free_space: +;--------------------------------------------- +; +; returns free space in edi +; rewr.by Mihasik +;--------------------------------------------- + + push eax ebx ecx + + mov edi, [ebp+FAT.fat12_unpacked_ptr];start of FAT + xor ax, ax;Free cluster=0x0000 in FAT + xor ebx, ebx;counter + mov ecx, [ebp+FAT.LAST_CLUSTER] + inc ecx + cld + rdfs1: + repne scasw + jnz rdfs2 ;if last cluster not 0 + inc ebx + test ecx, ecx + jnz rdfs1 + rdfs2: + shl ebx, 9;free clusters*512 + mov edi, ebx + + pop ecx ebx eax + ret + + + set_FAT: ;-------------------------------- ; input : EAX = cluster @@ -291,6 +753,8 @@ set_FAT: jb sfc_error cmp eax, [ebp+FAT.LAST_CLUSTER] ja sfc_error + cmp [ebp+FAT.fs_type], 12 + je set_FAT12 cmp [ebp+FAT.fs_type], 16 je sfc_1 add eax, eax @@ -300,7 +764,7 @@ set_FAT: and esi, eax ; esi = position in fat sector shr eax, 9 ; eax = fat sector add eax, [ebp+FAT.FAT_START] - lea ebx, [ebp+FAT.fat_cache] + mov ebx, [ebp+FAT.fat_cache_ptr] cmp eax, [ebp+FAT.fat_in_cache]; is fat sector already in memory? je sfc_in_cache ; yes @@ -349,6 +813,15 @@ set_FAT: stc jmp sfc_return + set_FAT12: + test edx, 0xF000 + jnz sfc_error + mov ebx, [ebp+FAT.fat12_unpacked_ptr] + xchg [ebx+eax*2], dx + mov [ebp+FAT.fat_change], 1 + pop esi ebx eax + clc + ret get_FAT: ;-------------------------------- @@ -359,6 +832,9 @@ get_FAT: ; out: CF set <=> error push ebx esi + cmp [ebp+FAT.fs_type], 12 + je get_FAT12 + cmp [ebp+FAT.fs_type], 16 je gfc_1 add eax, eax @@ -368,7 +844,7 @@ get_FAT: and esi, eax ; esi = position in fat sector shr eax, 9 ; eax = fat sector add eax, [ebp+FAT.FAT_START] - lea ebx, [ebp+FAT.fat_cache] + mov ebx, [ebp+FAT.fat_cache_ptr] cmp eax, [ebp+FAT.fat_in_cache]; is fat sector already in memory? je gfc_in_cache @@ -394,6 +870,13 @@ get_FAT: stc jmp gfc_return +get_FAT12: + mov ebx, [ebp+FAT.fat12_unpacked_ptr] + movzx eax, word [ebx+eax*2] + pop esi ebx + clc + ret + get_free_FAT: ;----------------------------------------------------------- @@ -403,8 +886,10 @@ get_free_FAT: ;----------------------------------------------------------- push ecx mov ecx, [ebp+FAT.LAST_CLUSTER]; counter for full disk - sub ecx, 2 mov eax, [ebp+FAT.fatStartScan] + cmp [ebp+FAT.fs_type], 12 + jz get_free_FAT12 + dec ecx cmp eax, 2 jb gff_reset @@ -424,7 +909,7 @@ get_free_FAT: je gff_found ; yes inc eax ; next cluster dec ecx ; is all checked? - jns gff_test ; no + jnz gff_test ; no gff_not_found: pop ecx ; yes. disk is full @@ -442,6 +927,41 @@ get_free_FAT: clc ret +get_free_FAT12: + push edx edi + mov edi, [ebp+FAT.fat12_unpacked_ptr] + cmp eax, 2 + jb .reset + cmp eax, ecx + jbe @f +.reset: + mov eax, 2 +@@: + mov edx, eax + lea edi, [edi+eax*2] + sub ecx, eax + inc ecx + xor eax, eax + repnz scasw + jz .found + cmp edx, 2 + jz .notfound + mov edi, [ebp+FAT.fat12_unpacked_ptr] + lea ecx, [edx-2] + repnz scasw + jnz .notfound +.found: + sub edi, [ebp+FAT.fat12_unpacked_ptr] + shr edi, 1 + mov [ebp+FAT.fatStartScan], edi + lea eax, [edi-1] + pop edi edx ecx + ret +.notfound: + pop edi edx ecx + stc + ret + write_fat_sector: ;----------------------------------------------------------- @@ -453,7 +973,7 @@ write_fat_sector: mov eax, [ebp+FAT.fat_in_cache] cmp eax, -1 jz write_fat_not_used - lea ebx, [ebp+FAT.fat_cache] + mov ebx, [ebp+FAT.fat_cache_ptr] mov ecx, [ebp+FAT.NUMBER_OF_FATS] write_next_fat: @@ -683,14 +1203,20 @@ get_hd_info: end if update_disk: + cmp [ebp+FAT.fat_change], 0 ; is fat changed? + je upd_no_change + cmp [ebp+FAT.fs_type], 12 + jz .fat12 ;----------------------------------------------------------- ; write changed fat and cache to disk ;----------------------------------------------------------- - cmp [ebp+FAT.fat_change], 0 ; is fat changed? - je upd_no_change call write_fat_sector jc update_disk_acces_denied + jmp upd_no_change +.fat12: + call restorefatchain + mov [ebp+FAT.fat_change], 0 upd_no_change: @@ -709,6 +1235,484 @@ fat_unlock: jmp mutex_unlock ; \begin{diamond} +uni2ansi_str: +; convert UNICODE zero-terminated string to ASCII-string (codepage 866) +; in: esi->source, edi->buffer (may be esi=edi) +; destroys: eax,esi,edi + lodsw + test ax, ax + jz .done + 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, 0xF0 ; 'Ё' + jmp .doit +.yo2: + mov al, 0xF1 ; 'ё' + jmp .doit +.rus1: +; 0x410-0x43F -> 0x80-0xAF + add al, 0x70 + jmp .doit +.rus2: +; 0x440-0x44F -> 0xE0-0xEF + add al, 0xA0 +.ascii: +.doit: + stosb + jmp uni2ansi_str +.done: + mov byte [edi], 0 + ret + +ansi2uni_char: +; convert ANSI character in al to UNICODE character in ax, using cp866 encoding + mov ah, 0 +; 0x00-0x7F - trivial map + cmp al, 0x80 + jb .ret +; 0x80-0xAF -> 0x410-0x43F + cmp al, 0xB0 + jae @f + add ax, 0x410-0x80 +.ret: + ret +@@: +; 0xE0-0xEF -> 0x440-0x44F + cmp al, 0xE0 + jb .unk + cmp al, 0xF0 + jae @f + add ax, 0x440-0xE0 + ret +; 0xF0 -> 0x401 +; 0xF1 -> 0x451 +@@: + cmp al, 0xF0 ; 'Ё' + jz .yo1 + cmp al, 0xF1 ; 'ё' + jz .yo2 +.unk: + mov al, '_' ; ah=0 + ret +.yo1: + mov ax, 0x401 + ret +.yo2: + mov ax, 0x451 + ret + +char_toupper: +; 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, 0xF1 ; 'ё' + jz .yo1 + cmp al, 0xA0 ; 'а' + jb .ret + cmp al, 0xE0 ; 'р' + jb .rus1 + cmp al, 0xEF ; 'я' + ja .ret +; 0xE0-0xEF -> 0x90-0x9F + sub al, 0xE0-0x90 +.ret: + ret +.rus1: +; 0xA0-0xAF -> 0x80-0x8F +.az: + and al, not 0x20 + ret +.yo1: +; 0xF1 -> 0xF0 + dec ax + ret + +fat_get_name: +; in: edi->FAT entry +; out: CF=1 - no valid entry +; else CF=0 and ebp->ASCIIZ-name +; (maximum length of filename is 255 (wide) symbols without trailing 0, +; but implementation requires buffer 261 words) +; destroys eax + cmp byte [edi], 0 + jz .no + cmp byte [edi], 0xE5 + jnz @f +.no: + stc + ret +@@: + cmp byte [edi+11], 0xF + jz .longname + test byte [edi+11], 8 + jnz .no + push ecx + push edi ebp + test byte [ebp-4], 1 + jnz .unicode_short + + mov eax, [edi] + mov ecx, [edi+4] + mov [ebp], eax + mov [ebp+4], ecx + + mov ecx, 8 +@@: + cmp byte [ebp+ecx-1], ' ' + loope @b + + mov eax, [edi+8] + cmp al, ' ' + je .done + shl eax, 8 + mov al, '.' + + lea ebp, [ebp+ecx+1] + mov [ebp], eax + mov ecx, 3 +@@: + rol eax, 8 + cmp al, ' ' + jne .done + loop @b + dec ebp +.done: + and byte [ebp+ecx+1], 0 ; CF=0 + pop ebp edi ecx + ret +.unicode_short: + mov ecx, 8 + push ecx +@@: + mov al, [edi] + inc edi + call ansi2uni_char + mov [ebp], ax + inc ebp + inc ebp + loop @b + pop ecx +@@: + cmp word [ebp-2], ' ' + jnz @f + dec ebp + dec ebp + loop @b +@@: + mov word [ebp], '.' + inc ebp + inc ebp + mov ecx, 3 + push ecx +@@: + mov al, [edi] + inc edi + call ansi2uni_char + mov [ebp], ax + inc ebp + inc ebp + loop @b + pop ecx +@@: + cmp word [ebp-2], ' ' + jnz @f + dec ebp + dec ebp + loop @b + dec ebp + dec ebp +@@: + and word [ebp], 0 ; CF=0 + pop ebp edi ecx + ret +.longname: +; LFN + mov al, byte [edi] + and eax, 0x3F + dec eax + cmp al, 20 + jae .no ; ignore invalid entries + mov word [ebp+260*2], 0 ; force null-terminating for orphans + imul eax, 13*2 + add ebp, eax + test byte [edi], 0x40 + jz @f + mov word [ebp+13*2], 0 +@@: + push eax +; now copy name from edi to ebp ... + mov eax, [edi+1] + mov [ebp], eax ; symbols 1,2 + mov eax, [edi+5] + mov [ebp+4], eax ; 3,4 + mov eax, [edi+9] + mov [ebp+8], ax ; 5 + mov eax, [edi+14] + mov [ebp+10], eax ; 6,7 + mov eax, [edi+18] + mov [ebp+14], eax ; 8,9 + mov eax, [edi+22] + mov [ebp+18], eax ; 10,11 + mov eax, [edi+28] + mov [ebp+22], eax ; 12,13 +; ... done + pop eax + sub ebp, eax + test eax, eax + jz @f +; if this is not first entry, more processing required + stc + ret +@@: +; if this is first entry: + test byte [ebp-4], 1 + jnz .ret +; buffer at ebp contains UNICODE name, convert it to ANSI + push esi edi + mov esi, ebp + mov edi, ebp + call uni2ansi_str + pop edi esi +.ret: + clc + ret + +fat_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 ebp esi +.loop: + mov al, [ebp] + inc ebp + call char_toupper + push eax + lodsb + call char_toupper + cmp al, [esp] + jnz .done + pop eax + test al, al + jnz .loop + dec esi + pop eax + pop ebp + xor eax, eax ; set ZF flag + ret +.done: + cmp al, '/' + jnz @f + cmp byte [esp], 0 + jnz @f + mov [esp+4], esi +@@: + pop eax + pop esi ebp + ret + +fat_find_lfn: +; in: esi->name +; [esp+4] = next +; [esp+8] = first +; [esp+C]... - possibly parameters for first and next +; out: CF=1 - file not found, eax=error code +; else CF=0, esi->next name component, edi->direntry + pusha + lea eax, [esp+0Ch+20h] + call dword [eax-4] + jc .reterr + sub esp, 262*2 ; reserve place for LFN + push 0 ; for fat_get_name: read ASCII name +.l1: + lea ebp, [esp+4] + call fat_get_name + jc .l2 + call fat_compare_name + jz .found +.l2: + mov ebp, [esp+8+262*2+4] + lea eax, [esp+0Ch+20h+262*2+4] + call dword [eax-8] + jnc .l1 + add esp, 262*2+4 +.reterr: + mov [esp+28], eax + stc + popa + ret +.found: + add esp, 262*2+4 + mov ebp, [esp+8] +; if this is LFN entry, advance to true entry + cmp byte [edi+11], 0xF + jnz @f + lea eax, [esp+0Ch+20h] + call dword [eax-8] + jc .reterr +@@: + add esp, 8 ; CF=0 + push esi + push edi + popa + ret + +fat_time_to_bdfe: +; in: eax=FAT time +; out: eax=BDFE time + push ecx edx + mov ecx, eax + mov edx, eax + shr eax, 11 + shl eax, 16 ; hours + and edx, 0x1F + add edx, edx + mov al, dl ; seconds + shr ecx, 5 + and ecx, 0x3F + mov ah, cl ; minutes + pop edx ecx + ret + +fat_date_to_bdfe: + push ecx edx + mov ecx, eax + mov edx, eax + shr eax, 9 + add ax, 1980 + shl eax, 16 ; year + and edx, 0x1F + mov al, dl ; day + shr ecx, 5 + and ecx, 0xF + mov ah, cl ; month + pop edx ecx + ret + +bdfe_to_fat_time: + push edx + mov edx, eax + shr eax, 16 + and dh, 0x3F + shl eax, 6 + or al, dh + shr dl, 1 + and dl, 0x1F + shl eax, 5 + or al, dl + pop edx + ret + +bdfe_to_fat_date: + push edx + mov edx, eax + shr eax, 16 + sub ax, 1980 + and dh, 0xF + shl eax, 4 + or al, dh + and dl, 0x1F + shl eax, 5 + or al, dl + pop edx + ret + +fat_entry_to_bdfe: +; convert FAT entry at edi to BDFE (block of data of folder entry) at esi, advance esi +; destroys eax + mov eax, [ebp-4] + mov [esi+4], eax ; ASCII/UNICODE name +fat_entry_to_bdfe2: + movzx eax, byte [edi+11] + mov [esi], eax ; attributes + movzx eax, word [edi+14] + call fat_time_to_bdfe + mov [esi+8], eax ; creation time + movzx eax, word [edi+16] + call fat_date_to_bdfe + mov [esi+12], eax ; creation date + and dword [esi+16], 0 ; last access time is not supported on FAT + movzx eax, word [edi+18] + call fat_date_to_bdfe + mov [esi+20], eax ; last access date + movzx eax, word [edi+22] + call fat_time_to_bdfe + mov [esi+24], eax ; last write time + movzx eax, word [edi+24] + call fat_date_to_bdfe + mov [esi+28], eax ; last write date + mov eax, [edi+28] + mov [esi+32], eax ; file size (low dword) + xor eax, eax + mov [esi+36], eax ; file size (high dword) + test ebp, ebp + jz .ret + push ecx edi + lea edi, [esi+40] + mov esi, ebp + test byte [esi-4], 1 + jz .ansi + mov ecx, 260/2 + rep movsd + mov [edi-2], ax +@@: + mov esi, edi + pop edi ecx +.ret: + ret +.ansi: + mov ecx, 264/4 + rep movsd + mov [edi-1], al + jmp @b + +bdfe_to_fat_entry: +; convert BDFE at edx to FAT entry at edi +; destroys eax +; attributes byte + test byte [edi+11], 8 ; volume label? + jnz @f + mov al, [edx] + and al, 0x27 + and byte [edi+11], 0x10 + or byte [edi+11], al +@@: + mov eax, [edx+8] + call bdfe_to_fat_time + mov [edi+14], ax ; creation time + mov eax, [edx+12] + call bdfe_to_fat_date + mov [edi+16], ax ; creation date + mov eax, [edx+20] + call bdfe_to_fat_date + mov [edi+18], ax ; last access date + mov eax, [edx+24] + call bdfe_to_fat_time + mov [edi+22], ax ; last write time + mov eax, [edx+28] + call bdfe_to_fat_date + mov [edi+24], ax ; last write date + ret + hd_find_lfn: ; in: ebp -> FAT structure ; in: esi+[esp+4] -> name @@ -718,12 +1722,14 @@ hd_find_lfn: push esi edi push 0 push 0 - push fat16_root_first - push fat16_root_next + push fat1x_root_first + push fat1x_root_next mov eax, [ebp+FAT.ROOT_CLUSTER] cmp [ebp+FAT.fs_type], 32 jz .fat32 .loop: + and [ebp+FAT.longname_sec1], 0 + and [ebp+FAT.longname_sec2], 0 call fat_find_lfn jc .notfound cmp byte [esi], 0 @@ -766,7 +1772,7 @@ hd_find_lfn: ret 4 ;---------------------------------------------------------------- -; fat_Read - FAT16/32 implementation of reading a file +; fat_Read - FAT implementation of reading a file ; in: ebp = pointer to FAT structure ; in: esi+[esp+4] = name ; in: ebx = pointer to parameters from sysfunc 70 @@ -905,7 +1911,7 @@ fat_Read: jmp .reteof ;---------------------------------------------------------------- -; fat_ReadFolder - FAT16/32 implementation of reading a folder +; fat_ReadFolder - FAT implementation of reading a folder ; in: ebp = pointer to FAT structure ; in: esi+[esp+4] = name ; in: ebx = pointer to parameters from sysfunc 70 @@ -1080,15 +2086,15 @@ fat_ReadFolder: pop esi edi ret -fat16_root_next: +fat1x_root_next: push ecx lea ecx, [ebp+FAT.buffer+0x200-0x20] cmp edi, ecx - jae fat16_root_next_sector + jae fat1x_root_next_sector pop ecx add edi, 0x20 ret ; CF=0 -fat16_root_next_sector: +fat1x_root_next_sector: ; read next sector push [ebp+FAT.longname_sec2] pop [ebp+FAT.longname_sec1] @@ -1101,11 +2107,11 @@ fat16_root_next_sector: mov [eax+4], ecx cmp ecx, [ebp+FAT.ROOT_SECTORS] pop ecx - jb fat16_root_first + jb fat1x_root_first mov eax, ERROR_FILE_NOT_FOUND stc ret -fat16_root_first: +fat1x_root_first: mov eax, [eax+4] add eax, [ebp+FAT.ROOT_START] push ebx @@ -1124,12 +2130,12 @@ fat16_root_first: mov eax, ERROR_FILE_NOT_FOUND stc ret -fat16_root_begin_write: +fat1x_root_begin_write: push edi eax - call fat16_root_first + call fat1x_root_first pop eax edi ret -fat16_root_end_write: +fat1x_root_end_write: pusha mov eax, [eax+4] add eax, [ebp+FAT.ROOT_START] @@ -1137,7 +2143,7 @@ fat16_root_end_write: call fs_write32_sys popa ret -fat16_root_next_write: +fat1x_root_next_write: push ecx lea ecx, [ebp+FAT.buffer+0x200] cmp edi, ecx @@ -1145,9 +2151,9 @@ fat16_root_next_write: pop ecx ret @@: - call fat16_root_end_write - jmp fat16_root_next_sector -fat16_root_extend_dir: + call fat1x_root_end_write + jmp fat1x_root_next_sector +fat1x_root_extend_dir: stc ret @@ -1308,7 +2314,7 @@ fshrad: ret ;---------------------------------------------------------------- -; fat_CreateFolder - FAT16/32 implementation of creating a folder +; fat_CreateFolder - FAT implementation of creating a folder ; in: ebp = pointer to FAT structure ; in: esi+[esp+4] = name ; in: ebx = pointer to parameters from sysfunc 70 @@ -1319,7 +2325,7 @@ fat_CreateFolder: jmp fat_Rewrite.common ;---------------------------------------------------------------- -; fat_Rewrite - FAT16/32 implementation of creating a new file +; fat_Rewrite - FAT implementation of creating a new file ; in: ebp = pointer to FAT structure ; in: esi+[esp+4] = name ; in: ebx = pointer to parameters from sysfunc 70 @@ -1360,14 +2366,14 @@ fat_Rewrite: jz .pushnotroot xor edx, edx push edx - push fat16_root_extend_dir - push fat16_root_end_write - push fat16_root_next_write - push fat16_root_begin_write + push fat1x_root_extend_dir + push fat1x_root_end_write + push fat1x_root_next_write + push fat1x_root_begin_write push edx push edx - push fat16_root_first - push fat16_root_next + push fat1x_root_first + push fat1x_root_next jmp .common1 .hasebp: mov eax, ERROR_ACCESS_DENIED @@ -1658,17 +2664,17 @@ fat_Rewrite: add esi, ecx stosb mov cl, 5 - call fs_RamdiskRewrite.read_symbols + call fat_read_symbols mov ax, 0xF stosw mov al, [esp+4] stosb mov cl, 6 - call fs_RamdiskRewrite.read_symbols + call fat_read_symbols xor eax, eax stosw mov cl, 2 - call fs_RamdiskRewrite.read_symbols + call fat_read_symbols pop ecx lea eax, [esp+8+8+12+8] call dword [eax+12] ; next write @@ -1866,6 +2872,25 @@ fat_Rewrite: mov [edi-32+20], cx jmp .writedircont +fat_read_symbol: + or ax, -1 + test esi, esi + jz .retFFFF + lodsb + test al, al + jnz ansi2uni_char + xor eax, eax + xor esi, esi +.retFFFF: + ret + +fat_read_symbols: + call fat_read_symbol + stosw + loop fat_read_symbols + ret + + fat_Write.access_denied: push ERROR_ACCESS_DENIED fat_Write.ret0: @@ -1878,7 +2903,7 @@ fat_Write.ret11: jmp fat_Write.ret0 ;---------------------------------------------------------------- -; fat_Write - FAT16/32 implementation of writing to file +; fat_Write - FAT implementation of writing to file ; in: ebp = pointer to FAT structure ; in: esi+[esp+4] = name ; in: ebx = pointer to parameters from sysfunc 70 @@ -2204,8 +3229,17 @@ hd_extend_file: stc ret +fat_update_datetime: + call get_time_for_file + mov [edi+22], ax ; last write time + call get_date_for_file + mov [edi+24], ax ; last write date + mov [edi+18], ax ; last access date + ret + + ;---------------------------------------------------------------- -; fat_SetFileEnd - FAT16/32 implementation of setting end-of-file +; fat_SetFileEnd - FAT implementation of setting end-of-file ; in: ebp = pointer to FAT structure ; in: esi+[esp+4] = name ; in: ebx = pointer to parameters from sysfunc 70 @@ -2445,7 +3479,7 @@ fat_SetFileEnd: ret ;---------------------------------------------------------------- -; fat_GetFileInfo - FAT16/32 implementation of getting file info +; fat_GetFileInfo - FAT implementation of getting file info ; in: ebp = pointer to FAT structure ; in: esi+[esp+4] = name ; in: ebx = pointer to parameters from sysfunc 70 @@ -2479,7 +3513,7 @@ fat_GetFileInfo: ret ;---------------------------------------------------------------- -; fat_SetFileInfo - FAT16/32 implementation of setting file info +; fat_SetFileInfo - FAT implementation of setting file info ; in: ebp = pointer to FAT structure ; in: esi+[esp+4] = name ; in: ebx = pointer to parameters from sysfunc 70 @@ -2514,7 +3548,7 @@ fat_SetFileInfo: ret ;---------------------------------------------------------------- -; fat_Delete - FAT16/32 implementation of deleting a file/folder +; fat_Delete - FAT implementation of deleting a file/folder ; in: ebp = pointer to FAT structure ; in: esi+[esp+4] = name ; in: ebx = pointer to parameters from sysfunc 70 diff --git a/kernel/branches/Kolibri-acpi/fs/fat12.inc b/kernel/branches/Kolibri-acpi/fs/fat12.inc deleted file mode 100644 index 0454f3e44a..0000000000 --- a/kernel/branches/Kolibri-acpi/fs/fat12.inc +++ /dev/null @@ -1,2268 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; ;; -;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; -;; Distributed under terms of the GNU General Public License ;; -;; ;; -;; FAT12.INC ;; -;; (C) 2005 Mario79, License: GPL ;; -;; ;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -$Revision$ - - -n_sector dd 0 ; temporary save for sector value -flp_status dd 0 -clust_tmp_flp dd 0 ; used by analyze_directory and analyze_directory_to_write -path_pointer_flp dd 0 -pointer_file_name_flp dd 0 -save_root_flag db 0 -save_flag db 0 -root_read db 0 ; 0-necessary to load root, 1-not to load root -flp_fat db 0 ; 0-necessary to load fat, 1-not to load fat -flp_number db 0 ; 1- Floppy A, 2-Floppy B -old_track db 0 ; old value track -flp_label rb 15 ; Label and ID of inserted floppy disk - -reserve_flp: - - cli - cmp [flp_status], 0 - je reserve_flp_ok - - sti - call change_task - jmp reserve_flp - - reserve_flp_ok: - - push eax - mov eax, [CURRENT_TASK] - shl eax, 5 - mov eax, [eax+CURRENT_TASK+TASKDATA.pid] - mov [flp_status], eax - pop eax - sti - ret - - -floppy_fileread: -;---------------------------------------------------------------- -; -; fileread - sys floppy -; -; eax points to filename 11 chars - for root directory -; ebx first wanted block ; 1+ ; if 0 then set to 1 -; ecx number of blocks to read ; 1+ ; if 0 then set to 1 -; edx mem location to return data -; esi length of filename 12*X -; edi pointer to path /fd/1/...... - for all files in nested directories -; -; ret ebx = size or 0xffffffff file not found -; eax = 0 ok read or other = errormsg -; 10 = access denied -;-------------------------------------------------------------- - - mov [save_flag], 0 - mov [path_pointer_flp], edi - test esi, esi ; return ramdisk root - jnz fr_noroot_1 - cmp ebx, 224/16 - jbe fr_do_1 - mov eax, 5 - xor ebx, ebx - mov [flp_status], ebx - ret - -fr_do_1: - push ebx ecx edx - call read_flp_root - pop edx ecx ebx - cmp [FDC_Status], 0 - jne fdc_status_error_1 - mov edi, edx - dec ebx - shl ebx, 9 - mov esi, FLOPPY_BUFF - add esi, ebx - shl ecx, 9 - cld - rep movsb - xor eax, eax - xor ebx, ebx -; mov eax,0 ; ok read -; mov ebx,0 - mov [flp_status], eax - ret -fdc_status_error_1: - xor eax, eax - mov [flp_status], eax - mov eax, 10 - or ebx, -1 - ret - -fr_noroot_1: - sub esp, 32 - call expand_filename -frfloppy_1: - test ebx, ebx - jnz frfl5_1 - mov ebx, 1 -frfl5_1: - test ecx, ecx - jnz frfl6_1 - mov ecx, 1 -frfl6_1: - dec ebx - push eax - push eax ebx ecx edx esi edi - call read_flp_fat - cmp [FDC_Status], 0 - jne fdc_status_error_3_1 - mov [FDD_Track], 0; Цилиндр - mov [FDD_Head], 1; Сторона - mov [FDD_Sector], 2; Сектор - call SeekTrack - mov dh, 14 -l.20_1: - call ReadSectWithRetr - cmp [FDC_Status], 0 - jne fdc_status_error_3_1 - mov dl, 16 - mov edi, FDD_BUFF - inc [FDD_Sector] -l.21_1: - mov esi, eax ;Name of file we want - mov ecx, 11 - cld - rep cmpsb ;Found the file? - je fifound_1 ;Yes - add ecx, 21 - add edi, ecx ;Advance to next entry - dec dl - test dl, dl - jnz l.21_1 - dec dh - test dh, dh - jnz l.20_1 -fdc_status_error_3: - mov eax, 5 ; file not found ? - or ebx, -1 - add esp, 32+28 - mov [flp_status], 0 - ret -fdc_status_error_3_2: - cmp [FDC_Status], 0 - je fdc_status_error_3 -fdc_status_error_3_1: - add esp, 32+28 - jmp fdc_status_error_1 - -fifound_1: - mov eax, [path_pointer_flp] - cmp [eax+36], byte 0 - je fifound_2 - add edi, 0xf - mov eax, [edi] - and eax, 65535 - mov ebx, [path_pointer_flp] - add ebx, 36 - call get_cluster_of_a_path_flp - jc fdc_status_error_3_2 - mov ebx, [ebx-11+28] ;file size - mov [esp+20], ebx - mov [esp+24], ebx - jmp fifound_3 -fifound_2: - mov ebx, [edi-11+28] ;file size - mov [esp+20], ebx - mov [esp+24], ebx - add edi, 0xf - mov eax, [edi] -fifound_3: - and eax, 65535 - mov [n_sector], eax ;eax=cluster -frnew_1: - add eax, 31 ;bootsector+2*fat+filenames - cmp [esp+16], dword 0; wanted cluster ? - jne frfl7_1 - call read_chs_sector - cmp [FDC_Status], 0 - jne fdc_status_error_5 - mov edi, [esp+8] - call give_back_application_data_1 - add [esp+8], dword 512 - dec dword [esp+12] ; last wanted cluster ? - cmp [esp+12], dword 0 - je frnoread_1 - jmp frfl8_1 -frfl7_1: - dec dword [esp+16] -frfl8_1: - mov edi, [n_sector] - shl edi, 1 ;find next cluster from FAT - add edi, FLOPPY_FAT - mov eax, [edi] - and eax, 4095 - mov edi, eax - mov [n_sector], edi - cmp edi, 4095 ;eof - cluster - jz frnoread2_1 - cmp [esp+24], dword 512;eof - size - jb frnoread_1 - sub [esp+24], dword 512 - jmp frnew_1 - -read_chs_sector: - call calculate_chs - call ReadSectWithRetr - ret - -frnoread2_1: - cmp [esp+16], dword 0; eof without read ? - je frnoread_1 - - pop edi esi edx ecx - add esp, 4 - pop ebx; ebx <- eax : size of file - add esp, 36 - mov eax, 6; end of file - mov [flp_status], 0 - ret - -frnoread_1: - pop edi esi edx ecx - add esp, 4 - pop ebx; ebx <- eax : size of file - add esp, 36 - xor eax, eax - mov [flp_status], eax - ret - -fdc_status_error_5: - pop edi esi edx ecx - add esp, 4 - pop ebx; ebx <- eax : size of file - add esp, 36 - jmp fdc_status_error_1 - -read_flp_root: - pusha - call check_label - cmp [FDC_Status], 0 - jne unnecessary_root_read - cmp [root_read], 1 - je unnecessary_root_read - mov [FDD_Track], 0; Цилиндр - mov [FDD_Head], 1; Сторона - mov [FDD_Sector], 2; Сектор - mov edi, FLOPPY_BUFF - call SeekTrack -read_flp_root_1: - call ReadSectWithRetr - cmp [FDC_Status], 0 - jne unnecessary_root_read - push edi - call give_back_application_data_1 - pop edi - add edi, 512 - inc [FDD_Sector] - cmp [FDD_Sector], 16 - jne read_flp_root_1 - mov [root_read], 1 -unnecessary_root_read: - popa - ret - - -read_flp_fat: - pusha - call check_label - cmp [FDC_Status], 0 - jne unnecessary_flp_fat - cmp [flp_fat], 1 - je unnecessary_flp_fat - mov [FDD_Track], 0; Цилиндр - mov [FDD_Head], 0; Сторона - mov [FDD_Sector], 2; Сектор - mov edi, FLOPPY_BUFF - call SeekTrack -read_flp_fat_1: - call ReadSectWithRetr - cmp [FDC_Status], 0 - jne unnecessary_flp_fat - push edi - call give_back_application_data_1 - pop edi - add edi, 512 - inc [FDD_Sector] - cmp [FDD_Sector], 19 - jne read_flp_fat_1 - mov [FDD_Sector], 1 - mov [FDD_Head], 1 - call ReadSectWithRetr - cmp [FDC_Status], 0 - jne unnecessary_flp_fat - call give_back_application_data_1 - call calculatefatchain_flp - mov [root_read], 0 - mov [flp_fat], 1 -unnecessary_flp_fat: - popa - ret - -calculatefatchain_flp: - pushad - - mov esi, FLOPPY_BUFF - mov edi, FLOPPY_FAT - - fcnew_1: - mov eax, dword [esi] - mov ebx, dword [esi+4] - mov ecx, dword [esi+8] - mov edx, ecx - shr edx, 4;8 ok - shr dx, 4;7 ok - xor ch, ch - shld ecx, ebx, 20;6 ok - shr cx, 4;5 ok - shld ebx, eax, 12 - and ebx, 0x0fffffff;4 ok - shr bx, 4;3 ok - shl eax, 4 - and eax, 0x0fffffff;2 ok - shr ax, 4;1 ok - mov dword [edi], eax - add edi, 4 - mov dword [edi], ebx - add edi, 4 - mov dword [edi], ecx - add edi, 4 - mov dword [edi], edx - add edi, 4 - add esi, 12 - - cmp edi, FLOPPY_FAT+2856*2;2849 clusters - jnz fcnew_1 - - popad - ret - -check_label: - pushad - mov [FDD_Track], 0; Цилиндр - mov [FDD_Head], 0; Сторона - mov [FDD_Sector], 1; Сектор - call FDDMotorON - call RecalibrateFDD - cmp [FDC_Status], 0 - jne fdc_status_error - call SeekTrack - cmp [FDC_Status], 0 - jne fdc_status_error - call ReadSectWithRetr - cmp [FDC_Status], 0 - jne fdc_status_error - mov esi, flp_label - mov edi, FDD_BUFF+39 - mov ecx, 15 - cld - rep cmpsb - je same_label - mov [root_read], 0 - mov [flp_fat], 0 -same_label: - mov esi, FDD_BUFF+39 - mov edi, flp_label - mov ecx, 15 - cld - rep movsb - popad - ret -fdc_status_error: - popad - ret - -save_flp_root: - pusha - call check_label - cmp [FDC_Status], 0 - jne unnecessary_root_save - cmp [root_read], 0 - je unnecessary_root_save - mov [FDD_Track], 0; Цилиндр - mov [FDD_Head], 1; Сторона - mov [FDD_Sector], 2; Сектор - mov esi, FLOPPY_BUFF - call SeekTrack -save_flp_root_1: - push esi - call take_data_from_application_1 - pop esi - add esi, 512 - call WriteSectWithRetr - cmp [FDC_Status], 0 - jne unnecessary_root_save - inc [FDD_Sector] - cmp [FDD_Sector], 16 - jne save_flp_root_1 -unnecessary_root_save: - popa - ret - -save_flp_fat: - pusha - call check_label - cmp [FDC_Status], 0 - jne unnecessary_flp_fat_save - cmp [flp_fat], 0 - je unnecessary_flp_fat_save - call restorefatchain_flp - mov [FDD_Track], 0; Цилиндр - mov [FDD_Head], 0; Сторона - mov [FDD_Sector], 2; Сектор - mov esi, FLOPPY_BUFF - call SeekTrack -save_flp_fat_1: - push esi - call take_data_from_application_1 - pop esi - add esi, 512 - call WriteSectWithRetr - cmp [FDC_Status], 0 - jne unnecessary_flp_fat_save - inc [FDD_Sector] - cmp [FDD_Sector], 19 - jne save_flp_fat_1 - mov [FDD_Sector], 1 - mov [FDD_Head], 1 - call take_data_from_application_1 - call WriteSectWithRetr - cmp [FDC_Status], 0 - jne unnecessary_flp_fat_save - mov [root_read], 0 -unnecessary_flp_fat_save: - popa - ret - - -restorefatchain_flp: ; restore fat chain - pushad - - mov esi, FLOPPY_FAT - mov edi, FLOPPY_BUFF - - fcnew2_1: - mov eax, dword [esi] - mov ebx, dword [esi+4] - shl ax, 4 - shl eax, 4 - shl bx, 4 - shr ebx, 4 - shrd eax, ebx, 8 - shr ebx, 8 - mov dword [edi], eax - add edi, 4 - mov word [edi], bx - add edi, 2 - add esi, 8 - - cmp edi, FLOPPY_BUFF+0x1200;4274 bytes - all used FAT - jb fcnew2_1 - - mov esi, FLOPPY_BUFF ; duplicate fat chain - mov edi, FLOPPY_BUFF+0x1200 - mov ecx, 0x1200/4 - cld - rep movsd - - popad - ret - - -save_chs_sector: - call calculate_chs - call WriteSectWithRetr - ret - -calculate_chs: - mov bl, [FDD_Track] - mov [old_track], bl - mov ebx, 18 - xor edx, edx - div ebx - inc edx - mov [FDD_Sector], dl - xor edx, edx - mov ebx, 2 - div ebx - mov [FDD_Track], al - mov [FDD_Head], 0 - test edx, edx - jz no_head_2 - inc [FDD_Head] -no_head_2: - mov dl, [old_track] - cmp dl, [FDD_Track] - je no_seek_track_1 - call SeekTrack -no_seek_track_1: - ret - - -get_cluster_of_a_path_flp: -;--------------------------------------------------------- -; input : EBX = pointer to a path string -; (example: the path "/files/data/document" become -; "files......data.......document...0" -; '.' = space char -; '0' = char(0) (ASCII=0) !!! ) -; output : if (CARRY=1) -> ERROR in the PATH -; if (CARRY=0) -> EAX=cluster -;--------------------------------------------------------- - - push edx - mov edx, ebx - -search_end_of_path_flp: - cmp [save_flag], 0 - jne search_end_of_path_flp_1 - cmp byte [edx], 0 - je found_end_of_path_flp - jmp search_end_of_path_flp_2 -search_end_of_path_flp_1: - cmp byte [edx+12], 0 - je found_end_of_path_flp -search_end_of_path_flp_2: - inc edx; '/' - call analyze_directory_flp - jc directory_not_found_flp - - mov eax, [ebx+20-2] ; read the HIGH 16bit cluster field - mov ax, [ebx+26] ; read the LOW 16bit cluster field - and eax, 0xfff ;[fatMASK] - add edx, 11 ; 8+3 (name+extension) - jmp search_end_of_path_flp - -found_end_of_path_flp: - inc edx - mov [pointer_file_name_flp], edx - pop edx - clc ; no errors - ret - -directory_not_found_flp: - pop edx - stc ; errors occour - ret - -analyze_directory_flp: -;-------------------------------- -; input : EAX = first cluster of the directory -; EBX = pointer to filename -; output : IF CARRY=0 EAX = sector where th file is found -; EBX = pointer in buffer -; [buffer .. buffer+511] -; ECX,EDX,EDI,EDI not changed -; IF CARRY=1 -;-------------------------------- - push ebx;[esp+16] - push ecx - push edx - push esi - push edi - - -adr56_flp: - mov [clust_tmp_flp], eax - add eax, 31 - pusha - call read_chs_sector - popa - cmp [FDC_Status], 0 - jne not_found_file_analyze_flp - - mov ecx, 512/32 - mov ebx, FDD_BUFF - -adr1_analyze_flp: - mov esi, edx;[esp+16] - mov edi, ebx - cld - push ecx - mov ecx, 11 - rep cmpsb - pop ecx - je found_file_analyze_flp - - add ebx, 32 - loop adr1_analyze_flp - - mov eax, [clust_tmp_flp] - shl eax, 1 ;find next cluster from FAT - add eax, FLOPPY_FAT - mov eax, [eax] - and eax, 4095 - cmp eax, 0x0ff8 - jb adr56_flp -not_found_file_analyze_flp: - pop edi - pop esi - pop edx - pop ecx - add esp, 4 - stc ;file not found - ret - -found_file_analyze_flp: - pop edi - pop esi - pop edx - pop ecx - add esp, 4 - clc ;file found - ret - - -; \begin{diamond} -fat_find_lfn: -; in: esi->name -; [esp+4] = next -; [esp+8] = first -; [esp+C]... - possibly parameters for first and next -; out: CF=1 - file not found, eax=error code -; else CF=0, esi->next name component, edi->direntry - pusha - lea eax, [esp+0Ch+20h] - call dword [eax-4] - jc .reterr - sub esp, 262*2 ; reserve place for LFN - push 0 ; for fat_get_name: read ASCII name -.l1: - lea ebp, [esp+4] - call fat_get_name - jc .l2 - call fat_compare_name - jz .found -.l2: - mov ebp, [esp+8+262*2+4] - lea eax, [esp+0Ch+20h+262*2+4] - call dword [eax-8] - jnc .l1 - add esp, 262*2+4 -.reterr: - mov [esp+28], eax - stc - popa - ret -.found: - add esp, 262*2+4 - mov ebp, [esp+8] -; if this is LFN entry, advance to true entry - cmp byte [edi+11], 0xF - jnz @f - lea eax, [esp+0Ch+20h] - call dword [eax-8] - jc .reterr -@@: - add esp, 8 ; CF=0 - push esi - push edi - popa - ret - -uglobal -; this is for delete support -fd_prev_sector dd ? -fd_prev_prev_sector dd ? -endg - -flp_root_next: - cmp edi, OS_BASE+0xD200-0x20 - jae @f - add edi, 0x20 - ret ; CF=0 -@@: -; read next sector - inc dword [eax] - cmp dword [eax], 14 - jae flp_root_first.readerr - push [fd_prev_sector] - pop [fd_prev_prev_sector] - push eax - mov eax, [eax] - add eax, 19-1 - mov [fd_prev_sector], eax - pop eax -flp_root_first: - mov eax, [eax] - pusha - add eax, 19 - call read_chs_sector - popa - cmp [FDC_Status], 0 - jnz .readerr - mov edi, FDD_BUFF - ret ; CF=0 -.readerr: - stc - ret - -flp_rootmem_first: - mov edi, FLOPPY_BUFF - clc - ret -flp_rootmem_next: - add edi, 0x20 - cmp edi, FLOPPY_BUFF+14*0x200 - cmc -flp_rootmem_next_write: -flp_rootmem_begin_write: -flp_rootmem_end_write: - ret -flp_rootmem_extend_dir: - stc - ret - -flp_notroot_next: - cmp edi, OS_BASE+0xD200-0x20 - jae flp_notroot_next_sector - add edi, 0x20 - ret ; CF=0 -flp_notroot_next_sector: - push ecx - mov ecx, [eax] - push [fd_prev_sector] - pop [fd_prev_prev_sector] - add ecx, 31 - mov [fd_prev_sector], ecx - mov ecx, [(ecx-31)*2+FLOPPY_FAT] - and ecx, 0xFFF - cmp ecx, 2849 - jae flp_notroot_first.err2 - mov [eax], ecx - pop ecx -flp_notroot_first: - mov eax, [eax] - cmp eax, 2 - jb .err - cmp eax, 2849 - jae .err - pusha - add eax, 31 - call read_chs_sector - popa - mov edi, FDD_BUFF - cmp [FDC_Status], 0 - jnz .err - ret ; CF=0 -.err2: - pop ecx -.err: - stc - ret -flp_notroot_begin_write: - pusha - mov eax, [eax] - add eax, 31 - call read_chs_sector - popa - ret -flp_notroot_end_write: - pusha - mov eax, [eax] - add eax, 31 - call save_chs_sector - popa - ret -flp_notroot_next_write: - cmp edi, OS_BASE+0xD200 - jae @f - ret -@@: - call flp_notroot_end_write - jmp flp_notroot_next_sector -flp_notroot_extend_dir: -; find free cluster in FAT - pusha - xor eax, eax - mov edi, FLOPPY_FAT - mov ecx, 2849 - repnz scasw - jnz .notfound - mov word [edi-2], 0xFFF ; mark as last cluster - sub edi, FLOPPY_FAT - shr edi, 1 - dec edi - mov eax, [esp+28] - mov ecx, [eax] - mov [FLOPPY_FAT+ecx*2], di - mov [eax], edi - xor eax, eax - mov edi, FDD_BUFF - mov ecx, 128 - rep stosd - popa - call flp_notroot_end_write - mov edi, FDD_BUFF - clc - ret -.notfound: - popa - stc - ret - -fd_find_lfn: -; in: esi+ebp -> name -; out: CF=1 - file not found -; else CF=0 and edi->direntry, eax=directory cluster (0 for root) - push esi edi - push 0 - push flp_root_first - push flp_root_next -.loop: - call fat_find_lfn - jc .notfound - cmp byte [esi], 0 - jz .found -.continue: - test byte [edi+11], 10h - jz .notfound - movzx eax, word [edi+26] ; cluster - mov [esp+8], eax - mov dword [esp+4], flp_notroot_first - mov dword [esp], flp_notroot_next - jmp .loop -.notfound: - add esp, 12 - pop edi esi - stc - ret -.found: - test ebp, ebp - jz @f - mov esi, ebp - xor ebp, ebp - jmp .continue -@@: - mov eax, [esp+8] - add eax, 31 - cmp dword [esp], flp_root_next - jnz @f - add eax, -31+19 -@@: - add esp, 16 ; CF=0 - pop esi - ret - -;---------------------------------------------------------------- -; -; fs_FloppyRead - LFN variant for reading floppy -; -; esi points to filename -; 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_FloppyRead: - call read_flp_fat - cmp byte [esi], 0 - jnz @f - or ebx, -1 - mov eax, 10 ; access denied - ret -@@: - push edi - call fd_find_lfn - jnc .found - pop edi - or ebx, -1 - mov eax, 5 ; file not found - ret -.found: - test ebx, ebx - jz .l1 - cmp dword [ebx+4], 0 - jz @f - xor ebx, ebx -.reteof: - mov eax, 6 ; EOF - pop edi - ret -@@: - mov ebx, [ebx] -.l1: - push ecx edx - push 0 - mov eax, [edi+28] - sub eax, ebx - jb .eof - cmp eax, ecx - jae @f - mov ecx, eax - mov byte [esp], 6 ; EOF -@@: - movzx edi, word [edi+26] -.new: - jecxz .done - test edi, edi - jz .eof - cmp edi, 0xFF8 - jae .eof - sub ebx, 512 - jae .skip - lea eax, [edi+31] - pusha - call read_chs_sector - popa - cmp [FDC_Status], 0 - jnz .err - lea eax, [FDD_BUFF+ebx+512] - neg ebx - push ecx - cmp ecx, ebx - jbe @f - mov ecx, ebx -@@: - mov ebx, edx - call memmove - add edx, ecx - sub [esp], ecx - pop ecx - xor ebx, ebx -.skip: - movzx edi, word [edi*2+FLOPPY_FAT] - jmp .new -.done: - mov ebx, edx - pop eax edx ecx edi - sub ebx, edx - ret -.eof: - mov ebx, edx - pop eax edx ecx - jmp .reteof -.err: - mov ebx, edx - pop eax edx ecx edi - sub ebx, edx - mov al, 11 - ret - -;---------------------------------------------------------------- -; -; fs_FloppyReadFolder - LFN variant for reading floppy folders -; -; esi points to filename -; 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_FloppyReadFolder: - call read_flp_fat - push edi - cmp byte [esi], 0 - jz .root - call fd_find_lfn - jnc .found - pop edi - or ebx, -1 - mov eax, ERROR_FILE_NOT_FOUND - ret -.found: - test byte [edi+11], 0x10 ; do not allow read files - jnz .found_dir - pop edi - or ebx, -1 - mov eax, ERROR_ACCESS_DENIED - ret -.found_dir: - movzx eax, word [edi+26] - add eax, 31 - push 0 - jmp .doit -.root: - mov eax, 19 - push 14 -.doit: - push ecx ebp - sub esp, 262*2 ; reserve space for LFN - mov ebp, esp - push dword [ebx+4] ; for fat_get_name: read ANSI/UNICODE names - mov ebx, [ebx] -; 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 esi, edi ; esi points to BDFE -.main_loop: - pusha - call read_chs_sector - popa - cmp [FDC_Status], 0 - jnz .error - mov edi, FDD_BUFF - push eax -.l1: - call fat_get_name - jc .l2 - cmp byte [edi+11], 0xF - jnz .do_bdfe - add edi, 0x20 - cmp edi, OS_BASE+0xD200 - jb .do_bdfe - pop eax - inc eax - dec byte [esp+262*2+12] - jz .done - jns @f -; read next sector from FAT - mov eax, [(eax-31-1)*2+FLOPPY_FAT] - and eax, 0xFFF - cmp eax, 0xFF8 - jae .done - add eax, 31 - mov byte [esp+262*2+12], 0 -@@: - pusha - call read_chs_sector - popa - cmp [FDC_Status], 0 - jnz .error - mov edi, FDD_BUFF - push eax -.do_bdfe: - inc dword [edx+8] ; new file found - dec ebx - jns .l2 - dec ecx - js .l2 - inc dword [edx+4] ; new file block copied - call fat_entry_to_bdfe -.l2: - add edi, 0x20 - cmp edi, OS_BASE+0xD200 - jb .l1 - pop eax - inc eax - dec byte [esp+262*2+12] - jz .done - jns @f -; read next sector from FAT - mov eax, [(eax-31-1)*2+FLOPPY_FAT] - and eax, 0xFFF - cmp eax, 0xFF8 - jae .done - add eax, 31 - mov byte [esp+262*2+12], 0 -@@: - jmp .main_loop -.error: - add esp, 262*2+4 - pop ebp ecx edi edi - or ebx, -1 - mov eax, ERROR_FILE_NOT_FOUND - ret -.done: - add esp, 262*2+4 - pop ebp - mov ebx, [edx+4] - xor eax, eax - dec ecx - js @f - mov al, ERROR_END_OF_FILE -@@: - pop ecx edi edi - ret - -;---------------------------------------------------------------- -; -; fs_FloppyRewrite - LFN variant for writing sys floppy -; -; esi points to filename -; ebx ignored (reserved) -; ecx number of bytes to write, 0+ -; edx mem location to data -; -; ret ebx = number of written bytes -; eax = 0 ok read or other = errormsg -; -;-------------------------------------------------------------- -@@: - mov eax, ERROR_ACCESS_DENIED - xor ebx, ebx - ret -fsfrfe2: - popad -fsfrfe: - mov eax, 11 - xor ebx, ebx - ret - -fs_FloppyCreateFolder: - mov al, 1 - jmp fs_FloppyRewrite.common - -fs_FloppyRewrite: - xor eax, eax -.common: - cmp byte [esi], 0 - jz @b - call read_flp_fat - cmp [FDC_Status], 0 - jnz fsfrfe - pushad - xor edi, edi - push esi - test ebp, ebp - jz @f - mov esi, ebp -@@: - lodsb - test al, al - jz @f - cmp al, '/' - jnz @b - lea edi, [esi-1] - jmp @b -@@: - pop esi - test edi, edi - jnz .noroot - test ebp, ebp - jnz .hasebp - call read_flp_root - cmp [FDC_Status], 0 - jnz fsfrfe2 - push flp_rootmem_extend_dir - push flp_rootmem_end_write - push flp_rootmem_next_write - push flp_rootmem_begin_write - xor ebp, ebp - push ebp - push flp_rootmem_first - push flp_rootmem_next - jmp .common1 -.hasebp: - mov eax, ERROR_ACCESS_DENIED - cmp byte [ebp], 0 - jz .ret1 - push ebp - xor ebp, ebp - call fd_find_lfn - pop esi - jc .notfound0 - jmp .common0 -.noroot: - mov eax, ERROR_ACCESS_DENIED - cmp byte [edi+1], 0 - jz .ret1 -; check existence - mov byte [edi], 0 - push edi - call fd_find_lfn - pop esi - mov byte [esi], '/' - jnc @f -.notfound0: - mov eax, ERROR_FILE_NOT_FOUND -.ret1: - mov [esp+28], eax - popad - xor ebx, ebx - ret -@@: - inc esi -.common0: - test byte [edi+11], 0x10 ; must be directory - mov eax, ERROR_ACCESS_DENIED - jz .ret1 - movzx ebp, word [edi+26] ; ebp=cluster - mov eax, ERROR_FAT_TABLE - cmp ebp, 2 - jb .ret1 - cmp ebp, 2849 - jae .ret1 - push flp_notroot_extend_dir - push flp_notroot_end_write - push flp_notroot_next_write - push flp_notroot_begin_write - push ebp - push flp_notroot_first - push flp_notroot_next -.common1: - call fat_find_lfn - jc .notfound -; found - test byte [edi+11], 10h - jz .exists_file -; found directory; if we are creating directory, return OK, -; if we are creating file, say "access denied" - add esp, 28 - popad - test al, al - mov eax, ERROR_ACCESS_DENIED - jz @f - mov al, 0 -@@: - xor ebx, ebx - ret -.exists_file: -; found file; if we are creating directory, return "access denied", -; if we are creating file, delete existing file and continue - cmp byte [esp+28+28], 0 - jz @f - add esp, 28 - popad - mov eax, ERROR_ACCESS_DENIED - xor ebx, ebx - ret -@@: -; delete FAT chain - push edi - xor eax, eax - mov dword [edi+28], eax ; zero size - xchg ax, word [edi+26] ; start cluster - test eax, eax - jz .done1 -@@: - cmp eax, 0xFF8 - jae .done1 - lea edi, [FLOPPY_FAT + eax*2] ; position in FAT - xor eax, eax - xchg ax, [edi] - jmp @b -.done1: - pop edi - call get_time_for_file - mov [edi+22], ax - call get_date_for_file - mov [edi+24], ax - mov [edi+18], ax - or byte [edi+11], 20h ; set 'archive' attribute - jmp .doit -.notfound: -; file is not found; generate short name - call fat_name_is_legal - jc @f - add esp, 28 - popad - mov eax, ERROR_FILE_NOT_FOUND - xor ebx, ebx - ret -@@: - sub esp, 12 - mov edi, esp - call fat_gen_short_name -.test_short_name_loop: - push esi edi ecx - mov esi, edi - lea eax, [esp+12+12+8] - mov [eax], ebp - call dword [eax-4] - jc .found -.test_short_name_entry: - cmp byte [edi+11], 0xF - jz .test_short_name_cont - mov ecx, 11 - push esi edi - repz cmpsb - pop edi esi - jz .short_name_found -.test_short_name_cont: - lea eax, [esp+12+12+8] - call dword [eax-8] - jnc .test_short_name_entry - jmp .found -.short_name_found: - pop ecx edi esi - call fat_next_short_name - jnc .test_short_name_loop -.disk_full: - add esp, 12+28 - popa - mov eax, ERROR_DISK_FULL - xor ebx, ebx - ret -.found: - pop ecx edi esi -; now find space in directory -; we need to save LFN <=> LFN is not equal to short name <=> generated name contains '~' - mov al, '~' - push ecx edi - mov ecx, 8 - repnz scasb - movi eax, 1 ; 1 entry - jnz .notilde -; we need ceil(strlen(esi)/13) additional entries = floor((strlen(esi)+12+13)/13) total - xor eax, eax -@@: - cmp byte [esi], 0 - jz @f - inc esi - inc eax - jmp @b -@@: - sub esi, eax - add eax, 12+13 - mov ecx, 13 - push edx - cdq - div ecx - pop edx -.notilde: - push -1 - push -1 -; find successive entries in directory - xor ecx, ecx - push eax - lea eax, [esp+12+8+12+8] - mov [eax], ebp - call dword [eax-4] - pop eax - jnc .scan_dir -.fsfrfe3: - add esp, 8+8+12+28 - popad - mov eax, 11 - xor ebx, ebx - ret -.scan_dir: - cmp byte [edi], 0 - jz .free - cmp byte [edi], 0xE5 - jz .free - xor ecx, ecx -.scan_cont: - push eax - lea eax, [esp+12+8+12+8] - call dword [eax-8] - pop eax - jnc .scan_dir - cmp [FDC_Status], 0 - jnz .fsfrfe3 - push eax - lea eax, [esp+12+8+12+8] - call dword [eax+16] ; extend directory - pop eax - jnc .scan_dir - add esp, 8+8+12+28 - popad - mov eax, ERROR_DISK_FULL - xor ebx, ebx - ret -.free: - test ecx, ecx - jnz @f - mov [esp], edi - mov ecx, [esp+8+8+12+8] - mov [esp+4], ecx - xor ecx, ecx -@@: - inc ecx - cmp ecx, eax - jb .scan_cont -; found! -; calculate name checksum - push esi ecx - mov esi, [esp+8+8] - mov ecx, 11 - xor eax, eax -@@: - ror al, 1 - add al, [esi] - inc esi - loop @b - pop ecx esi - pop edi - pop dword [esp+8+12+8] -; edi points to first entry in free chunk - dec ecx - jz .nolfn - push esi - push eax - lea eax, [esp+8+8+12+8] - call dword [eax+4] ; begin write - mov al, 40h -.writelfn: - or al, cl - mov esi, [esp+4] - push ecx - dec ecx - imul ecx, 13 - add esi, ecx - stosb - mov cl, 5 - call fs_RamdiskRewrite.read_symbols - mov ax, 0xF - stosw - mov al, [esp+4] - stosb - mov cl, 6 - call fs_RamdiskRewrite.read_symbols - xor eax, eax - stosw - mov cl, 2 - call fs_RamdiskRewrite.read_symbols - pop ecx - lea eax, [esp+8+8+12+8] - call dword [eax+8] ; next write - xor eax, eax - loop .writelfn - pop eax - pop esi -; lea eax, [esp+8+12+8] -; call dword [eax+12] ; end write -.nolfn: - xchg esi, [esp] - mov ecx, 11 - rep movsb - mov word [edi], 20h ; attributes - sub edi, 11 - pop esi ecx - add esp, 12 - mov byte [edi+13], 0 ; tenths of a second at file creation time - call get_time_for_file - mov [edi+14], ax ; creation time - mov [edi+22], ax ; last write time - call get_date_for_file - mov [edi+16], ax ; creation date - mov [edi+24], ax ; last write date - mov [edi+18], ax ; last access date - and word [edi+20], 0 ; high word of cluster - and word [edi+26], 0 ; low word of cluster - to be filled - and dword [edi+28], 0 ; file size - to be filled - cmp byte [esp+28+28], 0 - jz .doit -; create directory - mov byte [edi+11], 10h ; attributes: folder - mov ecx, 32*2 - mov edx, edi -.doit: - lea eax, [esp+8] - call dword [eax+12] ; flush directory - push ecx - push edi - push 0 - mov esi, edx - test ecx, ecx - jz .done - mov ecx, 2849 - mov edi, FLOPPY_FAT - push 0 ; first cluster -.write_loop: -; allocate new cluster - xor eax, eax - repnz scasw - mov al, ERROR_DISK_FULL - jnz .ret - dec edi - dec edi - - mov eax, edi - sub eax, FLOPPY_FAT - - shr eax, 1 ; eax = cluster - mov word [edi], 0xFFF ; mark as last cluster - xchg edi, [esp+4] - cmp dword [esp], 0 - jz .first - stosw - jmp @f -.first: - mov [esp], eax -@@: - mov edi, [esp+4] - inc ecx -; write data - push ecx edi - mov ecx, 512 - cmp dword [esp+20], ecx - jae @f - mov ecx, [esp+20] -@@: - mov edi, FDD_BUFF - cmp byte [esp+24+28+28], 0 - jnz .writedir - push ecx - rep movsb - pop ecx -.writedircont: - push ecx - sub ecx, 512 - neg ecx - push eax - xor eax, eax - rep stosb - pop eax - add eax, 31 - pusha - call save_chs_sector - popa - pop ecx - cmp [FDC_Status], 0 - jnz .diskerr - sub [esp+20], ecx - pop edi ecx - jnz .write_loop -.done: - xor eax, eax -.ret: - pop ebx edi edi ecx - mov [esp+28+28], eax - lea eax, [esp+8] - call dword [eax+4] - mov [edi+26], bx - mov ebx, esi - sub ebx, edx - mov [edi+28], ebx - call dword [eax+12] - mov [esp+28+16], ebx - test ebp, ebp - jnz @f - call save_flp_root -@@: - add esp, 28 - cmp [FDC_Status], 0 - jnz .err3 - call save_flp_fat - cmp [FDC_Status], 0 - jnz .err3 - popa - ret -.err3: - popa - mov al, 11 - xor ebx, ebx - ret -.diskerr: - sub esi, ecx - mov eax, 11 - pop edi ecx - jmp .ret -.writedir: - push ecx - mov ecx, 32/4 - push ecx esi - rep movsd - pop esi ecx - mov dword [edi-32], '. ' - mov dword [edi-32+4], ' ' - mov dword [edi-32+8], ' ' - mov byte [edi-32+11], 10h - mov word [edi-32+26], ax - push esi - rep movsd - pop esi - mov dword [edi-32], '.. ' - mov dword [edi-32+4], ' ' - mov dword [edi-32+8], ' ' - mov byte [edi-32+11], 10h - mov ecx, [esp+28+8] - mov word [edi-32+26], cx - pop ecx - jmp .writedircont - -;---------------------------------------------------------------- -; -; fs_FloppyWrite - LFN variant for writing to floppy -; -; esi points to filename -; ebx pointer to 64-bit number = first wanted byte, 0+ -; may be ebx=0 - start from first byte -; ecx number of bytes to write, 0+ -; edx mem location to data -; -; ret ebx = bytes written (maybe 0) -; eax = 0 ok write or other = errormsg -; -;-------------------------------------------------------------- - -@@: - push ERROR_ACCESS_DENIED -fs_FloppyWrite.ret0: - pop eax - xor ebx, ebx - ret - -fs_FloppyWrite.ret11: - push 11 - jmp fs_FloppyWrite.ret0 - -fs_FloppyWrite: - cmp byte [esi], 0 - jz @b - call read_flp_fat - cmp [FDC_Status], 0 - jnz .ret11 - pushad - call fd_find_lfn - jnc .found - popad - push ERROR_FILE_NOT_FOUND - jmp .ret0 -.found: -; FAT does not support files larger than 4GB - test ebx, ebx - jz .l1 - cmp dword [ebx+4], 0 - jz @f -.eof: - popad - push ERROR_END_OF_FILE - jmp .ret0 -@@: - mov ebx, [ebx] -.l1: -; now edi points to direntry, ebx=start byte to write, -; ecx=number of bytes to write, edx=data pointer - -; extend file if needed - add ecx, ebx - jc .eof ; FAT does not support files larger than 4GB - push eax ; save directory cluster - push 0 ; return value=0 - - call get_time_for_file - mov [edi+22], ax ; last write time - call get_date_for_file - mov [edi+24], ax ; last write date - mov [edi+18], ax ; last access date - - push dword [edi+28] ; save current file size - cmp ecx, [edi+28] - jbe .length_ok - cmp ecx, ebx - jz .length_ok - call floppy_extend_file - jnc .length_ok - mov [esp+4], eax -; floppy_extend_file can return two error codes: FAT table error or disk full. -; First case is fatal error, in second case we may write some data - cmp al, ERROR_DISK_FULL - jz .disk_full - pop eax - pop eax - mov [esp+4+28], eax - pop eax - popad - xor ebx, ebx - ret -.disk_full: -; correct number of bytes to write - mov ecx, [edi+28] - cmp ecx, ebx - ja .length_ok -.ret: - pop eax - pop eax - mov [esp+4+28], eax ; eax=return value - pop eax - sub edx, [esp+20] - mov [esp+16], edx ; ebx=number of written bytes - popad - ret -.length_ok: -; save FAT & directory -; note that directory must be saved first because save_flp_fat uses buffer at 0xD000 - mov esi, [edi+28] - movzx edi, word [edi+26] ; starting cluster - mov eax, [esp+8] - pusha - call save_chs_sector - popa - cmp [FDC_Status], 0 - jnz .device_err - call save_flp_fat - cmp [FDC_Status], 0 - jz @f -.device_err: - mov byte [esp+4], 11 - jmp .ret -@@: - -; now ebx=start pos, ecx=end pos, both lie inside file - sub ecx, ebx - jz .ret - -.write_loop: -; skip unmodified sectors - cmp dword [esp], 0x200 - jb .modify - sub ebx, 0x200 - jae .skip - add ebx, 0x200 -.modify: - lea eax, [edi+31] ; current sector -; get length of data in current sector - push ecx - sub ebx, 0x200 - jb .hasdata - neg ebx - xor ecx, ecx - jmp @f -.hasdata: - neg ebx - cmp ecx, ebx - jbe @f - mov ecx, ebx -@@: -; load sector if needed - cmp dword [esp+4], 0 ; we don't need to read uninitialized data - jz .noread - cmp ecx, 0x200 ; we don't need to read sector if it is fully rewritten - jz .noread - cmp ecx, esi ; (same for the last sector) - jz .noread - pusha - call read_chs_sector - popa - cmp [FDC_Status], 0 - jz @f -.device_err2: - pop ecx - jmp .device_err -@@: -.noread: -; zero uninitialized data if file was extended (because floppy_extend_file does not this) - push eax ecx edi - xor eax, eax - mov ecx, 0x200 - sub ecx, [esp+4+12] - jbe @f - mov edi, FDD_BUFF - add edi, [esp+4+12] - rep stosb -@@: -; zero uninitialized data in the last sector - mov ecx, 0x200 - sub ecx, esi - jbe @f - mov edi, FDD_BUFF - add edi, esi - rep stosb -@@: - pop edi ecx eax -; copy new data - push eax - mov eax, edx - neg ebx - jecxz @f - add ebx, FDD_BUFF+0x200 - call memmove - xor ebx, ebx -@@: - pop eax -; save sector - pusha - call save_chs_sector - popa - cmp [FDC_Status], 0 - jnz .device_err2 - add edx, ecx - sub [esp], ecx - pop ecx - jz .done -.skip: -.next_cluster: - movzx edi, word [edi*2+FLOPPY_FAT] - sub esi, 0x200 - jae @f - xor esi, esi -@@: - sub dword [esp], 0x200 - jae .write_loop - and dword [esp], 0 - jmp .write_loop -.done: - jmp .ret - -floppy_extend_file.zero_size: - xor eax, eax - jmp floppy_extend_file.start_extend - -; extends file on floppy to given size (new data area is undefined) -; in: edi->direntry, ecx=new size -; out: CF=0 => OK, eax=0 -; CF=1 => error, eax=code (ERROR_FAT_TABLE or ERROR_DISK_FULL) -floppy_extend_file: - push ecx -; find the last cluster of file - movzx eax, word [edi+26] ; first cluster - mov ecx, [edi+28] - jecxz .zero_size -@@: - sub ecx, 0x200 - jbe @f - mov eax, [eax*2+FLOPPY_FAT] - and eax, 0xFFF - jz .fat_err - cmp eax, 0xFF8 - jb @b -.fat_err: - pop ecx - movi eax, ERROR_FAT_TABLE - stc - ret -@@: - push eax - mov eax, [eax*2+FLOPPY_FAT] - and eax, 0xFFF - cmp eax, 0xFF8 - pop eax - jb .fat_err -; set length to full number of sectors - sub [edi+28], ecx -.start_extend: - pop ecx -; now do extend - push edx esi - mov esi, FLOPPY_FAT+2*2 ; start scan from cluster 2 - mov edx, 2847 ; number of clusters to scan -.extend_loop: - cmp [edi+28], ecx - jae .extend_done -; add new sector - push ecx - push edi -.scan: - mov ecx, edx - mov edi, esi - jecxz .disk_full - push eax - xor eax, eax - repnz scasw - pop eax - jnz .disk_full - mov word [edi-2], 0xFFF - mov esi, edi - mov edx, ecx - sub edi, FLOPPY_FAT - shr edi, 1 - dec edi ; now edi=new cluster - test eax, eax - jz .first_cluster - mov [FLOPPY_FAT+eax*2], di - jmp @f -.first_cluster: - pop eax ; eax->direntry - push eax - mov [eax+26], di -@@: - mov eax, edi ; eax=new cluster - pop edi ; edi->direntry - pop ecx ; ecx=required size - add dword [edi+28], 0x200 - jmp .extend_loop -.extend_done: - mov [edi+28], ecx - pop esi edx - xor eax, eax ; CF=0 - ret -.disk_full: - pop edi ecx - pop esi edx - stc - movi eax, ERROR_DISK_FULL - ret - -;---------------------------------------------------------------- -; -; fs_FloppySetFileEnd - set end of file on floppy -; -; esi points to filename -; ebx points to 64-bit number = new file size -; ecx ignored (reserved) -; edx ignored (reserved) -; -; ret eax = 0 ok or other = errormsg -; -;-------------------------------------------------------------- -fs_FloppySetFileEnd: - call read_flp_fat - cmp [FDC_Status], 0 - jnz ret11 - cmp byte [esi], 0 - jnz @f -.access_denied: - push ERROR_ACCESS_DENIED - jmp .ret -@@: - push edi - call fd_find_lfn - jnc @f - pop edi - push ERROR_FILE_NOT_FOUND -.ret: - pop eax - jmp .doret -@@: -; must not be directory - test byte [edi+11], 10h - jz @f - pop edi - jmp .access_denied -@@: -; file size must not exceed 4 Gb - cmp dword [ebx+4], 0 - jz @f - pop edi - push ERROR_END_OF_FILE - jmp .ret -@@: - push eax -; set file modification date/time to current - call fat_update_datetime - mov eax, [ebx] - cmp eax, [edi+28] - jb .truncate - ja .expand - pop eax - pushad - call save_chs_sector - popad - pop edi - xor eax, eax - cmp [FDC_Status], 0 - jz @f - mov al, 11 -@@: -.doret: - ret -.expand: - push ecx - push dword [edi+28] ; save old size - mov ecx, eax - call floppy_extend_file - push eax ; return code - jnc .expand_ok - cmp al, ERROR_DISK_FULL - jz .disk_full - pop eax ecx ecx edi edi - jmp .doret -.device_err: - pop eax -.device_err2: - pop ecx ecx eax edi - push 11 - jmp .ret -.disk_full: -.expand_ok: -; save directory & FAT - mov eax, [edi+28] - xchg eax, [esp+12] - movzx edi, word [edi+26] - pusha - call save_chs_sector - popa - cmp [FDC_Status], 0 - jnz .device_err - call save_flp_fat - cmp [FDC_Status], 0 - jnz .device_err -; now zero new data -; edi = current cluster, [esp+12]=new size, [esp+4]=old size, [esp]=return code -.zero_loop: - sub dword [esp+4], 0x200 - jae .next_cluster - cmp dword [esp+4], -0x200 - jz .noread - lea eax, [edi+31] - pusha - call read_chs_sector - popa - cmp [FDC_Status], 0 - jnz .err_next -.noread: - mov ecx, [esp+4] - neg ecx - push edi - mov edi, FDD_BUFF+0x200 - add edi, [esp+8] - xor eax, eax - mov [esp+8], eax - rep stosb - pop edi - lea eax, [edi+31] - pusha - call save_chs_sector - popa - cmp [FDC_Status], 0 - jz .next_cluster -.err_next: - mov byte [esp], 11 -.next_cluster: - sub dword [esp+12], 0x200 - jbe .expand_done - movzx edi, word [FLOPPY_FAT+edi*2] - jmp .zero_loop -.expand_done: - pop eax ecx ecx edi edi - jmp .doret -.truncate: - mov [edi+28], eax - push ecx - movzx ecx, word [edi+26] - test eax, eax - jz .zero_size -; find new last sector -@@: - sub eax, 0x200 - jbe @f - movzx ecx, word [FLOPPY_FAT+ecx*2] - jmp @b -@@: -; we will zero data at the end of last sector - remember it - push ecx -; terminate FAT chain - lea ecx, [FLOPPY_FAT+ecx+ecx] - push dword [ecx] - mov word [ecx], 0xFFF - pop ecx - and ecx, 0xFFF - jmp .delete -.zero_size: - and word [edi+26], 0 - push 0 -.delete: -; delete FAT chain starting with ecx -; mark all clusters as free - cmp ecx, 0xFF8 - jae .deleted - lea ecx, [FLOPPY_FAT+ecx+ecx] - push dword [ecx] - and word [ecx], 0 - pop ecx - and ecx, 0xFFF - jmp .delete -.deleted: - mov edi, [edi+28] -; save directory & FAT - mov eax, [esp+8] - pusha - call save_chs_sector - popa - cmp [FDC_Status], 0 - jnz .device_err2 - call save_flp_fat - cmp [FDC_Status], 0 - jnz .device_err2 -; zero last sector, ignore errors - pop eax - add eax, 31 - and edi, 0x1FF - jz .truncate_done - - pusha - call read_chs_sector - popa - add edi, FDD_BUFF - mov ecx, FDD_BUFF+0x200 - sub ecx, edi - push eax - xor eax, eax - rep stosb - pop eax - pusha - call save_chs_sector - popa -.truncate_done: - pop ecx eax edi - xor eax, eax - jmp .doret - -fs_FloppyGetFileInfo: - call read_flp_fat - cmp [FDC_Status], 0 - jnz ret11 - cmp byte [esi], 0 - jnz @f - mov eax, 2 ; unsupported - ret -@@: - push edi - call fd_find_lfn - jmp fs_GetFileInfo_finish - -ret11: - mov eax, 11 - ret - -fs_FloppySetFileInfo: - call read_flp_fat - cmp [FDC_Status], 0 - jnz ret11 - cmp byte [esi], 0 - jnz @f - mov eax, 2 ; unsupported - ret -@@: - push edi - call fd_find_lfn - jnc @f - pop edi - mov eax, ERROR_FILE_NOT_FOUND - ret -@@: - push eax - call bdfe_to_fat_entry - pop eax - pusha - call save_chs_sector - popa - pop edi - xor eax, eax - cmp [FDC_Status], al - jz @f - mov al, 11 -@@: - ret - -;---------------------------------------------------------------- -; -; fs_FloppyDelete - delete file or empty folder from floppy -; -; esi points to filename -; -; ret eax = 0 ok or other = errormsg -; -;-------------------------------------------------------------- -fs_FloppyDelete: - call read_flp_fat - cmp [FDC_Status], 0 - jz @f - push 11 - jmp .pop_ret -@@: - cmp byte [esi], 0 - jnz @f -; cannot delete root! -.access_denied: - push ERROR_ACCESS_DENIED -.pop_ret: - pop eax - ret -@@: - and [fd_prev_sector], 0 - and [fd_prev_prev_sector], 0 - push edi - call fd_find_lfn - jnc .found - pop edi - push ERROR_FILE_NOT_FOUND - jmp .pop_ret -.found: - cmp dword [edi], '. ' - jz .access_denied2 - cmp dword [edi], '.. ' - jz .access_denied2 - test byte [edi+11], 10h - jz .dodel -; we can delete only empty folders! - push eax - movzx eax, word [edi+26] - push ebx - pusha - add eax, 31 - call read_chs_sector - popa - mov ebx, FDD_BUFF + 2*0x20 -.checkempty: - cmp byte [ebx], 0 - jz .empty - cmp byte [ebx], 0xE5 - jnz .notempty - add ebx, 0x20 - cmp ebx, FDD_BUFF + 0x200 - jb .checkempty - movzx eax, word [FLOPPY_FAT + eax*2] - pusha - add eax, 31 - call read_chs_sector - popa - mov ebx, FDD_BUFF - jmp .checkempty -.notempty: - pop ebx - pop eax -.access_denied2: - pop edi - jmp .access_denied -.empty: - pop ebx - pop eax - pusha - call read_chs_sector - popa -.dodel: - push eax - movzx eax, word [edi+26] - xchg eax, [esp] -; delete folder entry - mov byte [edi], 0xE5 -; delete LFN (if present) -.lfndel: - cmp edi, FDD_BUFF - ja @f - cmp [fd_prev_sector], 0 - jz .lfndone - push [fd_prev_sector] - push [fd_prev_prev_sector] - pop [fd_prev_sector] - and [fd_prev_prev_sector], 0 - pusha - call save_chs_sector - popa - pop eax - pusha - call read_chs_sector - popa - mov edi, FDD_BUFF+0x200 -@@: - sub edi, 0x20 - cmp byte [edi], 0xE5 - jz .lfndone - cmp byte [edi+11], 0xF - jnz .lfndone - mov byte [edi], 0xE5 - jmp .lfndel -.lfndone: - pusha - call save_chs_sector - popa -; delete FAT chain - pop eax -@@: - cmp eax, 2 - jb .done - cmp eax, 0xFF8 - jae .done - lea eax, [FLOPPY_FAT + eax*2] - push dword [eax] - and word [eax], 0 - pop eax - and eax, 0xFFF - jmp @b -.done: - call save_flp_fat - pop edi - xor eax, eax - ret - -; \end{diamond} diff --git a/kernel/branches/Kolibri-acpi/fs/fs-et.inc b/kernel/branches/Kolibri-acpi/fs/fs-et.inc deleted file mode 100644 index 82a23d86c7..0000000000 --- a/kernel/branches/Kolibri-acpi/fs/fs-et.inc +++ /dev/null @@ -1,12 +0,0 @@ -dir0: - db 'KÕVAKETAS ' - db 'MÄLUKETAS ' - db 'FLOPPIKETAS' - db 0 - -dir1: - db 'ESIMENE ' - db 'TEINE ' - db 'KOLAMS ' - db 'NELJAS ' - db 0 \ No newline at end of file diff --git a/kernel/branches/Kolibri-acpi/fs/fs-sp.inc b/kernel/branches/Kolibri-acpi/fs/fs-sp.inc deleted file mode 100644 index a7e64e12ac..0000000000 --- a/kernel/branches/Kolibri-acpi/fs/fs-sp.inc +++ /dev/null @@ -1,13 +0,0 @@ -dir0: - db 'DISCO DURO ' - db 'UNIDAD RAM ' - db 'DISQUETE ' - db 0 - -dir1: - db 'PRIMERO ' - db 'SEGUNDO ' - db 'TERCERO ' - db 'CUARTO ' - db 0 - diff --git a/kernel/branches/Kolibri-acpi/fs/fs.inc b/kernel/branches/Kolibri-acpi/fs/fs.inc deleted file mode 100644 index 65e6862098..0000000000 --- a/kernel/branches/Kolibri-acpi/fs/fs.inc +++ /dev/null @@ -1,682 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; ;; -;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; -;; Distributed under terms of the GNU General Public License ;; -;; ;; -;; ;; -;; System service for filesystem call ;; -;; (C) 2004 Ville Turjanmaa, License: GPL ;; -;; 29.04.2006 Elimination of hangup after the ;; -;; expiration hd_wait_timeout (for LBA) - Mario79 ;; -;; 15.01.2005 get file size/attr/date, ;; -;; file_append (only for hd) - ATV ;; -;; 23.11.2004 test if hd/partition is set - ATV ;; -;; 18.11.2004 get_disk_info and more error codes - ATV ;; -;; 08.11.2004 expand_pathz and rename (only for hd) - ATV ;; -;; 20.10.2004 Makedir/Removedir (only for hd) - ATV ;; -;; ;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -$Revision$ - - -iglobal - -if lang eq sp -include 'fs/fs-sp.inc' -else if lang eq et -include 'fs/fs-et.inc' -else -dir0: - db 'HARDDISK ' - db 'RAMDISK ' - db 'FLOPPYDISK ' - db 0 - -dir1: - db 'FIRST ' - db 'SECOND ' - db 'THIRD ' - db 'FOURTH ' - db 0 -end if - -not_select_IDE db 0 - -hd_address_table: - dd 0x1f0,0x00,0x1f0,0x10 - dd 0x170,0x00,0x170,0x10 -endg - -file_system: - -; IN: -; -; eax = 0 ; read file /RamDisk/First 6 -; eax = 8 ; lba read -; eax = 15 ; get_disk_info -; -; OUT: -; -; eax = 0 : read ok -; eax = 1 : no hd base and/or partition defined -; eax = 2 : function is unsupported for this FS -; eax = 3 : unknown FS -; eax = 4 : partition not defined at hd -; eax = 5 : file not found -; eax = 6 : end of file -; eax = 7 : memory pointer not in application area -; eax = 8 : disk full -; eax = 9 : fat table corrupted -; eax = 10 : access denied -; eax = 11 : disk error -; -; ebx = size - -; \begin{diamond}[18.03.2006] -; for subfunction 16 (start application) error codes must be negative -; because positive values are valid PIDs -; so possible return values are: -; eax > 0 : process created, eax=PID - -; -0x10 <= eax < 0 : -eax is filesystem error code: -; eax = -1 = 0xFFFFFFFF : no hd base and/or partition defined -; eax = -3 = 0xFFFFFFFD : unknown FS -; eax = -5 = 0xFFFFFFFB : file not found -; eax = -6 = 0xFFFFFFFA : unexpected end of file (probably not executable file) -; eax = -9 = 0xFFFFFFF7 : fat table corrupted -; eax = -10 = 0xFFFFFFF6 : access denied - -; -0x20 <= eax < -0x10: eax is process creation error code: -; eax = -0x20 = 0xFFFFFFE0 : too many processes -; eax = -0x1F = 0xFFFFFFE1 : not Menuet/Kolibri executable -; eax = -0x1E = 0xFFFFFFE2 : no memory - -; ebx is not changed - -; \end{diamond}[18.03.2006] - - ; Extract parameters - ; add eax, std_application_base_address ; abs start of info block - - cmp dword [eax+0], 15; GET_DISK_INFO - je fs_info - - cmp dword [CURRENT_TASK], 1; no memory checks for kernel requests - jz no_checks_for_kernel - mov edx, eax - cmp dword [eax+0], 1 - jnz .usual_check - mov ebx, [eax+12] - ; add ebx,std_application_base_address - mov ecx, [eax+8] - call check_region - test eax, eax - jnz area_in_app_mem - -.error_output: - mov esi, buffer_failed - call sys_msg_board_str -; mov eax,7 - mov dword [esp+36], 7 - ret -iglobal - buffer_failed db 'K : Buffer check failed',13,10,0 -endg -.usual_check: - cmp dword [eax+0], 0 - mov ecx, 512 - jnz .small_size - mov ecx, [eax+8] - shl ecx, 9 -.small_size: - mov ebx, [eax+12] - ; add ebx,std_application_base_address - call check_region - test eax, eax - jz .error_output - area_in_app_mem: - mov eax, edx - no_checks_for_kernel: - - fs_read: - - mov ebx, [eax+20] ; program wants root directory ? - test bl, bl - je fs_getroot - test bh, bh - jne fs_noroot - fs_getroot: -; \begin{diamond}[18.03.2006] -; root - only read is allowed -; other operations return "access denied", eax=10 -; (execute operation returns eax=-10) - cmp dword [eax], 0 - jz .read_root - mov dword [esp+36], 10 - ret -.read_root: -; \end{diamond}[18.03.2006] - mov esi, dir0 - mov edi, [eax+12] - ; add edi,std_application_base_address - mov ecx, 11 - push ecx -; cld ; already is - rep movsb - mov al, 0x10 - stosb - add edi, 32-11-1 - pop ecx - rep movsb - stosb - and dword [esp+36], 0; ok read - mov dword [esp+24], 32*2; size of root - ret - - fs_info: ;start of code - Mihasik - push eax - cmp [eax+21], byte 'r' - je fs_info_r - cmp [eax+21], byte 'R' - je fs_info_r - mov eax, 3 ;if unknown disk - xor ebx, ebx - xor ecx, ecx - xor edx, edx - jmp fs_info1 - fs_info_r: - call ramdisk_free_space;if ramdisk - mov ecx, edi ;free space in ecx - shr ecx, 9 ;free clusters - mov ebx, 2847 ;total clusters - mov edx, 512 ;cluster size - xor eax, eax ;always 0 - fs_info1: - pop edi - mov [esp+36], eax - mov [esp+24], ebx ; total clusters on disk - mov [esp+32], ecx ; free clusters on disk - mov [edi], edx ; cluster size in bytes - ret ;end of code - Mihasik - - fs_noroot: - - push dword [eax+0] ; read/write/delete/.../makedir/rename/lba/run - push dword [eax+4] ; 512 block number to read - push dword [eax+8] ; bytes to write/append or 512 blocks to read - mov ebx, [eax+12] - ; add ebx,std_application_base_address - push ebx ; abs start of return/save area - - lea esi, [eax+20] ; abs start of dir + filename - mov edi, [eax+16] - ; add edi,std_application_base_address ; abs start of work area - - call expand_pathz - - push edi ; dir start - push ebx ; name of file start - - mov eax, [edi+1] - cmp eax, 'RD ' - je fs_yesramdisk - cmp eax, 'RAMD' - jne fs_noramdisk - - fs_yesramdisk: - - cmp byte [edi+1+11], 0 - je fs_give_dir1 - - mov eax, [edi+1+12] - cmp eax, '1 ' - je fs_yesramdisk_first - cmp eax, 'FIRS' - jne fs_noramdisk - - fs_yesramdisk_first: - - cmp dword [esp+20], 8; LBA read ramdisk - jne fs_no_LBA_read_ramdisk - - mov eax, [esp+16] ; LBA block to read - mov ecx, [esp+8] ; abs pointer to return area - - call LBA_read_ramdisk - jmp file_system_return - - - fs_no_LBA_read_ramdisk: - - cmp dword [esp+20], 0; READ - jne fs_noramdisk_read - - mov eax, [esp+4] ; fname - add eax, 2*12+1 - mov ebx, [esp+16] ; block start - inc ebx - mov ecx, [esp+12] ; block count - mov edx, [esp+8] ; return - mov esi, [esp+0] - sub esi, eax - add esi, 12+1 ; file name length - call fileread - - jmp file_system_return - - - fs_noramdisk_read: - fs_noramdisk: - - ;******************************************************************** - mov eax, [edi+1] - cmp eax, 'FD ' - je fs_yesflpdisk - cmp eax, 'FLOP' - jne fs_noflpdisk - - fs_yesflpdisk: - call reserve_flp - - cmp byte [edi+1+11], 0 - je fs_give_dir1 - - mov eax, [edi+1+12] - cmp eax, '1 ' - je fs_yesflpdisk_first - cmp eax, 'FIRS' - je fs_yesflpdisk_first - cmp eax, '2 ' - je fs_yesflpdisk_second - cmp eax, 'SECO' - jne fs_noflpdisk - jmp fs_yesflpdisk_second - - fs_yesflpdisk_first: - mov [flp_number], 1 - jmp fs_yesflpdisk_start - fs_yesflpdisk_second: - mov [flp_number], 2 - fs_yesflpdisk_start: - cmp dword [esp+20], 0; READ - jne fs_noflpdisk_read - - mov eax, [esp+4] ; fname - add eax, 2*12+1 - mov ebx, [esp+16] ; block start - inc ebx - mov ecx, [esp+12] ; block count - mov edx, [esp+8] ; return - mov esi, [esp+0] - sub esi, eax - add esi, 12+1 ; file name length - call floppy_fileread - - jmp file_system_return - - - fs_noflpdisk_read: - fs_noflpdisk: - ;***************************************************************** - - old_path_harddisk: - mov eax, [edi+1] - cmp eax, 'HD ' - je fs_yesharddisk - cmp eax, 'HARD' - jne fs_noharddisk - - fs_yesharddisk: - cmp dword [esp+20], 8; LBA read - jne fs_no_LBA_read - mov eax, [esp+16] ; LBA block to read - lea ebx, [edi+1+12] ; pointer to FIRST/SECOND/THIRD/FOURTH - mov ecx, [esp+8] ; abs pointer to return area - call LBA_read - jmp file_system_return - - fs_no_LBA_read: - -hd_err_return: - - fs_noharddisk: -; \begin{diamond}[18.03.2006] - mov eax, 5 ; file not found -; а может быть, возвращать другой код ошибки? - mov ebx, [esp+24+24]; do not change ebx in application -; \end{diamond}[18.03.2006] - - file_system_return: - - add esp, 24 - - mov [esp+36], eax - mov [esp+24], ebx - ret - - - fs_give_dir1: - -; \begin{diamond}[18.03.2006] -; /RD,/FD,/HD - only read is allowed -; other operations return "access denied", eax=10 -; (execute operation returns eax=-10) - cmp dword [esp+20], 0 - jz .read - add esp, 20 - pop ecx - mov dword [esp+36], 10 - ret -.read: -; \end{diamond}[18.03.2006] - mov al, 0x10 - mov ebx, 1 - mov edi, [esp+8] - mov esi, dir1 - fs_d1_new: - mov ecx, 11 -; cld - rep movsb - stosb - add edi, 32-11-1 - dec ebx - jne fs_d1_new - - add esp, 24 - - and dword [esp+36], 0; ok read - mov dword [esp+24], 32*1; dir/data size - ret - - - -LBA_read_ramdisk: - - cmp [lba_read_enabled], 1 - je lbarrl1 - - xor ebx, ebx - mov eax, 2 - ret - - lbarrl1: - - cmp eax, 18*2*80 - jb lbarrl2 - xor ebx, ebx - mov eax, 3 - ret - - lbarrl2: - - pushad - - call restorefatchain - - mov edi, ecx - mov esi, eax - - shl esi, 9 - add esi, RAMDISK - mov ecx, 512/4 -; cld - rep movsd - - popad - - xor ebx, ebx - xor eax, eax - ret - -LBA_read: - -; IN: -; -; eax = LBA block to read -; ebx = pointer to FIRST/SECOND/THIRD/FOURTH -; ecx = abs pointer to return area - - cmp [lba_read_enabled], 1 - je lbarl1 - mov eax, 2 - ret - - lbarl1: - - pushad - mov ecx, ide_mutex - call mutex_lock - popad - - push eax - push ecx - - mov edi, hd_address_table - mov esi, dir1 - mov eax, [ebx] - mov edx, '1 ' - mov ecx, 4 - blar0: - cmp eax, [esi] - je blar2 - cmp eax, edx - je blar2 - inc edx - add edi, 8 - add esi, 11 - dec ecx - jnz blar0 - - mov eax, 1 - mov ebx, 1 - jmp LBA_read_ret - - blar2: - mov eax, [edi+0] - mov ebx, [edi+4] - - mov [hdbase], eax - mov [hdid], ebx - - call wait_for_hd_idle - cmp [hd_error], 0 - jne hd_lba_error - - ; eax = hd port - ; ebx = set for primary (0x00) or slave (0x10) - - cli - - mov edx, eax - inc edx - xor eax, eax - out dx, al - inc edx - inc eax - out dx, al - inc edx - mov eax, [esp+4] - out dx, al - shr eax, 8 - inc edx - out dx, al - shr eax, 8 - inc edx - out dx, al - shr eax, 8 - inc edx - and al, 1+2+4+8 - add al, bl - add al, 128+64+32 - out dx, al - - inc edx - mov al, 20h - out dx, al - - sti - - call wait_for_sector_buffer - cmp [hd_error], 0 - jne hd_lba_error - - cli - - mov edi, [esp+0] - mov ecx, 256 - sub edx, 7 - cld - rep insw - - sti - - xor eax, eax - xor ebx, ebx - - LBA_read_ret: - mov [hd_error], 0 - mov [hd1_status], 0 - add esp, 2*4 - pushad - mov ecx, ide_mutex - call mutex_unlock - popad - - ret - - -expand_pathz: -; IN: -; esi = asciiz path & file -; edi = buffer for path & file name -; OUT: -; edi = directory & file : / 11 + / 11 + / 11 - zero terminated -; ebx = /file name - zero terminated -; esi = pointer after source - - push eax - push ecx - push edi;[esp+0] - - pathz_start: - mov byte [edi], '/' - inc edi - mov al, 32 - mov ecx, 11 - cld - rep stosb ; clear filename area - sub edi, 11 - mov ebx, edi ; start of dir/file name - - pathz_new_char: - mov al, [esi] - inc esi - cmp al, 0 - je pathz_end - - cmp al, '/' - jne pathz_not_path - cmp edi, ebx ; skip first '/' - jz pathz_new_char - lea edi, [ebx+11] ; start of next directory - jmp pathz_start - - pathz_not_path: - cmp al, '.' - jne pathz_not_ext - lea edi, [ebx+8] ; start of extension - jmp pathz_new_char - - pathz_not_ext: - cmp al, 'a' - jb pathz_not_low - cmp al, 'z' - ja pathz_not_low - sub al, 0x20 ; char to uppercase - - pathz_not_low: - mov [edi], al - inc edi - mov eax, [esp+0] ; start_of_dest_path - add eax, 512 ; keep maximum path under 512 bytes - cmp edi, eax - jb pathz_new_char - - pathz_end: - cmp ebx, edi ; if path end with '/' - jnz pathz_put_zero ; go back 1 level - sub ebx, 12 - - pathz_put_zero: - mov byte [ebx+11], 0 - dec ebx ; include '/' char into file name - pop edi - pop ecx - pop eax - ret - -;******************************************* -;* string to number -;* input eax - 4 byte string -;* output eax - number -;******************************************* -StringToNumber: -; ПЕРЕВОД СТРОКОВОГО ЧИСЛА В ЧИСЛОВОЙ ВИД -; Вход: -; EDI - адрес строки с числом. Конец числа отмечен кодом 0Dh -; Выход: -; CF - индикатор ошибок: -; 0 - ошибок нет; -; 1 - ошибка -; Если CF=0, то AX - число. - - push bx - push cx - push dx - push edi - mov [partition_string], eax - mov edi, partition_string - xor cx, cx -i1: - mov al, [edi] - cmp al, 32;13 - je i_exit -; cmp al,'0' -; jb err -; cmp al,'9' -; ja err - sub al, 48 - shl cx, 1 - jc error - mov bx, cx - shl cx, 1 - jc error - shl cx, 1 - jc error - add cx, bx - jc error - cbw - add cx, ax - jc error -i3: - inc edi - jmp i1 -i_exit: - mov ax, cx - clc -i4: - movzx eax, ax - pop edi - pop dx - pop cx - pop bx - ret - -error: - stc - jmp i4 - -partition_string: - dd 0 - db 32 diff --git a/kernel/branches/Kolibri-acpi/fs/fs_lfn.inc b/kernel/branches/Kolibri-acpi/fs/fs_lfn.inc index 466d29cead..efa433f227 100644 --- a/kernel/branches/Kolibri-acpi/fs/fs_lfn.inc +++ b/kernel/branches/Kolibri-acpi/fs/fs_lfn.inc @@ -30,18 +30,6 @@ image_of_ebx EQU esp+20 iglobal ; in this table names must be in lowercase rootdirs: - db 2,'rd' - dd fs_OnRamdisk - dd fs_NextRamdisk - db 7,'ramdisk' - dd fs_OnRamdisk - dd fs_NextRamdisk - db 2,'fd' - dd fs_OnFloppy - dd fs_NextFloppy - db 10,'floppydisk' - dd fs_OnFloppy - dd fs_NextFloppy ;********************************************** db 3,'cd0' dd fs_OnCd0 @@ -60,10 +48,6 @@ rootdirs: virtual_root_query: - dd fs_HasRamdisk - db 'rd',0 - dd fs_HasFloppy - db 'fd',0 ;********************************************** dd fs_HasCd0 db 'cd0',0 @@ -75,12 +59,6 @@ virtual_root_query: db 'cd3',0 ;********************************************** dd 0 - -fs_additional_handlers: - dd dyndisk_handler, dyndisk_enum_root -; add new handlers here - dd 0 - endg file_system_lfn_protected: @@ -257,7 +235,6 @@ file_system_lfn: .readroot: ; virtual root folder - special handler - mov esi, virtual_root_query mov ebp, [ebx+12] mov edx, [ebx+16] ; add edx, std_application_base_address @@ -269,9 +246,51 @@ file_system_lfn: mov ecx, 32/4 rep stosd mov byte [edx], 1 ; version + sub esp, 16 +.readroot_ah_loop2: + push edi + lea edi, [esp+4] + call dyndisk_enum_root + pop edi + test eax, eax + jz .readroot_done_dynamic + inc dword [edx+8] + dec dword [esp+16] + jns .readroot_ah_loop2 + dec ebp + js .readroot_ah_loop2 + push eax + xor eax, eax + inc dword [edx+4] + mov dword [edi], 0x10 ; attributes: folder + mov dword [edi+4], ebx + add edi, 8 + mov ecx, 40/4-2 + rep stosd + push esi edi + lea esi, [esp+12] +@@: + lodsb + stosb + test bl, 1 + jz .ansi3 + mov byte [edi], 0 + inc edi +.ansi3: + test al, al + jnz @b + pop edi esi eax + add edi, 520 + test bl, 1 + jnz .readroot_ah_loop2 + sub edi, 520-264 + jmp .readroot_ah_loop2 +.readroot_done_dynamic: + add esp, 16 + mov esi, virtual_root_query .readroot_loop: cmp dword [esi], eax - jz .readroot_done_static + jz .readroot_done call dword [esi] add esi, 4 test eax, eax @@ -312,54 +331,7 @@ file_system_lfn: jnz .readroot_loop sub edi, 520-264 jmp .readroot_loop -.readroot_done_static: - mov esi, fs_additional_handlers-8 - sub esp, 16 -.readroot_ah_loop: - add esi, 8 - cmp dword [esi], 0 - jz .readroot_done - xor eax, eax -.readroot_ah_loop2: - push edi - lea edi, [esp+4] - call dword [esi+4] - pop edi - test eax, eax - jz .readroot_ah_loop - inc dword [edx+8] - dec dword [esp+16] - jns .readroot_ah_loop2 - dec ebp - js .readroot_ah_loop2 - push eax - xor eax, eax - inc dword [edx+4] - mov dword [edi], 0x10 ; attributes: folder - mov dword [edi+4], ebx - add edi, 8 - mov ecx, 40/4-2 - rep stosd - push esi edi - lea esi, [esp+12] -@@: - lodsb - stosb - test bl, 1 - jz .ansi3 - mov byte [edi], 0 - inc edi -.ansi3: - test al, al - jnz @b - pop edi esi eax - add edi, 520 - test bl, 1 - jnz .readroot_ah_loop2 - sub edi, 520-264 - jmp .readroot_ah_loop2 .readroot_done: - add esp, 16 pop eax mov ebx, [edx+4] xor eax, eax @@ -371,14 +343,7 @@ file_system_lfn: mov [image_of_ebx], ebx ret .notfound_try: - mov edi, fs_additional_handlers -@@: - cmp dword [edi], 0 - jz .notfound - call dword [edi] - scasd - scasd - jmp @b + call dyndisk_handler .notfound: mov dword [image_of_eax], ERROR_FILE_NOT_FOUND and dword [image_of_ebx], 0 @@ -436,72 +401,10 @@ file_system_lfn: ; ebp = 0 or pointer to rest of name from folder addressed by esi ; out: [image_of_eax]=image of eax, [image_of_ebx]=image of ebx -fs_OnRamdisk: - cmp ecx, 1 - jnz file_system_lfn.notfound - mov eax, [ebx] - cmp eax, fs_NumRamdiskServices - jae .not_impl - mov ecx, [ebx+12] - mov edx, [ebx+16] - ; add edx, std_application_base_address - add ebx, 4 - call dword [fs_RamdiskServices + eax*4] - mov [image_of_eax], eax - mov [image_of_ebx], ebx - ret -.not_impl: - mov dword [image_of_eax], 2 ; not implemented - ret - fs_NotImplemented: mov eax, 2 ret -fs_RamdiskServices: - dd fs_RamdiskRead - dd fs_RamdiskReadFolder - dd fs_RamdiskRewrite - dd fs_RamdiskWrite - dd fs_RamdiskSetFileEnd - dd fs_RamdiskGetFileInfo - dd fs_RamdiskSetFileInfo - dd 0 - dd fs_RamdiskDelete - dd fs_RamdiskCreateFolder -fs_NumRamdiskServices = ($ - fs_RamdiskServices)/4 - -fs_OnFloppy: - cmp ecx, 2 - ja file_system_lfn.notfound - mov eax, [ebx] - cmp eax, fs_NumFloppyServices - jae fs_OnRamdisk.not_impl - call reserve_flp - mov [flp_number], cl - mov ecx, [ebx+12] - mov edx, [ebx+16] - ; add edx, std_application_base_address - add ebx, 4 - call dword [fs_FloppyServices + eax*4] - and [flp_status], 0 - mov [image_of_eax], eax - mov [image_of_ebx], ebx - ret - -fs_FloppyServices: - dd fs_FloppyRead - dd fs_FloppyReadFolder - dd fs_FloppyRewrite - dd fs_FloppyWrite - dd fs_FloppySetFileEnd - dd fs_FloppyGetFileInfo - dd fs_FloppySetFileInfo - dd 0 - dd fs_FloppyDelete - dd fs_FloppyCreateFolder -fs_NumFloppyServices = ($ - fs_FloppyServices)/4 - ;******************************************************* fs_OnCd0: call reserve_cd @@ -583,16 +486,6 @@ fs_CdServices: dd fs_NotImplemented fs_NumCdServices = ($ - fs_CdServices)/4 -;******************************************************* - -fs_HasRamdisk: - mov al, 1 ; we always have ramdisk - ret -fs_HasFloppy: - cmp byte [DRIVE_DATA], 0 - setnz al - ret - ;******************************************************* fs_HasCd0: test byte [DRIVE_DATA+1], 10000000b @@ -617,36 +510,6 @@ fs_HasCd3: ; out: CF=1 => no more partitions ; CF=0 => eax=next partition number -fs_NextRamdisk: -; we always have /rd/1 - test eax, eax - stc - jnz @f - mov al, 1 - clc -@@: - ret - -fs_NextFloppy: -; we have /fd/1 iff (([DRIVE_DATA] and 0xF0) != 0) and /fd/2 iff (([DRIVE_DATA] and 0x0F) != 0) - test byte [DRIVE_DATA], 0xF0 - jz .no1 - test eax, eax - jnz .no1 - inc eax - ret ; CF cleared -.no1: - test byte [DRIVE_DATA], 0x0F - jz .no2 - cmp al, 2 - jae .no2 - mov al, 2 - clc - ret -.no2: - stc - ret - ;******************************************************* fs_NextCd: ; we always have /cdX/1 diff --git a/kernel/branches/Kolibri-acpi/fs/part_set.inc b/kernel/branches/Kolibri-acpi/fs/part_set.inc deleted file mode 100644 index ebbd38ed7c..0000000000 --- a/kernel/branches/Kolibri-acpi/fs/part_set.inc +++ /dev/null @@ -1,436 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; ;; -;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; -;; Distributed under terms of the GNU General Public License ;; -;; ;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -$Revision$ - - -;************************************************************* -;* 13.02.2010 Find all partition and check supported FS -;* 12.07.2007 Check all 4 entry of MBR and EMBR -;* 29.04.2006 Elimination of hangup after the -;* expiration hd_wait_timeout - Mario79 -;* 28.01.2006 find all Fat16/32 partition in all input point -;* to MBR - Mario79 -;************************************************************* - -uglobal -align 4 - -;****************************************************** -; Please do not change this place - variables in text -; Mario79 -; START place -;****************************************************** -PARTITION_START dd 0x3f -PARTITION_END dd 0 -fs_type db 0 ; 1=NTFS, 2=EXT2/3, 16=FAT16, 32=FAT32 -align 4 - -fs_dependent_data_start: -; FATxx data - -.partition dd ? - rb 80 - -fs_dependent_data_end: -file_system_data_size = $ - PARTITION_START -if file_system_data_size > 96 -ERROR: - sizeof(file system data) too big! -end if - -virtual at fs_dependent_data_start -; NTFS data -ntfs_data: -.sectors_per_cluster dd ? -.mft_cluster dd ? -.mftmirr_cluster dd ? -.frs_size dd ? ; FRS size in bytes -.iab_size dd ? ; IndexAllocationBuffer size in bytes -.frs_buffer dd ? -.iab_buffer dd ? -.mft_retrieval dd ? -.mft_retrieval_size dd ? -.mft_retrieval_alloc dd ? -.mft_retrieval_end dd ? -.cur_index_size dd ? -.cur_index_buf dd ? -if $ > fs_dependent_data_end -ERROR: - increase sizeof(fs_dependent_data)! -end if -end virtual - -virtual at fs_dependent_data_start -; EXT2 data -ext2_data: - .log_block_size dd ? - .block_size dd ? - .count_block_in_block dd ? - .blocks_per_group dd ? - .global_desc_table dd ? - .root_inode dd ? ; pointer to root inode in memory - .inode_size dd ? - .count_pointer_in_block dd ? ; block_size / 4 - .count_pointer_in_block_square dd ? ; (block_size / 4)**2 - .ext2_save_block dd ? ;RUS: блок на глобальную 1 процедуру ;ENG: block for 1 global procedure - .ext2_temp_block dd ? ;RUS: блок для мелких процедур ;ENG: block for small procedures - .ext2_save_inode dd ? ;RUS: inode на глобальную процедуру ;ENG: inode for global procedure - .ext2_temp_inode dd ? ;RUS: inode для мелких процедур ;ENG: inode for small procedures - .sb dd ? ; superblock - .groups_count dd ? -if $ > fs_dependent_data_end -ERROR: - increase sizeof(fs_dependent_data)! -end if -end virtual - -;*************************************************************************** -; End place -; Mario79 -;*************************************************************************** -endg -iglobal - - partition_types: ; list of fat16/32 partitions - db 0x04 ; DOS: fat16 <32M - db 0x06 ; DOS: fat16 >32M - db 0x0b ; WIN95: fat32 - db 0x0c ; WIN95: fat32, LBA-mapped - db 0x0e ; WIN95: fat16, LBA-mapped - db 0x14 ; Hidden DOS: fat16 <32M - db 0x16 ; Hidden DOS: fat16 >32M - db 0x1b ; Hidden WIN95: fat32 - db 0x1c ; Hidden WIN95: fat32, LBA-mapped - db 0x1e ; Hidden WIN95: fat16, LBA-mapped - db 0xc4 ; DRDOS/secured: fat16 <32M - db 0xc6 ; DRDOS/secured: fat16 >32M - db 0xcb ; DRDOS/secured: fat32 - db 0xcc ; DRDOS/secured: fat32, LBA-mapped - db 0xce ; DRDOS/secured: fat16, LBA-mapped - db 0xd4 ; Old Multiuser DOS secured: fat16 <32M - db 0xd6 ; Old Multiuser DOS secured: fat16 >32M - db 0x07 ; NTFS - db 0x27 ; NTFS, hidden - db 0x83 ; Linux native file system (ext2fs) - partition_types_end: - - - extended_types: ; list of extended partitions - db 0x05 ; DOS: extended partition - db 0x0f ; WIN95: extended partition, LBA-mapped - db 0xc5 ; DRDOS/secured: extended partition - db 0xd5 ; Old Multiuser DOS secured: extended partition - extended_types_end: - -endg - -; Partition chain used: -; MBR <--------------------- -; | | -; |-> PARTITION1 | -; |-> EXTENDED PARTITION - ;not need be second partition -; |-> PARTITION3 -; |-> PARTITION4 - -set_PARTITION_variables: -set_FAT32_variables: ;deprecated - and [problem_partition], 0 - call reserve_hd1 - call reserve_hd_channel - - pushad - - cmp dword [hdpos], 0 - je problem_hd - - xor ecx, ecx ; partition count - ;or edx,-1 ; flag for partition - xor eax, eax ; address MBR - xor ebp, ebp ; extended partition start - -new_mbr: - test ebp, ebp ; is there extended partition? (MBR or EMBR) - jnz extended_already_set; yes - xchg ebp, eax ; no. set it now - -extended_already_set: - add eax, ebp ; mbr=mbr+0, ext_part=ext_start+relat_start - mov ebx, buffer - call hd_read - cmp [hd_error], 0 - jne problem_hd - - cmp word [ebx+0x1fe], 0xaa55; is it valid boot sector? - jnz end_partition_chain - push eax ; push only one time - cmp dword [ebx+0x1be+0xc], 0; skip over empty partition - jnz test_primary_partition_0 - cmp dword [ebx+0x1be+0xc+16], 0 - jnz test_primary_partition_1 - cmp dword [ebx+0x1be+0xc+16+16], 0 - jnz test_primary_partition_2 - cmp dword [ebx+0x1be+0xc+16+16+16], 0 - jnz test_primary_partition_3 - pop eax - jmp end_partition_chain - -test_primary_partition_0: - mov al, [ebx+0x1be+4]; get primary partition type - call scan_partition_types - jnz test_primary_partition_1; no. skip over - - inc ecx - cmp ecx, [known_part]; is it wanted partition? - jnz test_primary_partition_1; no - - pop eax - ;mov edx, eax ; start sector - add eax, [ebx+0x1be+8] ; add relative start - ;mov [PARTITON_START],edx - ;push edx - mov edx, [ebx+0x1be+12] ; length - ;add edx, eax ; add length - ;dec edx ; PARTITION_END is inclusive - ;mov [PARTITION_END], edx ; note that this can be changed - ; when file system data will be available - mov cl, [ebx+0x1be+4] ; fs_type - ;mov [fs_type], dl ; save for FS recognizer (separate FAT vs NTFS) - ;pop edx - jmp hd_and_partition_ok - -test_primary_partition_1: - mov al, [ebx+0x1be+4+16]; get primary partition type - call scan_partition_types - jnz test_primary_partition_2 ; no. skip over - - inc ecx - cmp ecx, [known_part]; is it wanted partition? - jnz test_primary_partition_2 ; no - - pop eax - add eax, [ebx+0x1be+8+16] - mov edx, [ebx+0x1be+12+16] - mov cl, [ebx+0x1be+4+16] - jmp hd_and_partition_ok - - ;mov edx, eax - ;add edx, [ebx+0x1be+8+16] - ;push edx - ;add edx, [ebx+0x1be+12+16] - ;dec edx - ;mov [PARTITION_END], edx - ;mov al, [ebx+0x1be+4+16] - ;mov [fs_type], dl - ;pop edx - -test_primary_partition_2: - mov al, [ebx+0x1be+4+16+16]; get primary partition type - call scan_partition_types - jnz test_primary_partition_3 ; no. skip over - - inc ecx - cmp ecx, [known_part]; is it wanted partition? - jnz test_primary_partition_3 ; no - - pop eax - add eax, [ebx+0x1be+8+16+16] - mov edx, [ebx+0x1be+12+16+16] - mov cl, [ebx+0x1be+4+16+16] - jmp hd_and_partition_ok - ;mov edx, eax - ;add edx, [ebx+0x1be+8+16+16] - ;push edx - ;add edx, [ebx+0x1be+12+16+16] - ;dec edx - ;mov [PARTITION_END], edx - ;mov al, [ebx+0x1be+4+16+16] - ;mov [fs_type], dl - ;pop edx - -test_primary_partition_3: - mov al, [ebx+0x1be+4+16+16+16]; get primary partition type - call scan_partition_types - jnz test_ext_partition_0 ; no. skip over - - inc ecx - cmp ecx, [known_part]; is it wanted partition? - jnz test_ext_partition_0; no - - pop eax - add eax, [ebx+0x1be+8+16+16+16] - mov edx, [ebx+0x1be+12+16+16+16] - mov cl, [ebx+0x1be+4+16+16+16] - jmp hd_and_partition_ok - - ;mov edx, eax - ;add edx, [ebx+0x1be+8+16+16+16] - ;push edx - ;add edx, [ebx+0x1be+12+16+16+16] - ;dec edx - ;mov [PARTITION_END], edx - ;mov al, [ebx+0x1be+4+16+16+16] - ;mov [fs_type], dl - ;pop edx - -test_ext_partition_0: - pop eax ; просто выкидываем из стека - mov al, [ebx+0x1be+4]; get extended partition type - call scan_extended_types - jnz test_ext_partition_1 - - mov eax, [ebx+0x1be+8]; add relative start - test eax, eax ; is there extended partition? - jnz new_mbr ; yes. read it - -test_ext_partition_1: - mov al, [ebx+0x1be+4+16]; get extended partition type - call scan_extended_types - jnz test_ext_partition_2 - - mov eax, [ebx+0x1be+8+16]; add relative start - test eax, eax ; is there extended partition? - jnz new_mbr ; yes. read it - -test_ext_partition_2: - mov al, [ebx+0x1be+4+16+16]; get extended partition type - call scan_extended_types - jnz test_ext_partition_3 - - mov eax, [ebx+0x1be+8+16+16]; add relative start - test eax, eax ; is there extended partition? - jnz new_mbr ; yes. read it - -test_ext_partition_3: - mov al, [ebx+0x1be+4+16+16+16]; get extended partition type - call scan_extended_types - jnz end_partition_chain; no. end chain - - mov eax, [ebx+0x1be+8+16+16+16]; get start of extended partition - test eax, eax ; is there extended partition? - jnz new_mbr ; yes. read it - -end_partition_chain: - ;mov [partition_count],ecx - - ;cmp edx,-1 ; found wanted partition? - ;jnz hd_and_partition_ok ; yes. install it - ;jmp problem_partition_or_fat -problem_hd: - or [problem_partition], 2 - jmp return_from_part_set - - -scan_partition_types: - push ecx - mov edi, partition_types - mov ecx, partition_types_end-partition_types - cld - repne scasb ; is partition type ok? - pop ecx - ret - -scan_extended_types: - push ecx - mov edi, extended_types - mov ecx, extended_types_end-extended_types - cld - repne scasb ; is it extended partition? - pop ecx - ret - -problem_fat_dec_count: ; bootsector is missing or another problem -; dec [partition_count] ; remove it from partition_count - -problem_partition_or_fat: - or [problem_partition], 1 - -return_from_part_set: - popad - ;mov [fs_type],0 - call free_hd_channel - mov [hd1_status], 0 ; free - ret - -hd_and_partition_ok: - -;eax = PARTITION_START edx=PARTITION_LENGTH cl=fs_type - mov [fs_type], cl - ;mov eax,edx - mov [PARTITION_START], eax - add edx, eax - dec edx - mov [PARTITION_END], edx - - ; mov edx, [PARTITION_END] - ; sub edx, eax - ; inc edx ; edx = length of partition зачем оно нам?? - -; mov [hd_setup],1 - mov ebx, buffer - call hd_read ; read boot sector of partition - cmp [hd_error], 0 - jz boot_read_ok - cmp [fs_type], 7 - jnz problem_fat_dec_count -; NTFS duplicates bootsector: -; NT4/2k/XP+ saves bootsector copy in the end of disk -; NT 3.51 saves bootsector copy in the middle of disk - and [hd_error], 0 - mov eax, [PARTITION_END] - call hd_read - cmp [hd_error], 0 - jnz @f - call ntfs_test_bootsec - jnc boot_read_ok -@@: - and [hd_error], 0 - mov eax, edx - shr eax, 1 - add eax, [PARTITION_START] - call hd_read - cmp [hd_error], 0 - jnz problem_fat_dec_count ; no chance... -boot_read_ok: - -; if we are running on NTFS, check bootsector - - call ntfs_test_bootsec ; test ntfs - jnc ntfs_setup - - call ext2_test_superblock ; test ext2fs - jnc ext2_setup - - mov eax, [PARTITION_START] ;ext2 test changes [buffer] - call hd_read - cmp [hd_error], 0 - jnz problem_fat_dec_count - - push 0 - mov eax, [PARTITION_END] - sub eax, [PARTITION_START] - inc eax - push eax - push 0 - push [PARTITION_START] - push ebp - push ebp - mov ebp, esp - mov esi, 'old' ; special value: there is no DISK structure - push 1 ; bootsector read successfully - call fat_create_partition - add esp, 4*7 - test eax, eax - jz problem_fat_dec_count - mov [fs_dependent_data_start.partition], eax - mov al, [eax+FAT.fs_type] - mov [fs_type], al - - popad - call free_hd_channel - mov [hd1_status], 0 ; free - ret diff --git a/kernel/branches/Kolibri-acpi/gui/char2_et.mt b/kernel/branches/Kolibri-acpi/gui/char2_et.mt new file mode 100644 index 0000000000000000000000000000000000000000..73993dde9d1d220b6a4ddc9521d1a6fe55b78041 GIT binary patch literal 2560 zcmd5-O>f&q5Zz@MYGpW<80g>t0!6aup*}e%;Mjn=wRx_S5XTiw*cAL(er%oo0*kS@t6qI4~6t(*32eaDbs%55Btw8kg>h#Ey^@g9EBfc zhQ1%}?miJ|>ulQq$&JPl$a_R&41IZg6g4l$at>>w(qv3hK}u!fZ_e^F0ni%DXtWzg z=8rZaV?0EK_UeiP98-^Vjb9)$OzmAmttxY~NvK`cb@5dF1(YPXAx~z~BuP@(W%%FV zFM61Zr>4}s`S!=Z>8$j2sXy@mPx8ocn zm{IG-%hsK4yzkgDAc$ej2+4T(7`&ZQV2C840wPwx{Hb9)r5gOBmI8kx7cWGgG(ATN+QNZr;)Ez1yXJOw2F$xO_6?FKNUjAp+ zhPEYF7A=sc;b_9hV^xhUvaz{s3p=)|?>RXEK|4v;o6Uw(;@rb-w|fB6dY0$;3#(7x*RZv8>=*=ie8n!wmg; zkLgA&oDB?JgO^`5;T}rK6D-=eAAECcS&A&~2c{E;+oSLj7IhKgJ;;72#SP(p@U7d2 zyf;`7?uSzQ&Hio!v=}w^m%J=Uso3FLqY0H-H}k0W4;JjmU(ib9WP2Wa6wUA7KMz@ zE}WxlYE{VhOmXW#e zaXogYp4n)Cw#Z4V7x!sulAP}ZM4*l;V`D>SoB^=!sj%z&I1DSf22lmUFda7rk|l36 zue&-01JZeDcPd4)qA&=mx(LiizbJkJU)W~Db-#L$7oBc~Q(_$T)nX}HNszxrUjF1>11U}FCQCg~$YED;m zL0WLZWQvVJGO{zJ5<+H-kd5nJmU~NTghKcnWBpCJUH6Ya_1BiWJ}&L;62)o#-gQ&# zr7=&{`(T~KBAFbL_d$(H>V^r0mx4e?im0!IhpnDbytEx2<3nZS<7m>$p?X-S$iKQl zzdd_VwD(PPZ>Js)=D*rVg-tyW;qO){u#IJOlz{}f#-7haC1*fLcEq0_4PKqa##vTQ zRReMt9UTX^Qw~brdMxhcpvOTrAp`W<@Ab54=t!lc+PQp0eKaA_Kue{8W}aokKue-Q zc4uZJ(?r+NVxpO6ooyGL^BS8+ow|{MW}Y?CyJl=E9S0V1CTx7xaV#(1X!5$q3l&W( lvH^06352AI+H?94{x{9#`);3LfM8d?HxMp^J`Vr({s+MJOSb?3 literal 0 HcmV?d00001 diff --git a/kernel/branches/Kolibri-acpi/gui/window.inc b/kernel/branches/Kolibri-acpi/gui/window.inc index 77596936fd..a1f3798f2d 100644 --- a/kernel/branches/Kolibri-acpi/gui/window.inc +++ b/kernel/branches/Kolibri-acpi/gui/window.inc @@ -2036,9 +2036,9 @@ window._.window_activate: ;//////////////////////////////////////////////////// ; if type of current active window is 3 or 4, it must be redrawn mov ebx, [TASK_COUNT] - + ; DEBUGF 1, "K : TASK_COUNT (0x%x)\n", ebx - + movzx ebx, word[WIN_POS + ebx * 2] shl ebx, 5 add eax, window_data @@ -2068,13 +2068,13 @@ align 4 cmp eax, [TASK_COUNT] jae .move_self_up inc eax - + ; push ebx ; xor ebx,ebx ; mov bx,[WIN_STACK + eax * 2] ; DEBUGF 1, "K : DEC WIN_STACK (0x%x)\n",ebx ; pop ebx - + cmp [WIN_STACK + eax * 2], bx jbe .next_stack_window dec word[WIN_STACK + eax * 2] @@ -2162,7 +2162,7 @@ align 4 mov word[MOUSE_SCROLL_V], 0 pop ebx eax ret -;------------------------------------------------------------------------------ +;------------------------------------------------------------------------------ align 4 ;------------------------------------------------------------------------------ window._.check_window_draw: ;////////////////////////////////////////////////// diff --git a/kernel/branches/Kolibri-acpi/kernel.asm b/kernel/branches/Kolibri-acpi/kernel.asm index 565ffa2452..9df4ddb32c 100644 --- a/kernel/branches/Kolibri-acpi/kernel.asm +++ b/kernel/branches/Kolibri-acpi/kernel.asm @@ -759,9 +759,10 @@ no_mode_0x12: ; Initialize system timer (IRQ0) call PIT_init -; CALCULATE FAT CHAIN FOR RAMDISK - - call calculatefatchain +; Register ramdisk file system + mov esi, boot_initramdisk + call boot_log + call ramdisk_init mov esi, boot_initapic call boot_log @@ -1333,8 +1334,8 @@ proc osloop_has_work? jnz .yes call stack_handler_has_work? jnz .yes -; call check_fdd_motor_status_has_work? -; jnz .yes + call check_fdd_motor_status_has_work? + jnz .yes call check_ATAPI_device_event_has_work? jnz .yes call check_lights_state_has_work? @@ -2673,29 +2674,14 @@ endg align 4 sys_cachetodiskette: cmp ebx, 1 - jne .no_floppy_a_save - mov [flp_number], 1 - jmp .save_image_on_floppy -;-------------------------------------- -align 4 -.no_floppy_a_save: + jb .no_floppy_save cmp ebx, 2 - jne .no_floppy_b_save - mov [flp_number], 2 -;-------------------------------------- -align 4 -.save_image_on_floppy: + ja .no_floppy_save call save_image - mov [esp + 32], dword 0 - cmp [FDC_Status], 0 - je .yes_floppy_save -;-------------------------------------- -align 4 -.no_floppy_b_save: + mov [esp + 32], eax + ret +.no_floppy_save: mov [esp + 32], dword 1 -;-------------------------------------- -align 4 -.yes_floppy_save: ret ;------------------------------------------------------------------------------ uglobal @@ -3268,7 +3254,7 @@ sys_cpuusage: ; Keyboard mode (+75) mov al, byte [ecx*8 + SLOT_BASE + APPDATA.keyboard_mode] - stosb + stosb pop esi pop edi @@ -5266,19 +5252,6 @@ align 4 align 4 -syscall_openramdiskfile: ; OpenRamdiskFile - - mov eax, ebx - mov ebx, ecx - mov ecx, edx - mov edx, esi - mov esi, 12 - call fileread - mov [esp+32], eax - ret - -align 4 - syscall_drawrect: ; DrawRect mov edi, edx ; color + gradient @@ -5638,13 +5611,7 @@ set_screen: ; eax - new Screen_Max_X ; ecx - new BytesPerScanLine ; edx - new Screen_Max_Y - cmp eax, [Screen_Max_X] - jne .set - cmp edx, [Screen_Max_Y] - jne .set - ret -.set: pushfd cli @@ -5783,12 +5750,11 @@ yes_shutdown_param: cli if ~ defined extended_primary_loader - mov eax, kernel_file ; load kernel.mnt to 0x7000:0 - movi esi, 12 - xor ebx, ebx - or ecx, -1 - mov edx, OS_BASE+0x70000 - call fileread +; load kernel.mnt to 0x7000:0 + mov ebx, kernel_file_load + pushad + call file_system_lfn + popad mov esi, restart_kernel_4000+OS_BASE+0x10000 ; move kernel re-starter to 0x4000:0 mov edi, OS_BASE+0x40000 @@ -5802,8 +5768,6 @@ end if ; cld ; rep movsd - call restorefatchain - call IRQ_mask_all if 0 diff --git a/kernel/branches/Kolibri-acpi/kernel32.inc b/kernel/branches/Kolibri-acpi/kernel32.inc index 391e2771f6..220f4299f6 100644 --- a/kernel/branches/Kolibri-acpi/kernel32.inc +++ b/kernel/branches/Kolibri-acpi/kernel32.inc @@ -185,11 +185,9 @@ include "gui/button.inc" include "blkdev/disk.inc" ; support for plug-n-play disks include "blkdev/disk_cache.inc" ; caching for plug-n-play disks -include "fs/fs.inc" ; syscall -include "fs/fat32.inc" ; read / write for fat32 filesystem -include "fs/ntfs.inc" ; read / write for ntfs filesystem -include "fs/fat12.inc" ; read / write for fat12 filesystem include "blkdev/rd.inc" ; ramdisk read /write +include "fs/fat.inc" ; read / write for fat filesystem +include "fs/ntfs.inc" ; read / write for ntfs filesystem include "fs/fs_lfn.inc" ; syscall, version 2 include "fs/iso9660.inc" ; read for iso9660 filesystem CD include "fs/ext2/ext2.asm" ; read / write for ext2 filesystem diff --git a/kernel/branches/Kolibri-acpi/memmap.inc b/kernel/branches/Kolibri-acpi/memmap.inc index 1bc967dd1d..921c78dc8a 100644 --- a/kernel/branches/Kolibri-acpi/memmap.inc +++ b/kernel/branches/Kolibri-acpi/memmap.inc @@ -198,8 +198,7 @@ ; 0x800A0000 -> AFFFF screen access area ; 0x800B0000 -> FFFFF bios rest in peace -area (320k) ? ; 0x80100000 -> 27FFFF diskette image (1m5) -; 0x80280000 -> 281FFF ramdisk fat (8k) -; 0x80282000 -> 283FFF floppy fat (8k) +; 0x80280000 -> 283FFF free (16k) ; ; 0x80284000 -> 28BFFF HDD DMA AREA (32k) ; 0x8028C000 -> 297FFF free (48k) diff --git a/kernel/branches/Kolibri-acpi/readme-ext-loader.txt b/kernel/branches/Kolibri-acpi/readme-ext-loader.txt new file mode 100644 index 0000000000..ccfe7fc629 --- /dev/null +++ b/kernel/branches/Kolibri-acpi/readme-ext-loader.txt @@ -0,0 +1,52 @@ +При компиляции ядра можно задать - например, в lang.inc, - дополнительный +параметр extended_primary_loader=1; он переключает ядро на альтернативный +способ загрузки. Загрузка несовместима +с основой версией ядра; требуется специальный первичный загрузчик, существующие +собраны в папке bootloader/extended_primary_loader. +Есть варианты загрузки с FAT12/FAT16/FAT32/ISO, +есть вариант загрузчика, встраивающегося в загрузку Windows. Встраивание +в GRUB аналогично описанному для основного способа загрузки - +последним загрузчиком в цепочке +при этом оказывается тот, который установлен в образе дискеты FAT12. + +При загрузке поддерживается опрос параметров из файла config.ini, +но не поддерживается сохранение выбранных параметров. Файл config.ini +ищется рядом с первичным загрузчиком, как и ядро kernel.mnt; в случае +загрузчика с дискеты эти файлы располагаются на самой дискете, +в случае других загрузчиков - рядом с первичным загрузчиком вне образа. + +Если config.ini не найден, используются умолчальные значения. Если +config.ini найден, то он разбивается на строчки, строчки должны иметь +вид <параметр>=<значение>, перед параметром и вокруг знака равенства +могут быть пробелы, всё, что идёт в строке после значения, игнорируется. +Параметры чувствительны к регистру символов. +Строки, не имеющие такого вида, а также строки, в которых параметр неизвестен, +а также строки, в которых значение недопустимо, игнорируются. + +Все числа должны быть целыми неотрицательными, записанными в десятичной +системе счисления. Булевские значения кодируются следующим образом: +0=off=no соответствует выключенному параметру, 1=on=yes - включённому. + +Известные параметры: + +timeout=<число секунд> задаёт время ожидания в экране выбора параметров. +Если таймаут больше 9, используется значение 9. Значение по умолчанию 5. + +resolution=<ширина>*<высота> или <ширина>x<высота> задаёт желаемое +разрешение графического режима. Если такого графического режима, +устраивающего систему, не найдено, параметр игнорируется. По умолчанию +пробуются последовательно разрешения 1024*768, 800*600, 640*480. + +vbemode=<номер видеорежима VBE> задаёт желаемый графический режим. +Если такой режим не существует или не устраивает систему, параметр +игнорируется. Параметр более приоритетен, чем resolution. Умолчального +значения нет. + +vrr=<включить VRR> - булевский параметр. Умолчальное значение 0. + +biosdisks=<включить доступ к дискам через BIOS> - булевский параметр. +Умолчальное значение 1. + +imgfrom=<источник рамдиска>. 1 - грузить дискету, 2 - грузить файл +kolibri.img, находящийся рядом с первичным загрузчиком. Умолчальное +значение 1 при загрузке с дискеты и 2 в противном случае. diff --git a/kernel/branches/Kolibri-acpi/skin/base.bmp b/kernel/branches/Kolibri-acpi/skin/base.bmp deleted file mode 100644 index 185b1f82897ca45a2c27936540eaa58ee8e4db56..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 584 zcmZvZF$+Oa7=|CFTQ-9%cE7+6Fj-6_gOVgA8I(a%GDsvpQxb#jVA1D0=XUGfC=?X1i6yUqfBjMY@WvKvkVwxdd+M)gnx8T^ya%8ouv6Odfrdr*}4915DmSVow+& z;xVy0AD;=1sdpy6GfZTG%yAB4iI}VqlQm+pLAHoGh#g|GM@$Zg$q`Xb-q|=KCKu%D N`H$p1Z}Zdj5q^14=R*Jh diff --git a/kernel/branches/Kolibri-acpi/skin/base_1.bmp b/kernel/branches/Kolibri-acpi/skin/base_1.bmp deleted file mode 100644 index f53bbeb6f4533da40e2871e94ac4d7dc79e46a97..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 584 zcmZ?r^CX;=5h~;Pp_y0_)<_2mGB5xDy&yS5 diff --git a/kernel/branches/Kolibri-acpi/skin/default.asm b/kernel/branches/Kolibri-acpi/skin/default.asm deleted file mode 100644 index a0d42fd487..0000000000 --- a/kernel/branches/Kolibri-acpi/skin/default.asm +++ /dev/null @@ -1,38 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; ;; -;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; -;; Distributed under terms of the GNU General Public License ;; -;; ;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -include 'me_skin.inc' - -SKIN_PARAMS \ - height = bmp_base.height,\ ; skin height - margins = [5:1:43:1],\ ; margins [left:top:right:bottom] - colors active = [binner=0x00081d:\ ; border inner color - bouter=0x00081d:\ ; border outer color - bframe=0x0054e7],\ ; border frame color - colors inactive = [binner=0x00081d:\ ; border inner color - bouter=0x00081d:\ ; border outer color - bframe=0x1a8acc],\ ; border frame color - dtp = 'myblue.dtp' ; dtp colors - -SKIN_BUTTONS \ - close = [-21:3][16:16],\ ; buttons coordinates - minimize = [-39:3][16:16] ; [left:top][width:height] - -SKIN_BITMAPS \ - left active = bmp_left,\ ; skin bitmaps pointers - left inactive = bmp_left1,\ - oper active = bmp_oper,\ - oper inactive = bmp_oper1,\ - base active = bmp_base,\ - base inactive = bmp_base1 - -BITMAP bmp_left ,'left.bmp' ; skin bitmaps -BITMAP bmp_oper ,'oper.bmp' -BITMAP bmp_base ,'base.bmp' -BITMAP bmp_left1,'left_1.bmp' -BITMAP bmp_oper1,'oper_1.bmp' -BITMAP bmp_base1,'base_1.bmp' diff --git a/kernel/branches/Kolibri-acpi/skin/left.bmp b/kernel/branches/Kolibri-acpi/skin/left.bmp deleted file mode 100644 index bfd97344eb8fa8b748475e1fdac8011645f5a37c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 670 zcmZ{b!3qHZ6h$v9HkPun_XR${-pV8kB}pV%C<{r+LL&JCU*lgSvCu4R^t^Y+VrD$k zd8gZ)nOgmn1)r+AqLSa(;14HfSLUeqgD(7$szUYnS)KGtLc8PmzZHidYw%^)6ZbBG7q0;ARJ3qw{D+0+~obC!n{%8!4+@+Zjmu828NK^($?#jFb ztOz7`ZBZsx1d_YHyx_*Nyc^5&&=?@On=4Chtt`8>vILC*lDoaG5-S49-Q7@+6@ldL zZEC)^xfw*FGC*<4{Xp~xOd>PDa(gE}**o#^zKM@f m86df*`=^1?bTkG??%9Fq&klkSDgz|<{LoCS2qcFKF#rHaTS9{X diff --git a/kernel/branches/Kolibri-acpi/skin/me_skin.inc b/kernel/branches/Kolibri-acpi/skin/me_skin.inc deleted file mode 100644 index 45292e7ff7..0000000000 --- a/kernel/branches/Kolibri-acpi/skin/me_skin.inc +++ /dev/null @@ -1,242 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; ;; -;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; -;; Distributed under terms of the GNU General Public License ;; -;; ;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;============================================================================ -; This file should be used to generate skins of new standard -;============================================================================ -; skin file structure: -;---------------------------------------------------------------------------- -; header: -; dd 'SKIN' -; dd = version (1 for now) -; dd @ params -; dd @ buttons -; dd @ bitmaps -; ... -;---------------------------------------------------------------------------- -; NOTE: order of sections listed below is insignificant -; since they're identified by pointer in above header -;---------------------------------------------------------------------------- -; ... -; params: -; dd = skin height -; dw = right margin -; dw = left margin -; dw = bottom margin -; dw = top margin -; dd = inner line color -; dd = outer line color -; dd = frame color -; dd = dtp file size -; ?? = dtp file itself -; ... -;---------------------------------------------------------------------------- -; ... -; buttons: -; dd = button type (1 = close, 2 = minimize) -; dw = left button coord (could be negative) -; dw = top button coord (could be negative) -; dw = button width -; dw = button height -; ... etc for all buttons -; dd = 0 (end of buttons list) -; ... -;---------------------------------------------------------------------------- -; ... -; bitmaps: -; dw = bitmap kind (1 = left, 2 = oper, 3 = base) -; dw = bitmap type (1 = active, 0 = inactive) -; dd @ bitmap -; ... etc for all bitmaps -; dd 0 (end of bitmaps list) -; ... -;---------------------------------------------------------------------------- -; ... -; bitmap: -; dd = bitmap width -; dd = bitmap height -; ?? = raw bitmap data -; ... etc for all bitmaps -; ... -;============================================================================ - -dd 'SKIN',1,__params__,__buttons__,__bitmaps__ - -struc BITMAPFILEHEADER { - .bfType dw ? ; WORD - .bfSize dd ? ; DWORD - .bfReserved1 dw ? ; WORD - .bfReserved2 dw ? ; WORD - .bfOffBits dd ? ; DWORD -} - -struc BITMAPINFOHEADER { - .biSize dd ? ; DWORD - .biWidth dd ? ; LONG - .biHeight dd ? ; LONG - .biPlanes dw ? ; WORD - .biBitCount dw ? ; WORD - .biCompression dd ? ; DWORD - .biSizeImage dd ? ; DWORD - .biXPelsPerMeter dd ? ; LONG - .biYPelsPerMeter dd ? ; LONG - .biClrUsed dd ? ; DWORD - .biClrImportant dd ? ; DWORD -} - -struc _bmp { - .h BITMAPFILEHEADER - .i BITMAPINFOHEADER -} -virtual at 0 - _bmp _bmp -end virtual - -macro BITMAP _name*,_fname* -{ - local w,h,a,r,g,b - virtual at 0 - file _fname - load w dword from _bmp.i.biWidth - load h dword from _bmp.i.biHeight - end virtual - align 4 - label _name - .width = w - .height = h - dd w,h - a=54+(w*3+(w mod 4))*(h-1) - size = $ - repeat h - repeat w - virtual at 0 - file _fname - load r from a+0 - load g from a+1 - load b from a+2 - end virtual - db r,g,b - a=a+3 - end repeat - a=a-w*3*2-(w mod 4) - end repeat -} - -macro define_colors name,[col,val] -{ - common - local a,b,c - forward - match =binner,col \{ a = val \} - match =bouter,col \{ b = val \} - match =bframe,col \{ c = val \} - common - name equ a,b,c -} - -macro SKIN_PARAMS [a] -{ - common - local _height,_margins,_colors,_colors_1,_dtp,_dtp_sz - __params__: - forward - match qq == ww,a - \{ - match =height,qq \\{ _height = ww \\} - match =margins,qq \\{ - match [q1:q2:q3:q4],ww - \\\{ - _margins equ q3,q1,q4,q2 - \\\} - \\} - match =colors =active,qq - \\{ - match [q10==q11:q20==q21:q30==q31],ww - \\\{ - define_colors _colors,q10,q11,q20,q21,q30,q31 - \\\} - \\} - match =colors =inactive,qq - \\{ - match [q10==q11:q20==q21:q30==q31],ww - \\\{ - define_colors _colors_1,q10,q11,q20,q21,q30,q31 - \\\} - \\} - match =dtp,qq \\{ _dtp equ ww \\} - \} - common - dd _height - dw _margins - dd _colors,_colors_1 - virtual at 0 - file _dtp - _dtp_sz = $ - end virtual - dd _dtp_sz - file _dtp -} - -macro SKIN_BUTTONS [a] -{ - common - local btn - __buttons__: - forward - match qq == ww,a - \{ - btn = 0 - match =close,qq \\{ btn = 1 \\} - match =minimize,qq \\{ btn = 2 \\} - match [q1:q2][q3:q4],ww - \\{ - if btn <> 0 - dd btn - dw q1,q2,q3,q4 - end if - \\} - \} - common - dd 0 -} - -macro SKIN_BITMAPS [a] -{ - common - local bmp - __bitmaps__: - forward - match qq == ww,a - \{ - bmp=-1 - match qqq =active,qq \\{ bmp = 1 \\} - match qqq =inactive,qq \\{ bmp = 0 \\} - match =left qqq,qq - \\{ - if bmp >= 0 - dw 1,bmp - dd ww - end if - \\} - match =oper qqq,qq - \\{ - if bmp >= 0 - dw 2,bmp - dd ww - end if - \\} - match =base qqq,qq - \\{ - if bmp >= 0 - dw 3,bmp - dd ww - end if - \\} - \} - common - dd 0 -} diff --git a/kernel/branches/Kolibri-acpi/skin/myblue.dtp b/kernel/branches/Kolibri-acpi/skin/myblue.dtp deleted file mode 100644 index 9e268cc7a7e358f6da593fac8e74b92da4d39ed3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40 rcmcap6Tol>ioaaA!0_eE7lwQ5`WQ}>*)V*2_l<#rgMr~%Qy2pPo0k%m diff --git a/kernel/branches/Kolibri-acpi/skin/oper.bmp b/kernel/branches/Kolibri-acpi/skin/oper.bmp deleted file mode 100644 index 6011b6d1bdecfb620e2244d0c02ad6332c940d52..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2694 zcmchZu}TC%5JcNd3=GA@SiivV0s}KaP((yHL`*~s1OpL43=ToWpYmH25e(!46KSiv zc6(>%lwBv-p|-B4uWR0pf!xN{WI=qb!`JYv;#tBoC(Ce=ZG8W{$j2M7mHC16x+@fj zSk-pN3piEJ*cNqhKReBjCHHMl1{S&R`vPf?#mUrrgfyLJP435`Lq{X+lq!ZpfNmbV zbP8h;VL`6Fb0;wdR6oZu9owsR5@P_vOwn_$y}`^1A`8{&kxY+UTx0?fMcPEo6upf5 zbs|t4i-IeNDC%DIKG-rv&$-#ve%-2mp9+Md0yIluCmmplUdGjP(X$peyiasuEGQ_lrfr#WFXY~dLJ26XgPt}~TclPYcOnWU++h7x7?&yc zihFN|^!gW#F${*5lc^V_D(<7`lPfE-EoRv1+0Vw3Y{eyXKqnVI Iyzsm32kq!*F8}}l diff --git a/kernel/branches/Kolibri-acpi/skin/oper_1.bmp b/kernel/branches/Kolibri-acpi/skin/oper_1.bmp deleted file mode 100644 index d57bd2d161f9f2364bbb199d087b9f28142bef8d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2694 zcmchZy-Nc@5XH|T{43TJT{S$n-mki6~;4UlN^6oJ^JMVtCDa6rs>lx#k7cHxP{`Q*=A-YkuJ^zo@thEjJY|Q*=A-`_U5ADVHg_9rxpS8B$zq)iSS) zBc|wf+{#J1a+=1g