📄 ezloader.c
字号:
Ezusb_KdPrint (("enter Ezusb_StartDevice\n"));
//
// First download loader firmware. The loader firmware implements a vendor
// specific command that will allow us to anchor load to external ram
//
Ezusb_8051Reset(fdo,1);
Ezusb_DownloadIntelHex(fdo,loader);
Ezusb_8051Reset(fdo,0);
//
// Now download the device firmware
//
Ezusb_DownloadIntelHex(fdo,firmware);
Ezusb_8051Reset(fdo,1);
Ezusb_8051Reset(fdo,0);
Ezusb_KdPrint (("exit Ezusb_StartDevice\n"));
return STATUS_SUCCESS;
}
NTSTATUS
Ezusb_RemoveDevice(
IN PDEVICE_OBJECT fdo
)
/*++
Routine Description:
Removes a given instance of a Ezusb Device device on the USB.
Arguments:
fdo - pointer to the device object for this instance of a Ezusb Device
Return Value:
NT status code
--*/
{
PDEVICE_EXTENSION pdx;
NTSTATUS ntStatus = STATUS_SUCCESS;
Ezusb_KdPrint (("enter Ezusb_RemoveDevice\n"));
pdx = fdo->DeviceExtension;
IoDetachDevice(pdx->StackDeviceObject);
IoDeleteDevice (fdo);
Ezusb_KdPrint (("exit Ezusb_RemoveDevice (%x)\n", ntStatus));
return ntStatus;
}
NTSTATUS
Ezusb_PnPAddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject
)
/*++
Routine Description:
This routine is called to create a new instance of the device
Arguments:
DriverObject - pointer to the driver object for this instance of Ezusb
PhysicalDeviceObject - pointer to a device object created by the bus
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_OBJECT fdo = NULL;
PDEVICE_EXTENSION pdx;
Ezusb_KdPrint(("enter Ezusb_PnPAddDevice\n"));
ntStatus = IoCreateDevice (DriverObject,
sizeof (DEVICE_EXTENSION),
NULL,
FILE_DEVICE_UNKNOWN,
0,
FALSE,
&fdo);
if (NT_SUCCESS(ntStatus))
{
pdx = fdo->DeviceExtension;
//
// Non plug and play drivers usually create the device object in
// driver entry, and the I/O manager autimatically clears this flag.
// Since we are creating the device object ourselves in response to
// a PnP START_DEVICE IRP, we need to clear this flag ourselves.
//
fdo->Flags &= ~DO_DEVICE_INITIALIZING;
//
// This driver uses direct I/O for read/write requests
//
fdo->Flags |= DO_DIRECT_IO;
//
//
// store away the Physical device Object
//
pdx->PhysicalDeviceObject=PhysicalDeviceObject;
//
// Attach to the StackDeviceObject. This is the device object that what we
// use to send Irps and Urbs down the USB software stack
//
pdx->StackDeviceObject =
IoAttachDeviceToDeviceStack(fdo, PhysicalDeviceObject);
ASSERT (pdx->StackDeviceObject != NULL);
pdx->usage = 1; // locked until RemoveDevice
KeInitializeEvent(&pdx->evRemove,
NotificationEvent,
FALSE); // set when use count drops to zero
}
Ezusb_KdPrint(("exit Ezusb_PnPAddDevice (%x)\n", ntStatus));
return ntStatus;
}
NTSTATUS
Ezusb_CallUSBD(
IN PDEVICE_OBJECT fdo,
IN PURB Urb
)
/*++
Routine Description:
Passes a Usb Request Block (URB) to the USB class driver (USBD)
Arguments:
fdo - pointer to the device object for this instance of an Ezusb Device
Urb - pointer to Urb request block
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
NTSTATUS ntStatus, status = STATUS_SUCCESS;
PDEVICE_EXTENSION pdx;
PIRP irp;
KEVENT event;
IO_STATUS_BLOCK ioStatus;
PIO_STACK_LOCATION nextStack;
Ezusb_KdPrint (("enter Ezusb_CallUSBD\n"));
pdx = fdo->DeviceExtension;
// issue a synchronous request (see notes above)
KeInitializeEvent(&event, NotificationEvent, FALSE);
irp = IoBuildDeviceIoControlRequest(
IOCTL_INTERNAL_USB_SUBMIT_URB,
pdx->StackDeviceObject,
NULL,
0,
NULL,
0,
TRUE, /* INTERNAL */
&event,
&ioStatus);
// Prepare for calling the USB driver stack
nextStack = IoGetNextIrpStackLocation(irp);
ASSERT(nextStack != NULL);
// Set up the URB ptr to pass to the USB driver stack
nextStack->Parameters.Others.Argument1 = Urb;
Ezusb_KdPrint (("Calling USB Driver Stack\n"));
//
// Call the USB class driver to perform the operation. If the returned status
// is PENDING, wait for the request to complete.
//
ntStatus = IoCallDriver(pdx->StackDeviceObject,
irp);
Ezusb_KdPrint (("return from IoCallDriver USBD %x\n", ntStatus));
if (ntStatus == STATUS_PENDING)
{
Ezusb_KdPrint (("Wait for single object\n"));
status = KeWaitForSingleObject(
&event,
Suspended,
KernelMode,
FALSE,
NULL);
Ezusb_KdPrint (("Wait for single object, returned %x\n", status));
}
else
{
ioStatus.Status = ntStatus;
}
Ezusb_KdPrint (("URB status = %x status = %x irp status %x\n",
Urb->UrbHeader.Status, status, ioStatus.Status));
ntStatus = ioStatus.Status;
Ezusb_KdPrint(("exit Ezusb_CallUSBD (%x)\n", ntStatus));
return ntStatus;
}
///////////////////////////////////////////////////////////////////////////////
// @func Lock a SIMPLE device object
// @parm Address of our device extension
// @rdesc TRUE if it was possible to lock the device, FALSE otherwise.
// @comm A FALSE return value indicates that we're in the process of deleting
// the device object, so all new requests should be failed
BOOLEAN LockDevice(
IN PDEVICE_OBJECT fdo
)
{
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
// Increment use count on our device object
LONG usage = InterlockedIncrement(&pdx->usage);
// AddDevice initialized the use count to 1, so it ought to be bigger than
// one now. HandleRemoveDevice sets the "removing" flag and decrements the
// use count, possibly to zero. So if we find a use count of "1" now, we
// should also find the "removing" flag set.
ASSERT(usage > 1 || pdx->removing);
// If device is about to be removed, restore the use count and return FALSE.
// If we're in a race with HandleRemoveDevice (maybe running on another CPU),
// the sequence we've followed is guaranteed to avoid a mistaken deletion of
// the device object. If we test "removing" after HandleRemoveDevice sets it,
// we'll restore the use count and return FALSE. In the meantime, if
// HandleRemoveDevice decremented the count to 0 before we did our increment,
// its thread will have set the remove event. Otherwise, we'll decrement to 0
// and set the event. Either way, HandleRemoveDevice will wake up to finish
// removing the device, and we'll return FALSE to our caller.
//
// If, on the other hand, we test "removing" before HandleRemoveDevice sets it,
// we'll have already incremented the use count past 1 and will return TRUE.
// Our caller will eventually call UnlockDevice, which will decrement the use
// count and might set the event HandleRemoveDevice is waiting on at that point.
if (pdx->removing)
{
if (InterlockedDecrement(&pdx->usage) == 0)
KeSetEvent(&pdx->evRemove, 0, FALSE);
return FALSE;
}
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
// @func Unlock a SIMPLE device object
// @parm Address of our device extension
// @comm If the use count drops to zero, set the evRemove event because we're
// about to remove this device object.
void UnlockDevice(
PDEVICE_OBJECT fdo
)
{
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
LONG usage = InterlockedDecrement(&pdx->usage);
ASSERT(usage >= 0);
if (usage == 0)
{ // removing device
ASSERT(pdx->removing); // HandleRemoveDevice should already have set this
KeSetEvent(&pdx->evRemove, 0, FALSE);
} // removing device
}
NTSTATUS Ezusb_8051Reset(
PDEVICE_OBJECT fdo,
UCHAR resetBit
)
/*++
Routine Description:
Uses the ANCHOR LOAD vendor specific command to either set or release the
8051 reset bit in the EZ-USB chip.
Arguments:
fdo - pointer to the device object for this instance of an Ezusb Device
resetBit - 1 sets the 8051 reset bit (holds the 8051 in reset)
0 clears the 8051 reset bit (8051 starts running)
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
NTSTATUS ntStatus;
PURB urb = NULL;
urb = ExAllocatePool(NonPagedPool,
sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
if (urb)
{
// toggle the EZ-USB reset bit (harmless on FX2)
RtlZeroMemory(urb,sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
urb->UrbHeader.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
urb->UrbHeader.Function = URB_FUNCTION_VENDOR_DEVICE;
urb->UrbControlVendorClassRequest.TransferBufferLength = 1;
urb->UrbControlVendorClassRequest.TransferBuffer = &resetBit;
urb->UrbControlVendorClassRequest.TransferBufferMDL = NULL;
urb->UrbControlVendorClassRequest.Request = ANCHOR_LOAD_INTERNAL;
urb->UrbControlVendorClassRequest.Value = CPUCS_REG_EZUSB;
urb->UrbControlVendorClassRequest.Index = 0;
ntStatus = Ezusb_CallUSBD(fdo, urb);
// toggle the FX2 reset bit (harmless on EZ-USB)
RtlZeroMemory(urb,sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
urb->UrbHeader.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
urb->UrbHeader.Function = URB_FUNCTION_VENDOR_DEVICE;
urb->UrbControlVendorClassRequest.TransferBufferLength = 1;
urb->UrbControlVendorClassRequest.TransferBuffer = &resetBit;
urb->UrbControlVendorClassRequest.TransferBufferMDL = NULL;
urb->UrbControlVendorClassRequest.Request = ANCHOR_LOAD_INTERNAL;
urb->UrbControlVendorClassRequest.Value = CPUCS_REG_FX2;
urb->UrbControlVendorClassRequest.Index = 0;
ntStatus = Ezusb_CallUSBD(fdo, urb);
}
else
{
ntStatus = STATUS_NO_MEMORY;
}
if (urb)
ExFreePool(urb);
return ntStatus;
}
NTSTATUS Ezusb_DownloadIntelHex(
PDEVICE_OBJECT fdo,
PINTEL_HEX_RECORD hexRecord
)
/*++
Routine Description:
This function downloads Intel Hex Records to the EZ-USB device. If any of the hex records
are destined for external RAM, then the caller must have previously downloaded firmware
to the device that knows how to download to external RAM (ie. firmware that implements
the ANCHOR_LOAD_EXTERNAL vendor specific command).
Arguments:
fdo - pointer to the device object for this instance of an Ezusb Device
hexRecord - pointer to an array of INTEL_HEX_RECORD structures. This array
is terminated by an Intel Hex End record (Type = 1).
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
NTSTATUS ntStatus;
PURB urb = NULL;
PINTEL_HEX_RECORD ptr = hexRecord;
urb = ExAllocatePool(NonPagedPool,
sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
if (urb)
{
//
// The download must be performed in two passes. The first pass loads all of the
// external addresses, and the 2nd pass loads to all of the internal addresses.
// why? because downloading to the internal addresses will probably wipe out the firmware
// running on the device that knows how to receive external ram downloads.
//
//
// First download all the records that go in external ram
//
while (ptr->Type == 0)
{
if (!INTERNAL_RAM(ptr->Address))
{
RtlZeroMemory(urb,sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
urb->UrbHeader.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
urb->UrbHeader.Function = URB_FUNCTION_VENDOR_DEVICE;
urb->UrbControlVendorClassRequest.TransferBufferLength = ptr->Length;
urb->UrbControlVendorClassRequest.TransferBuffer = ptr->Data;
urb->UrbControlVendorClassRequest.Request = ANCHOR_LOAD_EXTERNAL;
urb->UrbControlVendorClassRequest.Value = ptr->Address;
urb->UrbControlVendorClassRequest.Index = 0;
Ezusb_KdPrint (("Downloading %d bytes to 0x%x\n",ptr->Length,ptr->Address));
ntStatus = Ezusb_CallUSBD(fdo, urb);
if (!NT_SUCCESS(ntStatus))
break;
}
ptr++;
}
//
// Now download all of the records that are in internal RAM. Before starting
// the download, stop the 8051.
//
Ezusb_8051Reset(fdo,1);
ptr = hexRecord;
while (ptr->Type == 0)
{
if (INTERNAL_RAM(ptr->Address))
{
RtlZeroMemory(urb,sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
urb->UrbHeader.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
urb->UrbHeader.Function = URB_FUNCTION_VENDOR_DEVICE;
urb->UrbControlVendorClassRequest.TransferBufferLength = ptr->Length;
urb->UrbControlVendorClassRequest.TransferBuffer = ptr->Data;
urb->UrbControlVendorClassRequest.Request = ANCHOR_LOAD_INTERNAL;
urb->UrbControlVendorClassRequest.Value = ptr->Address;
urb->UrbControlVendorClassRequest.Index = 0;
Ezusb_KdPrint (("Downloading %d bytes to 0x%x\n",ptr->Length,ptr->Address));
ntStatus = Ezusb_CallUSBD(fdo, urb);
if (!NT_SUCCESS(ntStatus))
break;
}
ptr++;
}
}
else
{
ntStatus = STATUS_NO_MEMORY;
}
if (urb)
ExFreePool(urb);
return ntStatus;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -