Leaked source code of windows server 2003
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.

1429 lines
37 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. ixpcidat.c
  5. Abstract:
  6. Get/Set bus data routines for the PCI bus
  7. Author:
  8. Environment:
  9. Kernel mode
  10. Revision History:
  11. --*/
  12. #include "bootx86.h"
  13. #include "arc.h"
  14. #include "ixfwhal.h"
  15. #include "ntconfig.h"
  16. #include "pci.h"
  17. //extern WCHAR rgzMultiFunctionAdapter[];
  18. //extern WCHAR rgzConfigurationData[];
  19. //extern WCHAR rgzIdentifier[];
  20. //extern WCHAR rgzPCIIdentifier[];
  21. //
  22. // Hal specific PCI bus structures
  23. //
  24. typedef struct tagPCIPBUSDATA {
  25. union {
  26. struct {
  27. PULONG Address;
  28. ULONG Data;
  29. } Type1;
  30. struct {
  31. PUCHAR CSE;
  32. PUCHAR Forward;
  33. ULONG Base;
  34. } Type2;
  35. } Config;
  36. } PCIPBUSDATA, *PPCIPBUSDATA;
  37. #define PciBitIndex(Dev,Fnc) (Fnc*32 + Dev);
  38. #define PCI_CONFIG_TYPE(PciData) ((PciData)->HeaderType & ~PCI_MULTIFUNCTION)
  39. #define BUSHANDLER _BUSHANDLER
  40. #define PBUSHANDLER _PBUSHANDLER
  41. // thunk for NtLdr
  42. typedef struct {
  43. ULONG NoBuses;
  44. ULONG BusNumber;
  45. PVOID BusData;
  46. PCIPBUSDATA theBusData;
  47. } BUSHANDLER, *PBUSHANDLER;
  48. #define HalpPCIPin2Line(bus,rbus,slot,pcidata)
  49. #define HalpPCILine2Pin(bus,rbus,slot,pcidata,pcidata2)
  50. #define ExAllocatePool(a,l) FwAllocatePool(l)
  51. // thunk for NtLdr
  52. typedef ULONG (*FncConfigIO) (
  53. IN PPCIPBUSDATA BusData,
  54. IN PVOID State,
  55. IN PUCHAR Buffer,
  56. IN ULONG Offset
  57. );
  58. typedef VOID (*FncSync) (
  59. IN PBUSHANDLER BusHandler,
  60. IN PCI_SLOT_NUMBER Slot,
  61. IN PKIRQL Irql,
  62. IN PVOID State
  63. );
  64. typedef VOID (*FncReleaseSync) (
  65. IN PBUSHANDLER BusHandler,
  66. IN KIRQL Irql
  67. );
  68. typedef struct {
  69. FncSync Synchronize;
  70. FncReleaseSync ReleaseSynchronzation;
  71. FncConfigIO ConfigRead[3];
  72. FncConfigIO ConfigWrite[3];
  73. } CONFIG_HANDLER, *PCONFIG_HANDLER;
  74. //
  75. // Prototypes
  76. //
  77. ULONG
  78. HalpGetPCIData (
  79. IN ULONG BusNumber,
  80. IN PCI_SLOT_NUMBER SlotNumber,
  81. IN PVOID Buffer,
  82. IN ULONG Offset,
  83. IN ULONG Length
  84. );
  85. ULONG
  86. HalpSetPCIData (
  87. IN ULONG BusNumber,
  88. IN PCI_SLOT_NUMBER SlotNumber,
  89. IN PVOID Buffer,
  90. IN ULONG Offset,
  91. IN ULONG Length
  92. );
  93. extern ULONG
  94. HalpGetPCIInterruptVector (
  95. IN PBUSHANDLER BusHandler,
  96. IN PBUSHANDLER RootHandler,
  97. IN ULONG BusInterruptLevel,
  98. IN ULONG BusInterruptVector,
  99. OUT PKIRQL Irql,
  100. OUT PKAFFINITY Affinity
  101. );
  102. NTSTATUS
  103. HalpAdjustPCIResourceList (
  104. IN PBUSHANDLER BusHandler,
  105. IN PBUSHANDLER RootHandler,
  106. IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList
  107. );
  108. NTSTATUS
  109. HalpAssignPCISlotResources (
  110. IN ULONG BusNumber,
  111. IN ULONG SlotNumber,
  112. IN OUT PCM_RESOURCE_LIST *AllocatedResources
  113. );
  114. VOID
  115. HalpInitializePciBuses (
  116. VOID
  117. );
  118. //VOID
  119. //HalpPCIPin2Line (
  120. // IN PBUSHANDLER BusHandler,
  121. // IN PBUSHANDLER RootHandler,
  122. // IN PCI_SLOT_NUMBER Slot,
  123. // IN PPCI_COMMON_CONFIG PciData
  124. // );
  125. //
  126. //VOID
  127. //HalpPCILine2Pin (
  128. // IN PBUSHANDLER BusHandler,
  129. // IN PBUSHANDLER RootHandler,
  130. // IN PCI_SLOT_NUMBER SlotNumber,
  131. // IN PPCI_COMMON_CONFIG PciNewData,
  132. // IN PPCI_COMMON_CONFIG PciOldData
  133. // );
  134. BOOLEAN
  135. HalpValidPCISlot (
  136. IN PBUSHANDLER BusHandler,
  137. IN PCI_SLOT_NUMBER Slot
  138. );
  139. VOID
  140. HalpReadPCIConfig (
  141. IN PBUSHANDLER BusHandler,
  142. IN PCI_SLOT_NUMBER Slot,
  143. IN PVOID Buffer,
  144. IN ULONG Offset,
  145. IN ULONG Length
  146. );
  147. VOID
  148. HalpWritePCIConfig (
  149. IN PBUSHANDLER BusHandler,
  150. IN PCI_SLOT_NUMBER Slot,
  151. IN PVOID Buffer,
  152. IN ULONG Offset,
  153. IN ULONG Length
  154. );
  155. PBUSHANDLER
  156. HalpGetPciBusHandler (
  157. IN ULONG BusNumber
  158. );
  159. //-------------------------------------------------
  160. VOID HalpPCISynchronizeType1 (
  161. IN PBUSHANDLER BusHandler,
  162. IN PCI_SLOT_NUMBER Slot,
  163. IN PKIRQL Irql,
  164. IN PVOID State
  165. );
  166. VOID HalpPCIReleaseSynchronzationType1 (
  167. IN PBUSHANDLER BusHandler,
  168. IN KIRQL Irql
  169. );
  170. ULONG HalpPCIReadUlongType1 (
  171. IN PPCIPBUSDATA BusData,
  172. IN PVOID State,
  173. IN PUCHAR Buffer,
  174. IN ULONG Offset
  175. );
  176. ULONG HalpPCIReadUcharType1 (
  177. IN PPCIPBUSDATA BusData,
  178. IN PVOID State,
  179. IN PUCHAR Buffer,
  180. IN ULONG Offset
  181. );
  182. ULONG HalpPCIReadUshortType1 (
  183. IN PPCIPBUSDATA BusData,
  184. IN PVOID State,
  185. IN PUCHAR Buffer,
  186. IN ULONG Offset
  187. );
  188. ULONG HalpPCIWriteUlongType1 (
  189. IN PPCIPBUSDATA BusData,
  190. IN PVOID State,
  191. IN PUCHAR Buffer,
  192. IN ULONG Offset
  193. );
  194. ULONG HalpPCIWriteUcharType1 (
  195. IN PPCIPBUSDATA BusData,
  196. IN PVOID State,
  197. IN PUCHAR Buffer,
  198. IN ULONG Offset
  199. );
  200. ULONG HalpPCIWriteUshortType1 (
  201. IN PPCIPBUSDATA BusData,
  202. IN PVOID State,
  203. IN PUCHAR Buffer,
  204. IN ULONG Offset
  205. );
  206. VOID HalpPCISynchronizeType2 (
  207. IN PBUSHANDLER BusHandler,
  208. IN PCI_SLOT_NUMBER Slot,
  209. IN PKIRQL Irql,
  210. IN PVOID State
  211. );
  212. VOID HalpPCIReleaseSynchronzationType2 (
  213. IN PBUSHANDLER BusHandler,
  214. IN KIRQL Irql
  215. );
  216. ULONG HalpPCIReadUlongType2 (
  217. IN PPCIPBUSDATA BusData,
  218. IN PVOID State,
  219. IN PUCHAR Buffer,
  220. IN ULONG Offset
  221. );
  222. ULONG HalpPCIReadUcharType2 (
  223. IN PPCIPBUSDATA BusData,
  224. IN PVOID State,
  225. IN PUCHAR Buffer,
  226. IN ULONG Offset
  227. );
  228. ULONG HalpPCIReadUshortType2 (
  229. IN PPCIPBUSDATA BusData,
  230. IN PVOID State,
  231. IN PUCHAR Buffer,
  232. IN ULONG Offset
  233. );
  234. ULONG HalpPCIWriteUlongType2 (
  235. IN PPCIPBUSDATA BusData,
  236. IN PVOID State,
  237. IN PUCHAR Buffer,
  238. IN ULONG Offset
  239. );
  240. ULONG HalpPCIWriteUcharType2 (
  241. IN PPCIPBUSDATA BusData,
  242. IN PVOID State,
  243. IN PUCHAR Buffer,
  244. IN ULONG Offset
  245. );
  246. ULONG HalpPCIWriteUshortType2 (
  247. IN PPCIPBUSDATA BusData,
  248. IN PVOID State,
  249. IN PUCHAR Buffer,
  250. IN ULONG Offset
  251. );
  252. #define DISABLE_INTERRUPTS() //_asm { cli }
  253. #define ENABLE_INTERRUPTS() //_asm { sti }
  254. //
  255. // Globals
  256. //
  257. ULONG PCIMaxDevice;
  258. BUSHANDLER PCIBusHandler;
  259. CONFIG_HANDLER PCIConfigHandlers = {
  260. HalpPCISynchronizeType1,
  261. HalpPCIReleaseSynchronzationType1,
  262. {
  263. HalpPCIReadUlongType1, // 0
  264. HalpPCIReadUcharType1, // 1
  265. HalpPCIReadUshortType1 // 2
  266. },
  267. {
  268. HalpPCIWriteUlongType1, // 0
  269. HalpPCIWriteUcharType1, // 1
  270. HalpPCIWriteUshortType1 // 2
  271. }
  272. };
  273. CONFIG_HANDLER PCIConfigHandlersType2 = {
  274. HalpPCISynchronizeType2,
  275. HalpPCIReleaseSynchronzationType2,
  276. {
  277. HalpPCIReadUlongType2, // 0
  278. HalpPCIReadUcharType2, // 1
  279. HalpPCIReadUshortType2 // 2
  280. },
  281. {
  282. HalpPCIWriteUlongType2, // 0
  283. HalpPCIWriteUcharType2, // 1
  284. HalpPCIWriteUshortType2 // 2
  285. }
  286. };
  287. UCHAR PCIDeref[4][4] = { {0,1,2,2},{1,1,1,1},{2,1,2,2},{1,1,1,1} };
  288. VOID
  289. HalpPCIConfig (
  290. IN PBUSHANDLER BusHandler,
  291. IN PCI_SLOT_NUMBER Slot,
  292. IN PUCHAR Buffer,
  293. IN ULONG Offset,
  294. IN ULONG Length,
  295. IN FncConfigIO *ConfigIO
  296. );
  297. VOID
  298. HalpInitializePciBus (
  299. VOID
  300. )
  301. {
  302. PPCI_REGISTRY_INFO PCIRegInfo;
  303. PPCIPBUSDATA BusData;
  304. PBUSHANDLER Bus;
  305. PCONFIGURATION_COMPONENT_DATA ConfigData;
  306. PCM_PARTIAL_RESOURCE_LIST Desc;
  307. PCM_PARTIAL_RESOURCE_DESCRIPTOR PDesc;
  308. ULONG i;
  309. ULONG HwType;
  310. Bus = &PCIBusHandler;
  311. PCIBusHandler.BusData = &PCIBusHandler.theBusData;
  312. PCIRegInfo = NULL; // not found
  313. ConfigData = NULL; // start at begining
  314. do {
  315. ConfigData = KeFindConfigurationNextEntry (
  316. FwConfigurationTree,
  317. AdapterClass,
  318. MultiFunctionAdapter,
  319. NULL,
  320. &ConfigData
  321. );
  322. if (ConfigData == NULL) {
  323. // PCI info not found
  324. return ;
  325. }
  326. if (ConfigData->ComponentEntry.Identifier == NULL ||
  327. _stricmp (ConfigData->ComponentEntry.Identifier, "PCI") != 0) {
  328. continue;
  329. }
  330. PCIRegInfo = NULL;
  331. Desc = ConfigData->ConfigurationData;
  332. PDesc = Desc->PartialDescriptors;
  333. for (i = 0; i < Desc->Count; i++) {
  334. if (PDesc->Type == CmResourceTypeDeviceSpecific) {
  335. PCIRegInfo = (PPCI_REGISTRY_INFO) (PDesc+1);
  336. break;
  337. }
  338. PDesc++;
  339. }
  340. } while (!PCIRegInfo) ;
  341. //
  342. // PCIRegInfo describes the system's PCI support as indicated
  343. // by the BIOS.
  344. //
  345. HwType = PCIRegInfo->HardwareMechanism & 0xf;
  346. switch (HwType) {
  347. case 1:
  348. // this is the default case
  349. PCIMaxDevice = PCI_MAX_DEVICES;
  350. break;
  351. //
  352. // Type2 does not work MP, nor does the default type2
  353. // support more the 0xf device slots
  354. //
  355. case 2:
  356. RtlMoveMemory (&PCIConfigHandlers,
  357. &PCIConfigHandlersType2,
  358. sizeof (PCIConfigHandlersType2));
  359. PCIMaxDevice = 0x10;
  360. break;
  361. default:
  362. // unsupport type
  363. PCIRegInfo->NoBuses = 0;
  364. }
  365. PCIBusHandler.NoBuses = PCIRegInfo->NoBuses;
  366. if (PCIRegInfo->NoBuses) {
  367. BusData = (PPCIPBUSDATA) Bus->BusData;
  368. switch (HwType) {
  369. case 1:
  370. BusData->Config.Type1.Address = (PULONG)PCI_TYPE1_ADDR_PORT;
  371. BusData->Config.Type1.Data = PCI_TYPE1_DATA_PORT;
  372. break;
  373. case 2:
  374. BusData->Config.Type2.CSE = PCI_TYPE2_CSE_PORT;
  375. BusData->Config.Type2.Forward = PCI_TYPE2_FORWARD_PORT;
  376. BusData->Config.Type2.Base = PCI_TYPE2_ADDRESS_BASE;
  377. break;
  378. }
  379. }
  380. }
  381. PBUSHANDLER
  382. HalpGetPciBusHandler (
  383. IN ULONG BusNumber
  384. )
  385. {
  386. if (PCIBusHandler.BusData == NULL) {
  387. HalpInitializePciBus ();
  388. }
  389. if (BusNumber > PCIBusHandler.NoBuses) {
  390. return NULL;
  391. }
  392. PCIBusHandler.BusNumber = BusNumber;
  393. return &PCIBusHandler;
  394. }
  395. ULONG
  396. HalpGetPCIData (
  397. IN ULONG BusNumber,
  398. IN PCI_SLOT_NUMBER Slot,
  399. IN PUCHAR Buffer,
  400. IN ULONG Offset,
  401. IN ULONG Length
  402. )
  403. /*++
  404. Routine Description:
  405. The function returns the Pci bus data for a device.
  406. Arguments:
  407. BusNumber - Indicates which bus.
  408. VendorSpecificDevice - The VendorID (low Word) and DeviceID (High Word)
  409. Buffer - Supplies the space to store the data.
  410. Length - Supplies a count in bytes of the maximum amount to return.
  411. Return Value:
  412. Returns the amount of data stored into the buffer.
  413. If this PCI slot has never been set, then the configuration information
  414. returned is zeroed.
  415. --*/
  416. {
  417. PBUSHANDLER BusHandler;
  418. PPCI_COMMON_CONFIG PciData;
  419. UCHAR iBuffer[PCI_COMMON_HDR_LENGTH];
  420. PPCIPBUSDATA BusData;
  421. ULONG Len;
  422. BusHandler = HalpGetPciBusHandler (BusNumber);
  423. if (!BusHandler) {
  424. return 0;
  425. }
  426. if (Length > sizeof (PCI_COMMON_CONFIG)) {
  427. Length = sizeof (PCI_COMMON_CONFIG);
  428. }
  429. Len = 0;
  430. PciData = (PPCI_COMMON_CONFIG) iBuffer;
  431. if (Offset >= PCI_COMMON_HDR_LENGTH) {
  432. //
  433. // The user did not request any data from the common
  434. // header. Verify the PCI device exists, then continue
  435. // in the device specific area.
  436. //
  437. HalpReadPCIConfig (BusHandler, Slot, PciData, 0, sizeof(ULONG));
  438. if (PciData->VendorID == PCI_INVALID_VENDORID) {
  439. return 0;
  440. }
  441. } else {
  442. //
  443. // Caller requested at least some data within the
  444. // common header. Read the whole header, effect the
  445. // fields we need to and then copy the user's requested
  446. // bytes from the header
  447. //
  448. //
  449. // Read this PCI devices slot data
  450. //
  451. Len = PCI_COMMON_HDR_LENGTH;
  452. HalpReadPCIConfig (BusHandler, Slot, PciData, 0, Len);
  453. if (PciData->VendorID == PCI_INVALID_VENDORID) {
  454. Len = 2; // only return invalid id
  455. }
  456. //
  457. // Has this PCI device been configured?
  458. //
  459. BusData = (PPCIPBUSDATA) BusHandler->BusData;
  460. HalpPCIPin2Line (BusHandler, RootHandler, Slot, PciData);
  461. //
  462. // Copy whatever data overlaps into the callers buffer
  463. //
  464. if (Len < Offset) {
  465. // no data at caller's buffer
  466. return 0;
  467. }
  468. Len -= Offset;
  469. if (Len > Length) {
  470. Len = Length;
  471. }
  472. RtlMoveMemory(Buffer, iBuffer + Offset, Len);
  473. Offset += Len;
  474. Buffer += Len;
  475. Length -= Len;
  476. }
  477. if (Length) {
  478. if (Offset >= PCI_COMMON_HDR_LENGTH) {
  479. //
  480. // The remaining Buffer comes from the Device Specific
  481. // area - put on the kitten gloves and read from it.
  482. //
  483. // Specific read/writes to the PCI device specific area
  484. // are guarenteed:
  485. //
  486. // Not to read/write any byte outside the area specified
  487. // by the caller. (this may cause WORD or BYTE references
  488. // to the area in order to read the non-dword aligned
  489. // ends of the request)
  490. //
  491. // To use a WORD access if the requested length is exactly
  492. // a WORD long & WORD aligned.
  493. //
  494. // To use a BYTE access if the requested length is exactly
  495. // a BYTE long.
  496. //
  497. HalpReadPCIConfig (BusHandler, Slot, Buffer, Offset, Length);
  498. Len += Length;
  499. }
  500. }
  501. return Len;
  502. }
  503. ULONG
  504. HalpSetPCIData (
  505. IN ULONG BusNumber,
  506. IN PCI_SLOT_NUMBER Slot,
  507. IN PUCHAR Buffer,
  508. IN ULONG Offset,
  509. IN ULONG Length
  510. )
  511. /*++
  512. Routine Description:
  513. The function returns the Pci bus data for a device.
  514. Arguments:
  515. VendorSpecificDevice - The VendorID (low Word) and DeviceID (High Word)
  516. Buffer - Supplies the space to store the data.
  517. Length - Supplies a count in bytes of the maximum amount to return.
  518. Return Value:
  519. Returns the amount of data stored into the buffer.
  520. --*/
  521. {
  522. PBUSHANDLER BusHandler;
  523. PPCI_COMMON_CONFIG PciData, PciData2;
  524. UCHAR iBuffer[PCI_COMMON_HDR_LENGTH];
  525. UCHAR iBuffer2[PCI_COMMON_HDR_LENGTH];
  526. PPCIPBUSDATA BusData;
  527. ULONG Len;
  528. BusHandler = HalpGetPciBusHandler (BusNumber);
  529. if (!BusHandler) {
  530. return 0;
  531. }
  532. if (Length > sizeof (PCI_COMMON_CONFIG)) {
  533. Length = sizeof (PCI_COMMON_CONFIG);
  534. }
  535. Len = 0;
  536. PciData = (PPCI_COMMON_CONFIG) iBuffer;
  537. PciData2 = (PPCI_COMMON_CONFIG) iBuffer2;
  538. if (Offset >= PCI_COMMON_HDR_LENGTH) {
  539. //
  540. // The user did not request any data from the common
  541. // header. Verify the PCI device exists, then continue in
  542. // the device specific area.
  543. //
  544. HalpReadPCIConfig (BusHandler, Slot, PciData, 0, sizeof(ULONG));
  545. if (PciData->VendorID == PCI_INVALID_VENDORID) {
  546. return 0;
  547. }
  548. } else {
  549. //
  550. // Caller requested to set at least some data within the
  551. // common header.
  552. //
  553. Len = PCI_COMMON_HDR_LENGTH;
  554. HalpReadPCIConfig (BusHandler, Slot, PciData, 0, Len);
  555. if (PciData->VendorID == PCI_INVALID_VENDORID ||
  556. PCI_CONFIG_TYPE (PciData) != 0) {
  557. // no device, or header type unkown
  558. return 0;
  559. }
  560. //
  561. // Set this device as configured
  562. //
  563. BusData = (PPCIPBUSDATA) BusHandler->BusData;
  564. //
  565. // Copy COMMON_HDR values to buffer2, then overlay callers changes.
  566. //
  567. RtlMoveMemory (iBuffer2, iBuffer, Len);
  568. Len -= Offset;
  569. if (Len > Length) {
  570. Len = Length;
  571. }
  572. RtlMoveMemory (iBuffer2+Offset, Buffer, Len);
  573. // in case interrupt line or pin was editted
  574. HalpPCILine2Pin (BusHandler, RootHandler, Slot, PciData2, PciData);
  575. //
  576. // Set new PCI configuration
  577. //
  578. HalpWritePCIConfig (BusHandler, Slot, iBuffer2+Offset, Offset, Len);
  579. Offset += Len;
  580. Buffer += Len;
  581. Length -= Len;
  582. }
  583. if (Length) {
  584. if (Offset >= PCI_COMMON_HDR_LENGTH) {
  585. //
  586. // The remaining Buffer comes from the Device Specific
  587. // area - put on the kitten gloves and write it
  588. //
  589. // Specific read/writes to the PCI device specific area
  590. // are guarenteed:
  591. //
  592. // Not to read/write any byte outside the area specified
  593. // by the caller. (this may cause WORD or BYTE references
  594. // to the area in order to read the non-dword aligned
  595. // ends of the request)
  596. //
  597. // To use a WORD access if the requested length is exactly
  598. // a WORD long & WORD aligned.
  599. //
  600. // To use a BYTE access if the requested length is exactly
  601. // a BYTE long.
  602. //
  603. HalpWritePCIConfig (BusHandler, Slot, Buffer, Offset, Length);
  604. Len += Length;
  605. }
  606. }
  607. return Len;
  608. }
  609. VOID
  610. HalpReadPCIConfig (
  611. IN PBUSHANDLER BusHandler,
  612. IN PCI_SLOT_NUMBER Slot,
  613. IN PVOID Buffer,
  614. IN ULONG Offset,
  615. IN ULONG Length
  616. )
  617. {
  618. if (!HalpValidPCISlot (BusHandler, Slot)) {
  619. //
  620. // Invalid SlotID return no data
  621. //
  622. RtlFillMemory (Buffer, Length, (UCHAR) -1);
  623. return ;
  624. }
  625. HalpPCIConfig (BusHandler, Slot, (PUCHAR) Buffer, Offset, Length,
  626. PCIConfigHandlers.ConfigRead);
  627. }
  628. VOID
  629. HalpWritePCIConfig (
  630. IN PBUSHANDLER BusHandler,
  631. IN PCI_SLOT_NUMBER Slot,
  632. IN PVOID Buffer,
  633. IN ULONG Offset,
  634. IN ULONG Length
  635. )
  636. {
  637. if (!HalpValidPCISlot (BusHandler, Slot)) {
  638. //
  639. // Invalid SlotID do nothing
  640. //
  641. return ;
  642. }
  643. HalpPCIConfig (BusHandler, Slot, (PUCHAR) Buffer, Offset, Length,
  644. PCIConfigHandlers.ConfigWrite);
  645. }
  646. BOOLEAN
  647. HalpValidPCISlot (
  648. IN PBUSHANDLER BusHandler,
  649. IN PCI_SLOT_NUMBER Slot
  650. )
  651. {
  652. PCI_SLOT_NUMBER Slot2;
  653. UCHAR HeaderType;
  654. ULONG i;
  655. if (Slot.u.bits.Reserved != 0) {
  656. return FALSE;
  657. }
  658. if (Slot.u.bits.DeviceNumber >= PCIMaxDevice) {
  659. return FALSE;
  660. }
  661. if (Slot.u.bits.FunctionNumber == 0) {
  662. return TRUE;
  663. }
  664. //
  665. // Non zero function numbers are only supported if the
  666. // device has the PCI_MULTIFUNCTION bit set in it's header
  667. //
  668. i = Slot.u.bits.DeviceNumber;
  669. //
  670. // Read DeviceNumber, Function zero, to determine if the
  671. // PCI supports multifunction devices
  672. //
  673. Slot2 = Slot;
  674. Slot2.u.bits.FunctionNumber = 0;
  675. HalpReadPCIConfig (
  676. BusHandler,
  677. Slot2,
  678. &HeaderType,
  679. FIELD_OFFSET (PCI_COMMON_CONFIG, HeaderType),
  680. sizeof (UCHAR)
  681. );
  682. if (!(HeaderType & PCI_MULTIFUNCTION) || HeaderType == 0xFF) {
  683. // this device doesn't exists or doesn't support MULTIFUNCTION types
  684. return FALSE;
  685. }
  686. return TRUE;
  687. }
  688. VOID
  689. HalpPCIConfig (
  690. IN PBUSHANDLER BusHandler,
  691. IN PCI_SLOT_NUMBER Slot,
  692. IN PUCHAR Buffer,
  693. IN ULONG Offset,
  694. IN ULONG Length,
  695. IN FncConfigIO *ConfigIO
  696. )
  697. {
  698. KIRQL OldIrql;
  699. ULONG i;
  700. UCHAR State[20];
  701. PPCIPBUSDATA BusData;
  702. BusData = (PPCIPBUSDATA) BusHandler->BusData;
  703. PCIConfigHandlers.Synchronize (BusHandler, Slot, &OldIrql, State);
  704. while (Length) {
  705. i = PCIDeref[Offset % sizeof(ULONG)][Length % sizeof(ULONG)];
  706. i = ConfigIO[i] (BusData, State, Buffer, Offset);
  707. Offset += i;
  708. Buffer += i;
  709. Length -= i;
  710. }
  711. PCIConfigHandlers.ReleaseSynchronzation (BusHandler, OldIrql);
  712. }
  713. VOID HalpPCISynchronizeType1 (
  714. IN PBUSHANDLER BusHandler,
  715. IN PCI_SLOT_NUMBER Slot,
  716. IN PKIRQL Irql,
  717. IN PPCI_TYPE1_CFG_BITS PciCfg1
  718. )
  719. {
  720. UNREFERENCED_PARAMETER( Irql );
  721. //
  722. // Initialize PciCfg1
  723. //
  724. PciCfg1->u.AsULONG = 0;
  725. PciCfg1->u.bits.BusNumber = BusHandler->BusNumber;
  726. PciCfg1->u.bits.DeviceNumber = Slot.u.bits.DeviceNumber;
  727. PciCfg1->u.bits.FunctionNumber = Slot.u.bits.FunctionNumber;
  728. PciCfg1->u.bits.Enable = TRUE;
  729. //
  730. // Synchronize with PCI type1 config space
  731. //
  732. //KeAcquireSpinLock (&HalpPCIConfigLock, Irql);
  733. }
  734. VOID HalpPCIReleaseSynchronzationType1 (
  735. IN PBUSHANDLER BusHandler,
  736. IN KIRQL Irql
  737. )
  738. {
  739. PCI_TYPE1_CFG_BITS PciCfg1;
  740. PPCIPBUSDATA BusData;
  741. UNREFERENCED_PARAMETER( Irql );
  742. //
  743. // Disable PCI configuration space
  744. //
  745. PciCfg1.u.AsULONG = 0;
  746. BusData = (PPCIPBUSDATA) BusHandler->BusData;
  747. WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1.u.AsULONG);
  748. //
  749. // Release spinlock
  750. //
  751. //KeReleaseSpinLock (&HalpPCIConfigLock, Irql);
  752. }
  753. ULONG
  754. HalpPCIReadUcharType1 (
  755. IN PPCIPBUSDATA BusData,
  756. IN PPCI_TYPE1_CFG_BITS PciCfg1,
  757. IN PUCHAR Buffer,
  758. IN ULONG Offset
  759. )
  760. {
  761. ULONG i;
  762. i = Offset % sizeof(ULONG);
  763. PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG);
  764. WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
  765. *Buffer = READ_PORT_UCHAR ((PUCHAR) (BusData->Config.Type1.Data + i));
  766. return sizeof (UCHAR);
  767. }
  768. ULONG
  769. HalpPCIReadUshortType1 (
  770. IN PPCIPBUSDATA BusData,
  771. IN PPCI_TYPE1_CFG_BITS PciCfg1,
  772. IN PUCHAR Buffer,
  773. IN ULONG Offset
  774. )
  775. {
  776. ULONG i;
  777. i = Offset % sizeof(ULONG);
  778. PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG);
  779. WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
  780. *((PUSHORT) Buffer) = READ_PORT_USHORT ((PUSHORT) (BusData->Config.Type1.Data + i));
  781. return sizeof (USHORT);
  782. }
  783. ULONG
  784. HalpPCIReadUlongType1 (
  785. IN PPCIPBUSDATA BusData,
  786. IN PPCI_TYPE1_CFG_BITS PciCfg1,
  787. IN PUCHAR Buffer,
  788. IN ULONG Offset
  789. )
  790. {
  791. PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG);
  792. WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
  793. *((PULONG) Buffer) = READ_PORT_ULONG ((PULONG) BusData->Config.Type1.Data);
  794. return sizeof (ULONG);
  795. }
  796. ULONG
  797. HalpPCIWriteUcharType1 (
  798. IN PPCIPBUSDATA BusData,
  799. IN PPCI_TYPE1_CFG_BITS PciCfg1,
  800. IN PUCHAR Buffer,
  801. IN ULONG Offset
  802. )
  803. {
  804. ULONG i;
  805. i = Offset % sizeof(ULONG);
  806. PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG);
  807. WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
  808. WRITE_PORT_UCHAR ((PUCHAR) (BusData->Config.Type1.Data + i), *Buffer);
  809. return sizeof (UCHAR);
  810. }
  811. ULONG
  812. HalpPCIWriteUshortType1 (
  813. IN PPCIPBUSDATA BusData,
  814. IN PPCI_TYPE1_CFG_BITS PciCfg1,
  815. IN PUCHAR Buffer,
  816. IN ULONG Offset
  817. )
  818. {
  819. ULONG i;
  820. i = Offset % sizeof(ULONG);
  821. PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG);
  822. WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
  823. WRITE_PORT_USHORT ((PUSHORT) (BusData->Config.Type1.Data + i), *((PUSHORT) Buffer));
  824. return sizeof (USHORT);
  825. }
  826. ULONG
  827. HalpPCIWriteUlongType1 (
  828. IN PPCIPBUSDATA BusData,
  829. IN PPCI_TYPE1_CFG_BITS PciCfg1,
  830. IN PUCHAR Buffer,
  831. IN ULONG Offset
  832. )
  833. {
  834. PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG);
  835. WRITE_PORT_ULONG (BusData->Config.Type1.Address, PciCfg1->u.AsULONG);
  836. WRITE_PORT_ULONG ((PULONG) BusData->Config.Type1.Data, *((PULONG) Buffer));
  837. return sizeof (ULONG);
  838. }
  839. VOID HalpPCISynchronizeType2 (
  840. IN PBUSHANDLER BusHandler,
  841. IN PCI_SLOT_NUMBER Slot,
  842. IN PKIRQL Irql,
  843. IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr
  844. )
  845. {
  846. PCI_TYPE2_CSE_BITS PciCfg2Cse;
  847. PPCIPBUSDATA BusData;
  848. UNREFERENCED_PARAMETER( Irql );
  849. BusData = (PPCIPBUSDATA) BusHandler->BusData;
  850. //
  851. // Initialize Cfg2Addr
  852. //
  853. PciCfg2Addr->u.AsUSHORT = 0;
  854. PciCfg2Addr->u.bits.Agent = (USHORT) Slot.u.bits.DeviceNumber;
  855. PciCfg2Addr->u.bits.AddressBase = (USHORT) BusData->Config.Type2.Base;
  856. //
  857. // Synchronize with type2 config space - type2 config space
  858. // remaps 4K of IO space, so we can not allow other I/Os to occur
  859. // while using type2 config space, hence the disable_interrupts.
  860. //
  861. //KeAcquireSpinLock (&HalpPCIConfigLock, Irql);
  862. //DISABLE_INTERRUPTS (); // is not MP safe
  863. PciCfg2Cse.u.AsUCHAR = 0;
  864. PciCfg2Cse.u.bits.Enable = TRUE;
  865. PciCfg2Cse.u.bits.FunctionNumber = (UCHAR) Slot.u.bits.FunctionNumber;
  866. PciCfg2Cse.u.bits.Key = 0xff;
  867. //
  868. // Select bus & enable type 2 configuration space
  869. //
  870. WRITE_PORT_UCHAR (BusData->Config.Type2.Forward, (UCHAR) BusHandler->BusNumber);
  871. WRITE_PORT_UCHAR (BusData->Config.Type2.CSE, PciCfg2Cse.u.AsUCHAR);
  872. }
  873. VOID HalpPCIReleaseSynchronzationType2 (
  874. IN PBUSHANDLER BusHandler,
  875. IN KIRQL Irql
  876. )
  877. {
  878. PCI_TYPE2_CSE_BITS PciCfg2Cse;
  879. PPCIPBUSDATA BusData;
  880. UNREFERENCED_PARAMETER( Irql );
  881. //
  882. // disable PCI configuration space
  883. //
  884. BusData = (PPCIPBUSDATA) BusHandler->BusData;
  885. PciCfg2Cse.u.AsUCHAR = 0;
  886. WRITE_PORT_UCHAR (BusData->Config.Type2.CSE, PciCfg2Cse.u.AsUCHAR);
  887. //
  888. // Restore interrupts, release spinlock
  889. //
  890. //ENABLE_INTERRUPTS ();
  891. //KeReleaseSpinLock (&HalpPCIConfigLock, Irql);
  892. }
  893. ULONG
  894. HalpPCIReadUcharType2 (
  895. IN PPCIPBUSDATA BusData,
  896. IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
  897. IN PUCHAR Buffer,
  898. IN ULONG Offset
  899. )
  900. {
  901. UNREFERENCED_PARAMETER( BusData );
  902. PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
  903. *Buffer = READ_PORT_UCHAR ((PUCHAR) ((ULONG)PciCfg2Addr->u.AsUSHORT));
  904. return sizeof (UCHAR);
  905. }
  906. ULONG
  907. HalpPCIReadUshortType2 (
  908. IN PPCIPBUSDATA BusData,
  909. IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
  910. IN PUCHAR Buffer,
  911. IN ULONG Offset
  912. )
  913. {
  914. USHORT RetVal;
  915. UNREFERENCED_PARAMETER( BusData );
  916. PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
  917. RetVal = READ_PORT_USHORT ((PUSHORT) ((ULONG)PciCfg2Addr->u.AsUSHORT));
  918. *Buffer = TRUNCATE_SIZE_AT_UCHAR_MAX(RetVal);
  919. return sizeof (USHORT);
  920. }
  921. ULONG
  922. HalpPCIReadUlongType2 (
  923. IN PPCIPBUSDATA BusData,
  924. IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
  925. IN PUCHAR Buffer,
  926. IN ULONG Offset
  927. )
  928. {
  929. ULONG RetVal;
  930. UNREFERENCED_PARAMETER( BusData );
  931. PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
  932. RetVal = READ_PORT_ULONG ((PULONG) ((ULONG) PciCfg2Addr->u.AsUSHORT));
  933. *Buffer = TRUNCATE_SIZE_AT_UCHAR_MAX(RetVal);
  934. return sizeof(ULONG);
  935. }
  936. ULONG
  937. HalpPCIWriteUcharType2 (
  938. IN PPCIPBUSDATA BusData,
  939. IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
  940. IN PUCHAR Buffer,
  941. IN ULONG Offset
  942. )
  943. {
  944. UNREFERENCED_PARAMETER( BusData );
  945. PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
  946. WRITE_PORT_UCHAR ((PUCHAR) ((ULONG)PciCfg2Addr->u.AsUSHORT), *Buffer);
  947. return sizeof (UCHAR);
  948. }
  949. ULONG
  950. HalpPCIWriteUshortType2 (
  951. IN PPCIPBUSDATA BusData,
  952. IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
  953. IN PUCHAR Buffer,
  954. IN ULONG Offset
  955. )
  956. {
  957. UNREFERENCED_PARAMETER( BusData );
  958. PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
  959. WRITE_PORT_USHORT ((PUSHORT) ((ULONG)PciCfg2Addr->u.AsUSHORT), *((PUSHORT) Buffer));
  960. return sizeof (USHORT);
  961. }
  962. ULONG
  963. HalpPCIWriteUlongType2 (
  964. IN PPCIPBUSDATA BusData,
  965. IN PPCI_TYPE2_ADDRESS_BITS PciCfg2Addr,
  966. IN PUCHAR Buffer,
  967. IN ULONG Offset
  968. )
  969. {
  970. UNREFERENCED_PARAMETER( BusData );
  971. PciCfg2Addr->u.bits.RegisterNumber = (USHORT) Offset;
  972. WRITE_PORT_ULONG ((PULONG) ((ULONG)PciCfg2Addr->u.AsUSHORT), *((PULONG) Buffer));
  973. return sizeof(ULONG);
  974. }
  975. NTSTATUS
  976. HalpAssignPCISlotResources (
  977. IN ULONG BusNumber,
  978. IN ULONG Slot,
  979. IN OUT PCM_RESOURCE_LIST *pAllocatedResources
  980. )
  981. /*++
  982. Routine Description:
  983. Reads the targeted device to determine it's required resources.
  984. Calls IoAssignResources to allocate them.
  985. Sets the targeted device with it's assigned resoruces
  986. and returns the assignments to the caller.
  987. Arguments:
  988. Return Value:
  989. STATUS_SUCCESS or error
  990. --*/
  991. {
  992. PBUSHANDLER BusHandler;
  993. UCHAR buffer[PCI_COMMON_HDR_LENGTH];
  994. UCHAR buffer2[PCI_COMMON_HDR_LENGTH];
  995. PPCI_COMMON_CONFIG PciData, PciData2;
  996. PCI_SLOT_NUMBER PciSlot;
  997. ULONG i, j, length, type;
  998. PHYSICAL_ADDRESS Address;
  999. PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor;
  1000. static PCM_RESOURCE_LIST CmResList;
  1001. USHORT NewCommand;
  1002. BusHandler = HalpGetPciBusHandler (BusNumber);
  1003. if (!BusHandler) {
  1004. return 0;
  1005. }
  1006. *pAllocatedResources = NULL;
  1007. PciData = (PPCI_COMMON_CONFIG) buffer;
  1008. PciData2 = (PPCI_COMMON_CONFIG) buffer2;
  1009. PciSlot = *((PPCI_SLOT_NUMBER) &Slot);
  1010. BusNumber = BusHandler->BusNumber;
  1011. //
  1012. // Read the PCI device's configuration
  1013. //
  1014. HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH);
  1015. if (PciData->VendorID == PCI_INVALID_VENDORID) {
  1016. return STATUS_NO_SUCH_DEVICE;
  1017. }
  1018. //
  1019. // Make a copy of the device's current settings
  1020. //
  1021. RtlMoveMemory (buffer2, buffer, PCI_COMMON_HDR_LENGTH);
  1022. //
  1023. // Set resources to all bits on to see what type of resources
  1024. // are required.
  1025. //
  1026. for (j=0; j < PCI_TYPE0_ADDRESSES; j++) {
  1027. PciData->u.type0.BaseAddresses[j] = 0xFFFFFFFF;
  1028. }
  1029. PciData->u.type0.ROMBaseAddress = 0xFFFFFFFF;
  1030. NewCommand = PciData->Command;
  1031. PciData->Command &= ~(PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE);
  1032. PciData->u.type0.ROMBaseAddress &= ~PCI_ROMADDRESS_ENABLED;
  1033. HalpWritePCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH);
  1034. HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH);
  1035. HalpPCIPin2Line (BusHandler, RootHandler, PciSlot, PciData);
  1036. //
  1037. // Restore the device's settings in case we don't complete
  1038. //
  1039. HalpWritePCIConfig (BusHandler, PciSlot, buffer2, 0, PCI_COMMON_HDR_LENGTH);
  1040. //
  1041. // Build a CmResource descriptor list for the device
  1042. //
  1043. if (!CmResList) {
  1044. // NtLdr pool is only allocated and never freed. Allocate the
  1045. // buffer once, and from then on just use the buffer over
  1046. CmResList = ExAllocatePool (PagedPool,
  1047. sizeof (CM_RESOURCE_LIST) +
  1048. sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR) * (PCI_TYPE0_ADDRESSES + 2)
  1049. );
  1050. }
  1051. if (!CmResList) {
  1052. return STATUS_NO_MEMORY;
  1053. }
  1054. RtlZeroMemory (CmResList,
  1055. sizeof (CM_RESOURCE_LIST) +
  1056. sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR) * (PCI_TYPE0_ADDRESSES + 2)
  1057. );
  1058. *pAllocatedResources = CmResList;
  1059. CmResList->List[0].InterfaceType = PCIBus;
  1060. CmResList->List[0].BusNumber = BusNumber;
  1061. CmDescriptor = CmResList->List[0].PartialResourceList.PartialDescriptors;
  1062. if (PciData->u.type0.InterruptPin) {
  1063. CmDescriptor->Type = CmResourceTypeInterrupt;
  1064. CmDescriptor->ShareDisposition = CmResourceShareShared;
  1065. CmDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
  1066. // in the loader interrupts aren't actually enabled, so just
  1067. // pass back the untranslated values
  1068. CmDescriptor->u.Interrupt.Level = PciData->u.type0.InterruptLine;
  1069. CmDescriptor->u.Interrupt.Vector = PciData->u.type0.InterruptLine;
  1070. CmDescriptor->u.Interrupt.Affinity = 1;
  1071. CmResList->List[0].PartialResourceList.Count++;
  1072. CmDescriptor++;
  1073. }
  1074. // clear last address index + 1
  1075. PciData->u.type0.BaseAddresses[PCI_TYPE0_ADDRESSES] = 0;
  1076. if (PciData2->u.type0.ROMBaseAddress & PCI_ROMADDRESS_ENABLED) {
  1077. // put rom address in last index+1
  1078. PciData->u.type0.BaseAddresses[PCI_TYPE0_ADDRESSES] =
  1079. PciData->u.type0.ROMBaseAddress & ~PCI_ADDRESS_IO_SPACE;
  1080. PciData2->u.type0.BaseAddresses[PCI_TYPE0_ADDRESSES] =
  1081. PciData2->u.type0.ROMBaseAddress & ~PCI_ADDRESS_IO_SPACE;
  1082. }
  1083. for (j=0; j < PCI_TYPE0_ADDRESSES + 1; j++) {
  1084. if (PciData->u.type0.BaseAddresses[j]) {
  1085. i = PciData->u.type0.BaseAddresses[j];
  1086. //
  1087. // Make sure the appropriate decode is turned on for this BAR.
  1088. //
  1089. if (i & PCI_ADDRESS_IO_SPACE) {
  1090. NewCommand |= PCI_ENABLE_IO_SPACE;
  1091. } else {
  1092. NewCommand |= PCI_ENABLE_MEMORY_SPACE;
  1093. }
  1094. // scan for first set bit, that's the length & alignment
  1095. length = 1 << (i & PCI_ADDRESS_IO_SPACE ? 2 : 4);
  1096. Address.HighPart = 0;
  1097. Address.LowPart = PciData2->u.type0.BaseAddresses[j] & ~(length-1);
  1098. while (!(i & length) && length) {
  1099. length <<= 1;
  1100. }
  1101. // translate bus specific address
  1102. type = (i & PCI_ADDRESS_IO_SPACE) ? 0 : 1;
  1103. if (!HalTranslateBusAddress (
  1104. PCIBus,
  1105. BusNumber,
  1106. Address,
  1107. &type,
  1108. &Address )) {
  1109. // translation failed, skip it
  1110. continue;
  1111. }
  1112. // fill in CmDescriptor to return
  1113. if (type == 0) {
  1114. CmDescriptor->Type = CmResourceTypePort;
  1115. CmDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  1116. CmDescriptor->Flags = CM_RESOURCE_PORT_IO;
  1117. CmDescriptor->u.Port.Length = length;
  1118. CmDescriptor->u.Port.Start = Address;
  1119. } else {
  1120. CmDescriptor->Type = CmResourceTypeMemory;
  1121. CmDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  1122. CmDescriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
  1123. CmDescriptor->u.Memory.Length = length;
  1124. CmDescriptor->u.Memory.Start = Address;
  1125. if (j == PCI_TYPE0_ADDRESSES) {
  1126. // this is a ROM address
  1127. CmDescriptor->Flags = CM_RESOURCE_MEMORY_READ_ONLY;
  1128. }
  1129. }
  1130. CmResList->List[0].PartialResourceList.Count++;
  1131. CmDescriptor++;
  1132. if (i & PCI_TYPE_64BIT) {
  1133. // skip upper half of 64 bit address.
  1134. j++;
  1135. }
  1136. }
  1137. }
  1138. //
  1139. // If any decodes need to be turned on, do this now.
  1140. //
  1141. if (NewCommand != PciData2->Command) {
  1142. HalpWritePCIConfig(BusHandler,
  1143. PciSlot,
  1144. &NewCommand,
  1145. FIELD_OFFSET(PCI_COMMON_CONFIG, Command),
  1146. sizeof(NewCommand));
  1147. }
  1148. return STATUS_SUCCESS;
  1149. }