/*++ Copyright (c) 1999 Microsoft Corporation Module Name: cmnbuf.c Abstract: Code to manage common buffer -- hardware addressable memory a common buffer block looks like this start ------------ <- address returned from the hal padding ------------ <- address returned to the miniport mp data ------------ <- ptr to header header end ------------ Environment: kernel mode only Notes: Revision History: 6-20-99 : created --*/ #include "common.h" // paged functions #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, USBPORT_HalAllocateCommonBuffer) #endif // non paged functions PUSBPORT_COMMON_BUFFER USBPORT_HalAllocateCommonBuffer( PDEVICE_OBJECT FdoDeviceObject, ULONG NumberOfBytes ) /*++ Routine Description: Allocates common buffer directly from the hal. The common buffer is passed to the miniport, we always allocate a multiple of PAGE_SIZE so the always starts on a page_boundry. This ensures proper alignement of the TDs used by the miniport Arguments: DeviceObject - DeviceObject of the controller to stop Return Value: returns Virtual Address of common buffer or NULL if unsuccessful. --*/ { PDEVICE_EXTENSION devExt; PUSBPORT_COMMON_BUFFER header; PUCHAR virtualAddress, mpBuffer, baseVa; PHYSICAL_ADDRESS logicalAddress; ULONG headerLength; ULONG n, basePhys, mpBufferPhys, pageCount, extra; PAGED_CODE(); LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS, 'acm>', 0, 0, NumberOfBytes); GET_DEVICE_EXT(devExt, FdoDeviceObject); ASSERT_FDOEXT(devExt); // NULL initialize the return value in case the allocation fails // header = NULL; headerLength = sizeof(USBPORT_COMMON_BUFFER); // compute number min of pages we will need to satisfy // the request n = NumberOfBytes+headerLength; pageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(0, n); #if DBG { ULONG pc; // compute number of pages we will need pc = n / PAGE_SIZE; if ((n % PAGE_SIZE)) { pc++; } USBPORT_ASSERT(pc == pageCount); } #endif extra = (pageCount*PAGE_SIZE)-n; n = (pageCount*PAGE_SIZE); USBPORT_KdPrint((1,"'ALLOC(%d) extra %d bytes\n", n, extra)); virtualAddress = HalAllocateCommonBuffer(devExt->Fdo.AdapterObject, n, &logicalAddress, TRUE); #if DBG if (virtualAddress == NULL) { USBPORT_KdPrint((0,"'HalAllocateCommonBuffer failed\n")); USBPORT_KdPrint((0,"'alloced bytes %d\n")); DEBUG_BREAK(); } #endif if (virtualAddress != NULL) { devExt->Fdo.StatCommonBufferBytes += n; basePhys = logicalAddress.LowPart & ~(PAGE_SIZE-1); baseVa = PAGE_ALIGN(virtualAddress); // hal should have given us a page aligned address since // we asked for a multiple of PAGE_SIZE, // i trust NT but not Win9x USBPORT_ASSERT(virtualAddress == baseVa); // client ptrs mpBuffer = baseVa; mpBufferPhys = basePhys; header = (PUSBPORT_COMMON_BUFFER) (mpBuffer+NumberOfBytes+extra); USBPORT_ASSERT(n == NumberOfBytes+extra+headerLength); // USB controllers only support 32 bit phys addresses // for control structures USBPORT_ASSERT(logicalAddress.HighPart == 0); #if DBG RtlFillMemory(virtualAddress, n, 'x'); #endif // init the header header->Sig = SIG_CMNBUF; header->Flags = 0; header->TotalLength = n; header->LogicalAddress = logicalAddress; header->VirtualAddress = virtualAddress; header->BaseVa = baseVa; header->BasePhys = basePhys; header->MiniportLength = NumberOfBytes+extra; header->MiniportVa = mpBuffer; header->MiniportPhys = mpBufferPhys; // zero the client part RtlZeroMemory(header->MiniportVa, header->MiniportLength); } LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS, 'acm<', mpBuffer, mpBufferPhys, header); return header; } VOID USBPORT_HalFreeCommonBuffer( PDEVICE_OBJECT FdoDeviceObject, PUSBPORT_COMMON_BUFFER CommonBuffer ) /*++ Routine Description: Free a common buffer for the miniport Arguments: Return Value: returns Virtual Address of common buffer or NULL if unsuccessful. --*/ { PDEVICE_EXTENSION devExt; GET_DEVICE_EXT(devExt, FdoDeviceObject); ASSERT_FDOEXT(devExt); USBPORT_ASSERT(CommonBuffer != NULL); ASSERT_COMMON_BUFFER(CommonBuffer); LOGENTRY(NULL, FdoDeviceObject, LOG_XFERS, 'hFCB', CommonBuffer, CommonBuffer->TotalLength, CommonBuffer->MiniportVa); devExt->Fdo.StatCommonBufferBytes -= CommonBuffer->TotalLength; HalFreeCommonBuffer(devExt->Fdo.AdapterObject, CommonBuffer->TotalLength, CommonBuffer->LogicalAddress, CommonBuffer->MiniportVa, TRUE); } PUCHAR USBPORTSVC_MapHwPhysicalToVirtual( HW_32BIT_PHYSICAL_ADDRESS HwPhysicalAddress, PDEVICE_DATA DeviceData, PENDPOINT_DATA EndpointData ) /*++ Routine Description: given a physical address return the corresponding virtual address. Arguments: if the phys address is associated with an endpoint the endpoint is passed in. Return Value: Virtual Address, NULL if not found --*/ { PDEVICE_EXTENSION devExt; PUCHAR virtualAddress; PHCD_ENDPOINT endpoint; ULONG offset; PDEVICE_OBJECT fdoDeviceObject; DEVEXT_FROM_DEVDATA(devExt, DeviceData); ASSERT_FDOEXT(devExt); fdoDeviceObject = devExt->HcFdoDeviceObject; LOGENTRY(NULL, fdoDeviceObject, LOG_XFERS, 'mapP', HwPhysicalAddress, 0, EndpointData); if (EndpointData == NULL) { TEST_TRAP(); } else { PUSBPORT_COMMON_BUFFER cb; ENDPOINT_FROM_EPDATA(endpoint, EndpointData); ASSERT_ENDPOINT(endpoint); cb = endpoint->CommonBuffer; // mask off base physical address offset = HwPhysicalAddress - cb->BasePhys; virtualAddress = cb->BaseVa+offset; LOGENTRY(NULL, fdoDeviceObject, LOG_XFERS, 'mpPV', HwPhysicalAddress, offset, cb->BaseVa); USBPORT_ASSERT(HwPhysicalAddress >= cb->BasePhys && HwPhysicalAddress < cb->BasePhys+cb->MiniportLength); LOGENTRY(NULL, fdoDeviceObject, LOG_XFERS, 'mapV', HwPhysicalAddress, 0, virtualAddress); return virtualAddress; } // probably a bug in the miniport DEBUG_BREAK(); return NULL; }