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.
337 lines
9.0 KiB
337 lines
9.0 KiB
/*++
|
|
|
|
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;
|
|
}
|
|
|
|
|