.386
LOCALS

.MODEL	FLAT


L			EQU	<LARGE>

;Значения параметра функции GetStdHandle
STD_INPUT_HANDLE	EQU	-10
STD_OUTPUT_HANDLE	EQU	-11
STD_ERROR_HANDLE	EQU	-12


;*******************************************************************************
;Параметры устройства IDE/ATAPI
;*******************************************************************************
SCANDEVENTRY	STRUC
	sde_wBasePort	DW	?
	sde_bDevNum	DB	?
	sde_lpszPort	DD	?
SCANDEVENTRY	ENDS


EXTRN	hStdOut:DWORD

EXTRN	ExitProcess:PROC
EXTRN	GetStdHandle:PROC
EXTRN	WaitForSingleObject:PROC
EXTRN	_wsprintfA:PROC
EXTRN	lstrcpynA:PROC
EXTRN	GetVersionExA:PROC


.DATA

szPriMaster	DB	"======================Primary Master=======================", 0Dh, 0Ah, 0
szPriSlave	DB	"=======================Primary Slave=======================", 0Dh, 0Ah, 0
szSecMaster	DB	"=====================Secondary Master======================", 0Dh, 0Ah, 0
szSecSlave	DB	"======================Secondary Slave======================", 0Dh, 0Ah, 0
szTerMaster	DB	"======================Tertiary Master======================", 0Dh, 0Ah, 0
szTerSlave	DB	"======================Tertiary Slave=======================", 0Dh, 0Ah, 0
szQuaMaster	DB	"=====================Quaternary Master=====================", 0Dh, 0Ah, 0
szQuaSlave	DB	"=====================Quaternary Slave======================", 0Dh, 0Ah, 0

szDevice	DB	"           Device: %s", 0Dh, 0Ah, 0
szModel		DB	"            Model: %s", 0Dh, 0Ah, 0
szFirmwareRev	DB	"Firmware Revision: %s", 0Dh, 0Ah, 0
szSerNum	DB	"    Serial Number: %s", 0Dh, 0Ah, 0

szHDD		DB	"HDD %uM", 0
szCDROM		DB	"CDROM", 0
szUnknown	DB	"Unknown", 0

szPressAnyKey	DB	0Dh, 0Ah, "Press any key...", 0

ScanDevices	SCANDEVENTRY	<1F0h,0,OFFSET szPriMaster>
		SCANDEVENTRY	<1F0h,1,OFFSET szPriSlave>
		SCANDEVENTRY	<170h,2,OFFSET szSecMaster>
		SCANDEVENTRY	<170h,3,OFFSET szSecSlave>
		SCANDEVENTRY	<1E8h,4,OFFSET szTerMaster>
		SCANDEVENTRY	<1E8h,5,OFFSET szTerSlave>
		SCANDEVENTRY	<168h,6,OFFSET szQuaMaster>
		SCANDEVENTRY	<168h,7,OFFSET szQuaSlave>
SCANDEVICESCOUNT	=	($-ScanDevices)/SIZE SCANDEVENTRY


.DATA?

DevInfo		DW	256 DUP(?)


.CODE

EXTRN	puts:PROC
EXTRN	fputs:PROC
EXTRN	printf:PROC
EXTRN	Ring0Call:PROC
EXTRN	GetATAPIDevInfo:PROC
EXTRN	GetIDEDevInfo:PROC
EXTRN	DetectATAPIDev:PROC
EXTRN	NT_GetDevInfo:PROC

Start:
		push	L STD_OUTPUT_HANDLE
		call	GetStdHandle
		inc	eax
		jz	Exit
		dec	eax
		mov	[hStdOut],eax

		mov	ebp,OFFSET W9x_GetDevInfo
		call	IsWinNT				;Windows NT?
		jnz	@@ScanDevices

		mov	ebp,OFFSET NT_GetDevInfo

@@ScanDevices:

;Сканирование устройств IDE/ATAPI
		mov	esi,OFFSET ScanDevices		;ESI -> ScanDevices
		mov	edi,OFFSET DevInfo		;EDI -> DevInfo

		mov	ecx,SCANDEVICESCOUNT
@@DevLoop:	push	ecx

;Получение информации об устройстве IDE/ATAPI
		mov	dx,[(SCANDEVENTRY PTR esi).sde_wBasePort]
		mov	al,[(SCANDEVENTRY PTR esi).sde_bDevNum]
		call	ebp
		or	eax,eax				;информация получена?
		jz	@@NextDev

