Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

566 lines
17 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. diskc.c
  5. Abstract:
  6. This is the NEC PD756 (aka AT, aka ISA, aka ix86) and Intel 82077
  7. (aka MIPS) floppy diskette detection code for NT. This file also
  8. collect BIOS disk drive parameters.
  9. Author:
  10. Shie-Lin Tzong (shielint) Dec-26-1991.
  11. Environment:
  12. x86 real mode.
  13. Revision History:
  14. Notes:
  15. --*/
  16. //
  17. // Include files.
  18. //
  19. #include "hwdetect.h"
  20. #include "disk.h"
  21. #include <string.h>
  22. FPFWCONFIGURATION_COMPONENT_DATA
  23. GetFloppyInformation(
  24. VOID
  25. )
  26. /*++
  27. Routine Description:
  28. This routine tries to get floppy configuration information.
  29. Arguments:
  30. None.
  31. Return Value:
  32. A pointer to a FPCONFIGURATION_COMPONENT_DATA is returned. It is
  33. the head of floppy component tree root.
  34. --*/
  35. {
  36. UCHAR DriveType;
  37. FPUCHAR ParameterTable;
  38. FPFWCONFIGURATION_COMPONENT_DATA CurrentEntry, PreviousEntry = NULL;
  39. FPFWCONFIGURATION_COMPONENT_DATA FirstController = NULL;
  40. FPFWCONFIGURATION_COMPONENT Component;
  41. HWCONTROLLER_DATA ControlData;
  42. UCHAR FloppyNumber = 0;
  43. UCHAR FloppySkipped = 0;
  44. UCHAR DiskName[30];
  45. UCHAR FloppyParmTable[FLOPPY_PARAMETER_TABLE_LENGTH];
  46. FPUCHAR fpString;
  47. USHORT Length, z;
  48. ULONG MaxDensity = 0;
  49. CM_FLOPPY_DEVICE_DATA far *FloppyData;
  50. FPHWRESOURCE_DESCRIPTOR_LIST DescriptorList;
  51. USHORT FloppyDataVersion;
  52. for (z = 0; z < FLOPPY_PARAMETER_TABLE_LENGTH; z++ ) {
  53. FloppyParmTable[z] = 0;
  54. }
  55. //
  56. // Initialize Controller data
  57. //
  58. ControlData.NumberPortEntries = 0;
  59. ControlData.NumberIrqEntries = 0;
  60. ControlData.NumberMemoryEntries = 0;
  61. ControlData.NumberDmaEntries = 0;
  62. z = 0;
  63. //
  64. // Allocate space for Controller component and initialize it.
  65. //
  66. CurrentEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
  67. sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
  68. FirstController = CurrentEntry;
  69. Component = &CurrentEntry->ComponentEntry;
  70. Component->Class = ControllerClass;
  71. Component->Type = DiskController;
  72. Component->Flags.Removable = 1;
  73. Component->Flags.Input = 1;
  74. Component->Flags.Output = 1;
  75. Component->Version = 0;
  76. Component->Key = 0;
  77. Component->AffinityMask = 0xffffffff;
  78. //
  79. // Set up Port information
  80. //
  81. ControlData.NumberPortEntries = 1;
  82. ControlData.DescriptorList[z].Type = RESOURCE_PORT;
  83. ControlData.DescriptorList[z].ShareDisposition =
  84. CmResourceShareDeviceExclusive;
  85. ControlData.DescriptorList[z].Flags = CM_RESOURCE_PORT_IO;
  86. ControlData.DescriptorList[z].u.Port.Start.LowPart = (ULONG)0x3f0;
  87. ControlData.DescriptorList[z].u.Port.Start.HighPart = (ULONG)0;
  88. ControlData.DescriptorList[z].u.Port.Length = 8;
  89. z++;
  90. //
  91. // Set up Irq information
  92. //
  93. ControlData.NumberIrqEntries = 1;
  94. ControlData.DescriptorList[z].Type = RESOURCE_INTERRUPT;
  95. ControlData.DescriptorList[z].ShareDisposition =
  96. CmResourceShareUndetermined;
  97. if (HwBusType == MACHINE_TYPE_MCA) {
  98. ControlData.DescriptorList[z].Flags = LEVEL_SENSITIVE;
  99. } else {
  100. ControlData.DescriptorList[z].Flags = EDGE_TRIGGERED;
  101. }
  102. ControlData.DescriptorList[z].u.Interrupt.Level = 6;
  103. ControlData.DescriptorList[z].u.Interrupt.Vector = 6;
  104. ControlData.DescriptorList[z].u.Interrupt.Affinity = ALL_PROCESSORS;
  105. z++;
  106. //
  107. // Set up DMA information. Only set channel number. Timming and
  108. // transferSize are defaulted - 8 bits and ISA compatible.
  109. //
  110. ControlData.NumberDmaEntries = 1;
  111. ControlData.DescriptorList[z].Type = RESOURCE_DMA;
  112. ControlData.DescriptorList[z].ShareDisposition =
  113. CmResourceShareUndetermined;
  114. ControlData.DescriptorList[z].Flags = 0;
  115. ControlData.DescriptorList[z].u.Dma.Channel = (ULONG)2;
  116. ControlData.DescriptorList[z].u.Dma.Port = 0;
  117. z++;
  118. CurrentEntry->ConfigurationData =
  119. HwSetUpResourceDescriptor(Component,
  120. NULL,
  121. &ControlData,
  122. 0,
  123. NULL
  124. );
  125. //
  126. // Collect disk peripheral data
  127. //
  128. while (1) {
  129. _asm {
  130. push es
  131. mov DriveType, 0
  132. mov FloppyDataVersion, CURRENT_FLOPPY_DATA_VERSION
  133. mov ah, 15h
  134. mov dl, FloppyNumber
  135. int 13h
  136. jc short CmosTest
  137. cmp ah, 0
  138. je short Exit
  139. cmp ah, 2 ; make sure this is floppy
  140. ja short Exit
  141. mov ah, 8
  142. mov dl, FloppyNumber
  143. lea di, word ptr FloppyParmTable ; use 'word ptr' to quiet compiler
  144. push ds
  145. pop es ; (es:di)->dummy FloppyParmTable
  146. int 13h
  147. jc short CmosTest
  148. mov DriveType, bl
  149. mov ax, es
  150. mov word ptr ParameterTable + 2, ax
  151. mov word ptr ParameterTable, di
  152. jmp short Exit
  153. CmosTest:
  154. ;
  155. ; ifint 13 fails, we know that floppy drive is present.
  156. ;So, we tryto get the Drive Type from CMOS.
  157. ;
  158. mov al, CMOS_FLOPPY_CONFIG_BYTE
  159. mov dx, CMOS_CONTROL_PORT ; address port
  160. out dx, al
  161. jmp short delay1 ; I/O DELAY
  162. delay1:
  163. mov dx, CMOS_DATA_PORT ; READ IN REQUESTED CMOS DATA
  164. in al, dx
  165. jmp short delay2 ; I/O DELAY
  166. delay2:
  167. cmp FloppyNumber, 0
  168. jne short CmosTest1
  169. and al, 0xf0
  170. shr al, 4
  171. jmp short Test2Cmos
  172. CmosTest1:
  173. cmp FloppyNumber, 1
  174. jne short Exit
  175. and al, 0xf
  176. Test2Cmos:
  177. mov DriveType, al
  178. mov FloppyDataVersion, 0
  179. Exit:
  180. pop es
  181. }
  182. if (DriveType) {
  183. //
  184. // Allocate space for first pripheral component and initialize it.
  185. //
  186. CurrentEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
  187. sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
  188. Component = &CurrentEntry->ComponentEntry;
  189. Component->Class = PeripheralClass;
  190. Component->Type = FloppyDiskPeripheral;
  191. Component->Version = 0;
  192. Component->Key = FloppyNumber - FloppySkipped;
  193. Component->AffinityMask = 0xffffffff;
  194. Component->ConfigurationDataLength = 0;
  195. //
  196. // Set up type string.
  197. //
  198. strcpy(DiskName, "FLOPPYx");
  199. DiskName[6] = FloppyNumber - FloppySkipped + (UCHAR)'1';
  200. Length = strlen(DiskName) + 1;
  201. fpString = (FPUCHAR)HwAllocateHeap(Length, FALSE);
  202. _fstrcpy(fpString, DiskName);
  203. Component->IdentifierLength = Length;
  204. Component->Identifier = fpString;
  205. //
  206. // Set up floppy device specific data
  207. //
  208. switch (DriveType) {
  209. case 1:
  210. MaxDensity = 360;
  211. break;
  212. case 2:
  213. MaxDensity = 1200;
  214. break;
  215. case 3:
  216. MaxDensity = 720;
  217. break;
  218. case 4:
  219. MaxDensity = 1440;
  220. break;
  221. case 5:
  222. case 6:
  223. MaxDensity = 2880;
  224. break;
  225. case 0x10:
  226. //
  227. // Mark a removable atapi as a super floppy.
  228. // Enable it to work around the problem of not having
  229. // a floppy but only a LS-120
  230. //
  231. //N.B we can ONLY get away with using the high bit on the
  232. // superfloppy. SFLOPPY doesn't use this field
  233. // fdc does, but isn't loaded on these devices!
  234. //
  235. MaxDensity=(2880 | 0x80000000);
  236. break;
  237. default:
  238. MaxDensity = 0;
  239. break;
  240. }
  241. if (FloppyDataVersion == CURRENT_FLOPPY_DATA_VERSION) {
  242. Length = sizeof(CM_FLOPPY_DEVICE_DATA);
  243. } else {
  244. Length = (SHORT)&(((CM_FLOPPY_DEVICE_DATA*)0)->StepRateHeadUnloadTime);
  245. }
  246. DescriptorList = (FPHWRESOURCE_DESCRIPTOR_LIST)HwAllocateHeap(
  247. Length + sizeof(HWRESOURCE_DESCRIPTOR_LIST),
  248. TRUE);
  249. CurrentEntry->ConfigurationData = DescriptorList;
  250. Component->ConfigurationDataLength =
  251. Length + sizeof(HWRESOURCE_DESCRIPTOR_LIST);
  252. DescriptorList->Count = 1;
  253. DescriptorList->PartialDescriptors[0].Type = RESOURCE_DEVICE_DATA;
  254. DescriptorList->PartialDescriptors[0].u.DeviceSpecificData.DataSize =
  255. Length;
  256. FloppyData = (CM_FLOPPY_DEVICE_DATA far *)(DescriptorList + 1);
  257. FloppyData->MaxDensity = MaxDensity;
  258. FloppyData->Version = FloppyDataVersion;
  259. if (FloppyDataVersion == CURRENT_FLOPPY_DATA_VERSION) {
  260. _fmemcpy((FPCHAR)&FloppyData->StepRateHeadUnloadTime,
  261. ParameterTable,
  262. sizeof(CM_FLOPPY_DEVICE_DATA) -
  263. (SHORT)&(((CM_FLOPPY_DEVICE_DATA*)0)->StepRateHeadUnloadTime)
  264. );
  265. }
  266. if ((FloppyNumber - FloppySkipped) == 0) {
  267. FirstController->Child = CurrentEntry;
  268. } else {
  269. PreviousEntry->Sibling = CurrentEntry;
  270. }
  271. CurrentEntry->Parent = FirstController;
  272. PreviousEntry = CurrentEntry;
  273. FloppyNumber++;
  274. } else {
  275. //
  276. // This is a *hack* for ntldr. Here we create a arc name for
  277. // each bios disks such that ntldr can open them.
  278. //
  279. if (NumberBiosDisks != 0) {
  280. for (z = 0; z < NumberBiosDisks; z++) {
  281. //
  282. // Allocate space for disk peripheral component
  283. //
  284. CurrentEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
  285. sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
  286. Component = &CurrentEntry->ComponentEntry;
  287. Component->Class = PeripheralClass;
  288. Component->Type = DiskPeripheral;
  289. Component->Flags.Input = 1;
  290. Component->Flags.Output = 1;
  291. Component->Version = 0;
  292. Component->Key = z;
  293. Component->AffinityMask = 0xffffffff;
  294. //
  295. // Set up identifier string = 8 digit signature - 8 digit checksum
  296. // for example: 00fe964d-005467dd
  297. //
  298. GetDiskId(0x80 + z, DiskName);
  299. if (DiskName[0] == (UCHAR)NULL) {
  300. strcpy(DiskName, "BIOSDISKx");
  301. DiskName[8] = (UCHAR)z + (UCHAR)'1';
  302. }
  303. Length = strlen(DiskName) + 1;
  304. fpString = (FPUCHAR)HwAllocateHeap(Length, FALSE);
  305. _fstrcpy(fpString, DiskName);
  306. Component->IdentifierLength = Length;
  307. Component->Identifier = fpString;
  308. //
  309. // Set up BIOS disk device specific data.
  310. // (If extended int 13 drive parameters are supported by
  311. // BIOS, we will collect them and store them here.)
  312. //
  313. if (IsExtendedInt13Available(0x80+z)) {
  314. DescriptorList = (FPHWRESOURCE_DESCRIPTOR_LIST)HwAllocateHeap(
  315. sizeof(HWRESOURCE_DESCRIPTOR_LIST) +
  316. sizeof(CM_DISK_GEOMETRY_DEVICE_DATA),
  317. TRUE);
  318. Length = GetExtendedDriveParameters(
  319. 0x80 + z,
  320. (CM_DISK_GEOMETRY_DEVICE_DATA far *)(DescriptorList + 1)
  321. );
  322. if (Length) {
  323. CurrentEntry->ConfigurationData = DescriptorList;
  324. Component->ConfigurationDataLength =
  325. Length + sizeof(HWRESOURCE_DESCRIPTOR_LIST);
  326. DescriptorList->Count = 1;
  327. DescriptorList->PartialDescriptors[0].Type = RESOURCE_DEVICE_DATA;
  328. DescriptorList->PartialDescriptors[0].u.DeviceSpecificData.DataSize =
  329. Length;
  330. } else {
  331. HwFreeHeap(sizeof(HWRESOURCE_DESCRIPTOR_LIST) +
  332. sizeof(CM_DISK_GEOMETRY_DEVICE_DATA));
  333. }
  334. }
  335. if (PreviousEntry == NULL) {
  336. FirstController->Child = CurrentEntry;
  337. } else {
  338. PreviousEntry->Sibling = CurrentEntry;
  339. }
  340. CurrentEntry->Parent = FirstController;
  341. PreviousEntry = CurrentEntry;
  342. }
  343. }
  344. return (FirstController);
  345. }
  346. }
  347. }
  348. #pragma warning(4:4146) // unary minus operator applied to unsigned type (checksum on line 733)
  349. VOID
  350. GetDiskId(
  351. USHORT Disk,
  352. PUCHAR Identifier
  353. )
  354. /*++
  355. Routine Description:
  356. This routine reads the master boot sector of the specified harddisk drive,
  357. compute the checksum of the sector to form a drive identifier.
  358. The identifier will be set to "8-digit-checksum"+"-"+"8-digit-signature"
  359. For example: 00ff6396-6549071f
  360. Arguments:
  361. Disk - supplies the BIOS drive number, i.e. 80h - 87h
  362. Identifier - Supplies a buffer to receive the disk id.
  363. Return Value:
  364. None. In the worst case, the Identifier will be empty.
  365. --*/
  366. {
  367. UCHAR Sector[512];
  368. ULONG Signature, Checksum;
  369. USHORT i, Length;
  370. PUCHAR BufferAddress;
  371. BOOLEAN Fail;
  372. Identifier[0] = 0;
  373. BufferAddress = &Sector[0];
  374. Fail = FALSE;
  375. //
  376. // Read in the first sector
  377. //
  378. _asm {
  379. push es
  380. mov ax, 0x201
  381. mov cx, 1
  382. mov dx, Disk
  383. push ss
  384. pop es
  385. mov bx, BufferAddress
  386. int 0x13
  387. pop es
  388. jnc Gdixxx
  389. mov Fail, 1
  390. Gdixxx:
  391. }
  392. if (Fail) {
  393. #if DBG
  394. // could not get the sector, so return NULL DiskID
  395. BlPrint("Failed to read sector -- returning NULL DiskId\n");
  396. #endif
  397. return;
  398. }
  399. Signature = ((PULONG)Sector)[PARTITION_TABLE_OFFSET/2-1];
  400. //
  401. // compute the checksum
  402. //
  403. Checksum = 0;
  404. for (i = 0; i < 128; i++) {
  405. Checksum += ((PULONG)Sector)[i];
  406. }
  407. Checksum = -Checksum;
  408. //
  409. // Zero the identifier
  410. //
  411. for (i=0; i < 30; i++) {
  412. Identifier[i]='0';
  413. }
  414. //
  415. // Put the dashes in the right places.
  416. //
  417. Identifier[8] = '-';
  418. Identifier[17] = '-';
  419. //
  420. // If the boot sector has a valid partition table signature,
  421. // attach an 'A.' Otherwise we use 'X.'
  422. //
  423. if (((PUSHORT)Sector)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE) {
  424. Identifier[18]='X';
  425. } else {
  426. Identifier[18]='A';
  427. }
  428. //
  429. // Reuse sector buffer to build checksum string.
  430. //
  431. ultoa(Checksum, Sector, 16);
  432. Length = strlen(Sector);
  433. for (i=0; i<Length; i++) {
  434. Identifier[7-i] = Sector[Length-i-1];
  435. }
  436. //
  437. // Reuse sector buffer to build signature string.
  438. //
  439. ultoa(Signature, Sector, 16);
  440. Length = strlen(Sector);
  441. for (i=0; i<Length; i++) {
  442. Identifier[16-i] = Sector[Length-i-1];
  443. }
  444. //
  445. // Terminate string.
  446. //
  447. Identifier[19] = 0;
  448. #if DBG
  449. BlPrint("%s\n", Identifier);
  450. #endif
  451. }