/*++ Copyright (c) 1999, 2000 Microsoft Corporation Module Name: async.c Abstract: miniport transfer code for sstool (single step tool) interface Environment: kernel mode only Notes: THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. Copyright (c) 1999, 2000 Microsoft Corporation. All Rights Reserved. Revision History: 1-1-00 : created, jdunn --*/ #include "common.h" typedef struct _SS_PACKET_CONTEXT { MP_HW_POINTER Qh; MP_HW_POINTER Td; MP_HW_POINTER Data; ULONG padTo8[2]; } SS_PACKET_CONTEXT, *PSS_PACKET_CONTEXT; #define EHCI_TEST_TD_ALIGNMENT 256 C_ASSERT((sizeof(SS_PACKET_CONTEXT) <= EHCI_TEST_TD_ALIGNMENT)); C_ASSERT((sizeof(HCD_QUEUEHEAD_DESCRIPTOR) <= EHCI_TEST_TD_ALIGNMENT)); C_ASSERT((sizeof(HCD_TRANSFER_DESCRIPTOR) <= EHCI_TEST_TD_ALIGNMENT)); //implements the following miniport functions: //non paged //EHCI_StartSendOnePacket //EHCI_EndSendOnePacket USB_MINIPORT_STATUS USBMPFN EHCI_StartSendOnePacket( PDEVICE_DATA DeviceData, PMP_PACKET_PARAMETERS PacketParameters, PUCHAR PacketData, PULONG PacketLength, PUCHAR WorkspaceVirtualAddress, HW_32BIT_PHYSICAL_ADDRESS WorkspacePhysicalAddress, ULONG WorkSpaceLength, OUT USBD_STATUS *UsbdStatus ) /*++ Routine Description: insert structures to transmit a single packet -- this is for debug tool purposes only so we can be a little creative here. Arguments: Return Value: --*/ { PHC_OPERATIONAL_REGISTER hcOp; PHCD_QUEUEHEAD_DESCRIPTOR qh; PHCD_TRANSFER_DESCRIPTOR td; PUCHAR pch, data; PSS_PACKET_CONTEXT context; HW_LINK_POINTER hwQh, tdLink; ULONG phys, qhPhys, tdPhys, dataPhys, i; ULONG siz; hcOp = DeviceData->OperationalRegisters; // allocate an TD from the scratch space and // initialize it phys = WorkspacePhysicalAddress; pch = WorkspaceVirtualAddress; LOGENTRY(DeviceData, G, '_ssS', phys, 0, pch); // specify a TD alignment to work around HW bugs. siz = EHCI_TEST_TD_ALIGNMENT; context = (PSS_PACKET_CONTEXT) pch; pch += siz; phys += siz; // carve out a qh qhPhys = phys; qh = (PHCD_QUEUEHEAD_DESCRIPTOR) pch; pch += siz; phys += siz; LOGENTRY(DeviceData, G, '_ssQ', qh, 0, qhPhys); // carve out a TD tdPhys = phys; td = (PHCD_TRANSFER_DESCRIPTOR) pch; pch += siz; phys += siz; LOGENTRY(DeviceData, G, '_ssT', td, 0, tdPhys); // use the rest for data LOGENTRY(DeviceData, G, '_ssD', PacketData, *PacketLength, 0); dataPhys = phys; data = pch; RtlCopyMemory(data, PacketData, *PacketLength); pch+=*PacketLength; phys+=*PacketLength; // init qh RtlZeroMemory(qh, sizeof(*qh)); qh->PhysicalAddress = qhPhys; ENDPOINT_DATA_PTR(qh->EndpointData) = NULL; qh->Sig = SIG_HCD_DQH; hwQh.HwAddress = qh->PhysicalAddress; SET_QH(hwQh.HwAddress); //qh->HwQH.EpChars.HeadOfReclimationList = 1; // manual Toggle qh->HwQH.EpChars.DataToggleControl = HcEPCHAR_Toggle_From_qTD; // init the hw descriptor qh->HwQH.EpChars.DeviceAddress = PacketParameters->DeviceAddress; qh->HwQH.EpChars.EndpointNumber = PacketParameters->EndpointAddress; qh->HwQH.EpCaps.HighBWPipeMultiplier = 1; qh->HwQH.EpCaps.HubAddress = 0; qh->HwQH.EpCaps.PortNumber = 0; // link back to ourselves //qh->HwQH.HLink.HwAddress = hwQh.HwAddress; switch (PacketParameters->Speed) { case ss_Low: qh->HwQH.EpChars.EndpointSpeed = HcEPCHAR_LowSpeed; qh->HwQH.EpCaps.HubAddress = PacketParameters->HubDeviceAddress; qh->HwQH.EpCaps.PortNumber = PacketParameters->PortTTNumber; break; case ss_Full: qh->HwQH.EpChars.EndpointSpeed = HcEPCHAR_FullSpeed; qh->HwQH.EpCaps.HubAddress = PacketParameters->HubDeviceAddress; qh->HwQH.EpCaps.PortNumber = PacketParameters->PortTTNumber; break; case ss_High: qh->HwQH.EpChars.EndpointSpeed = HcEPCHAR_HighSpeed; break; default: USBPORT_BUGCHECK(DeviceData); } // jdxxx //qh->HwQH.EpChars.EndpointSpeed = HcEPCHAR_HighSpeed; qh->HwQH.EpChars.MaximumPacketLength = PacketParameters->MaximumPacketSize; // init td RtlZeroMemory(td, sizeof(*td)); for (i=0; i<5; i++) { td->HwTD.BufferPage[i].ul = 0x0badf000; } td->PhysicalAddress = tdPhys; td->Sig = SIG_HCD_TD; switch(PacketParameters->Type) { case ss_Setup: LOGENTRY(DeviceData, G, '_sSU', 0, 0, 0); td->HwTD.Token.Pid = HcTOK_Setup; break; case ss_In: LOGENTRY(DeviceData, G, '_ssI', 0, 0, 0); td->HwTD.Token.Pid = HcTOK_In; break; case ss_Out: td->HwTD.Token.Pid = HcTOK_Out; LOGENTRY(DeviceData, G, '_ssO', 0, 0, 0); break; case ss_Iso_In: break; case ss_Iso_Out: break; } switch(PacketParameters->Toggle) { case ss_Toggle0: td->HwTD.Token.DataToggle = HcTOK_Toggle0; break; case ss_Toggle1: td->HwTD.Token.DataToggle = HcTOK_Toggle1; break; } // prime the overlay with td so that this td // becomes the current td. qh->HwQH.Overlay.qTD.Next_qTD.HwAddress = td->PhysicalAddress; td->HwTD.Token.Active = 1; td->HwTD.Token.ErrorCounter = PacketParameters->ErrorCount; // point TD at the data td->HwTD.BufferPage[0].ul = dataPhys; td->HwTD.Token.BytesToTransfer = *PacketLength; tdLink.HwAddress = 0; SET_T_BIT(tdLink.HwAddress); td->HwTD.Next_qTD.HwAddress = tdLink.HwAddress; td->HwTD.AltNext_qTD.HwAddress = tdLink.HwAddress; QH_DESCRIPTOR_PTR(context->Qh) = qh; TRANSFER_DESCRIPTOR_PTR(context->Td) = td; HW_PTR(context->Data) = data; *UsbdStatus = USBD_STATUS_SUCCESS; // stick the QH in the schedule and wait for it to complete // swap the async qh, wait one frame then // replace the old value. // NOTE: This will interrupt normal bus operation for one ms //WRITE_REGISTER_ULONG(&hcOp->AsyncListAddr, hwQh.HwAddress); EHCI_InsertQueueHeadInAsyncList(DeviceData, qh); EHCI_EnableAsyncList(DeviceData); return USBMP_STATUS_SUCCESS; } USB_MINIPORT_STATUS USBMPFN EHCI_EndSendOnePacket( PDEVICE_DATA DeviceData, PMP_PACKET_PARAMETERS PacketParameters, PUCHAR PacketData, PULONG PacketLength, PUCHAR WorkspaceVirtualAddress, HW_32BIT_PHYSICAL_ADDRESS WorkspacePhysicalAddress, ULONG WorkSpaceLength, OUT USBD_STATUS *UsbdStatus ) /*++ Routine Description: Arguments: Return Value: --*/ { PHC_OPERATIONAL_REGISTER hcOp; PUCHAR pch; PSS_PACKET_CONTEXT context; HW_LINK_POINTER asyncHwQh; PHCD_QUEUEHEAD_DESCRIPTOR qh; PHCD_TRANSFER_DESCRIPTOR td; PUCHAR data; LOGENTRY(DeviceData, G, '_ssE', 0, 0, 0); hcOp = DeviceData->OperationalRegisters; context = (PSS_PACKET_CONTEXT) WorkspaceVirtualAddress; qh = QH_DESCRIPTOR_PTR(context->Qh); td = TRANSFER_DESCRIPTOR_PTR(context->Td); data = HW_PTR(context->Data); LOGENTRY(DeviceData, G, '_sE2', qh, td, *PacketLength ); asyncHwQh.HwAddress = DeviceData->AsyncQueueHead->PhysicalAddress; SET_QH(asyncHwQh.HwAddress); *PacketLength = *PacketLength - td->HwTD.Token.BytesToTransfer; LOGENTRY(DeviceData, G, '_sE3', td->HwTD.Token.BytesToTransfer, td, *PacketLength ); RtlCopyMemory(PacketData, data, *PacketLength); EHCI_DisableAsyncList(DeviceData); EHCI_RemoveQueueHeadFromAsyncList(DeviceData, qh); // WRITE_REGISTER_ULONG(&hcOp->AsyncListAddr, asyncHwQh.HwAddress); // return the error here *UsbdStatus = USBD_STATUS_SUCCESS; if (td->HwTD.Token.Halted == 1) { if (td->HwTD.Token.XactErr) { *UsbdStatus = USBD_STATUS_XACT_ERROR; } else if (td->HwTD.Token.BabbleDetected) { *UsbdStatus = USBD_STATUS_BABBLE_DETECTED; } else if (td->HwTD.Token.DataBufferError) { *UsbdStatus = USBD_STATUS_DATA_BUFFER_ERROR; } else { *UsbdStatus = USBD_STATUS_STALL_PID; } } EHCI_KdPrint((DeviceData, 1, "'Status.XactErr %d\n", td->HwTD.Token.XactErr)); EHCI_KdPrint((DeviceData, 1, "'Status.BabbleDetected %d\n", td->HwTD.Token.BabbleDetected)); EHCI_KdPrint((DeviceData, 1, "'Status.DataBufferError %d\n", td->HwTD.Token.DataBufferError)); return USBMP_STATUS_SUCCESS; }