;Вывод информации об устройстве IDE/ATAPI
		push	[(SCANDEVENTRY PTR esi).sde_lpszPort]
		call	puts

		call	PrintDevInfo

@@NextDev:	pop	ecx
		add	esi,SIZE SCANDEVENTRY
		loop	@@DevLoop

;Ожидание нажатия клавиши
		push	L STD_ERROR_HANDLE
		call	GetStdHandle

		push	L OFFSET szPressAnyKey
		push	eax
		call	fputs

		push	L STD_INPUT_HANDLE
		call	GetStdHandle
		inc	eax
		jz	Exit
		dec	eax

		push	L 0FFFFFFFFh
		push	eax
		call	WaitForSingleObject

Exit:
		push	L 0
		call	ExitProcess


;*******************************************************************************
;PrintDevInfo	выводит информацию об устройстве IDE/ATAPI
;*******************************************************************************
;Использует:	lstrcpynA, printf
;
;Вызов:		EDI -> буфер с информацией об устройстве
;
;Возврат:	нет
;
;Изменяемые
;  регистры:	EAX,ECX,EDX,Flags
;*******************************************************************************
PrintDevInfo	PROC
		LOCAL	@@szTemp:BYTE:64 = LOCAL_SIZE

		enter	LOCAL_SIZE,0
		push	esi

		lea	esi,[@@szTemp]		;ESI -> @@szTemp

;Тип устройства
		mov	al,[edi+1]
		test	al,80h			;устройство ATAPI?
		jz	@@IDE

		and	al,1Fh			;AL = тип устройства ATAPI
		cmp	al,5			;CDROM?
		mov	eax,OFFSET szCDROM
		je	@@PrintDeviceType
		mov	eax,OFFSET szUnknown
		jmp	@@PrintDeviceType

@@IDE:

;Жесткий диск IDE
		mov	eax,DWORD PTR [edi+120]	;EAX = общее число секторов
						;в режиме LBA
		cmp	eax,16515072
		jae	@@GetSizeInMB

		movzx	eax,WORD PTR [edi+2]	;EAX = количество цилиндров
		movzx	ecx,WORD PTR [edi+6]	;ECX = количество головок
		mul	ecx			;EAX = количество дорожек
		movzx	ecx,WORD PTR [edi+12]	;ECX = число секторов на дорожке
		mul	ecx			;EAX = общее число секторов

@@GetSizeInMB:	mov	ecx,512
		mul	ecx
		mov	ecx,500000
		div	ecx
		shr	eax,1			;EAX = объем диска в мегабайтах
		adc	eax,0			;округление до мегабайта

		push	eax
		push	L OFFSET szHDD
		push	esi
		call	_wsprintfA
		add	esp,12
		mov	eax,esi

@@PrintDeviceType:
		push	eax
		push	L OFFSET szDevice
		call	printf
		add	esp,8

;Модель
		cmp	WORD PTR [edi+54],0
		je	@@Model_Done

		push	L 41
		lea	eax,[edi+54]
		push	eax
		push	esi
		call	lstrcpynA

		push	esi
		push	L OFFSET szModel
		call	printf
		add	esp,8

@@Model_Done:

;Firmware Revision
		cmp	WORD PTR [edi+46],0
		je	@@FirmwareRev_Done

		push	L 9
		lea	eax,[edi+46]
		push	eax
		push	esi
		call	lstrcpynA

		push	esi
		push	L OFFSET szFirmwareRev
		call	printf
		add	esp,8

@@FirmwareRev_Done:

;Серийный номер
		cmp	WORD PTR [edi+20],0
		je	@@SerNum_Done

		push	L 21
		lea	eax,[edi+20]
		push	eax
		push	esi
		call	lstrcpynA

		push	esi
		push	L OFFSET szSerNum
		call	printf
		add	esp,8

@@SerNum_Done:

		pop	esi
		leave

		ret

PrintDevInfo	ENDP


;*******************************************************************************
;Параметры, передаваемые в процедуру Ring0_GetDevInfo
;*******************************************************************************
GETDEVINFOPARAMS	STRUC
	gdip_wBasePort	DW	?
	gdip_bDevNum	DB	?
	gdip_lpBuffer	DD	?
GETDEVINFOPARAMS	ENDS

;*******************************************************************************
;W9x_GetDevInfo	получает информацию об устройстве IDE/ATAPI (Win9x)
;*******************************************************************************
;Использует:	Ring0Call, Ring0_GetDevInfo
;
;Вызов:		DX = базовый порт
;		AL = номер устройства
;		EDI -> буфер для информации об устройстве
;
;Возврат:	EAX = флаг успешного/неудачного завершения
;
;Изменяемые
;  регистры:	EAX,ECX,DX,Flags
;*******************************************************************************
W9x_GetDevInfo	PROC
		LOCAL	@@gdip:GETDEVINFOPARAMS, @@fSuccess:DWORD = LOCAL_SIZE

		enter	LOCAL_SIZE,0

		mov	[@@gdip.gdip_wBasePort],dx
		mov	[@@gdip.gdip_bDevNum],al
		mov	[@@gdip.gdip_lpBuffer],edi

		lea	eax,[@@fSuccess]
		push	eax
		lea	eax,[@@gdip]
		push	eax
		push	L OFFSET Ring0_GetDevInfo
		call	Ring0Call
		or	eax,eax				;процедура выполнена?
		jz	@@Exit

		mov	eax,[@@fSuccess]

@@Exit:		leave

		ret

W9x_GetDevInfo	ENDP

;*******************************************************************************
;Ring0_GetDevInfo получает информацию об устройстве IDE/ATAPI
;Вызывается из Ring 0
;*******************************************************************************
;Использует:	DetectATAPIDev, GetATAPIDevInfo, GetIDEDevInfo
;
;Вызов:		ECX -> параметры для получения информации (GETDEVINFOPARAMS)
;
;Возврат:	EAX = флаг успешного/неудачного завершения
;
;Изменяемые
;  регистры:	EAX,ECX,DX,Flags
;*******************************************************************************
Ring0_GetDevInfo	PROC	FAR

		push	edi

		mov	dx,[(GETDEVINFOPARAMS PTR ecx).gdip_wBasePort]
		mov	al,[(GETDEVINFOPARAMS PTR ecx).gdip_bDevNum]
		mov	edi,[(GETDEVINFOPARAMS PTR ecx).gdip_lpBuffer]

		push	eax
		push	edx
		call	DetectATAPIDev		;устройство ATAPI?
		pop	edx
		pop	eax
		jc	@@TryIDE

		call	GetATAPIDevInfo		;получить информацию
						;об устройстве ATAPI
		jmp	@@Exit

@@TryIDE:	call	GetIDEDevInfo		;получить информацию
						;об устройстве IDE

@@Exit:		setnc	al
		movzx	eax,al

		pop	edi

		ret

Ring0_GetDevInfo	ENDP


;*******************************************************************************
;Информация о версии OS, передаваемая GetVersionExA
;*******************************************************************************
OSVERSIONINFOA	STRUC
	osvi_dwOSVersionInfoSize	DD	?
	osvi_dwMajorVersion		DD	?
	osvi_dwMinorVersion		DD	?
	osvi_dwBuildNumber		DD	?
	osvi_dwPlatformId		DD	?
	osvi_szCSDVersion		DB	128 DUP(?)
OSVERSIONINFOA	ENDS

;Значения osvi_dwPlatformId
VER_PLATFORM_WIN32s		EQU	0
VER_PLATFORM_WIN32_WINDOWS	EQU	1
VER_PLATFORM_WIN32_NT		EQU	2

;*******************************************************************************
;IsWinNT	определяет наличие Windows NT
;*******************************************************************************
;Использует:	GetVersionExA
;
;Вызов:		нет
;
;Возврат:	ZF=1 - Windows NT
;		ZF=0 - не Windows NT
;
;Изменяемые
;  регистры:	EAX,ECX,EDX,Flags
;*******************************************************************************
IsWinNT		PROC
		LOCAL	@@osvi:OSVERSIONINFOA = LOCAL_SIZE

		enter	LOCAL_SIZE,0

		mov	[(OSVERSIONINFOA PTR esp).osvi_dwOSVersionInfoSize],SIZE OSVERSIONINFOA
		push	esp
		call	GetVersionExA
		cmp	[(OSVERSIONINFOA PTR esp).osvi_dwPlatformId],VER_PLATFORM_WIN32_NT

		leave

		ret

IsWinNT		ENDP


END	Start
