www.pudn.com > EZUSBµÄFIRMWARE.zip > DriverEntry.cpp


// Main program for LoadEz function driver: EZ-USB auto-loader program, Version 2.0 
// Copyright (C) 2000 by John Hyde, USB Design By Example 
// All rights reserved 
// 
// Derived using Walter Oney's WDM Wizard 
// Copyright (C) 1999, 2000 by Walter Oney 
// All rights reserved.  Used with permission 
// 
// Also uses Walter Oney's Portable FileIO Subsystem 
// Copyright (C) 1999, 2000 by Walter Oney 
// All rights reserved.  Used with permission 
// 
// Please send all comments, suggestions and error reports to John@USB-By-Example.com 
 
/*	Permission is hereby granted to: 
	(1) to merge this program code with other program material to create a derivative work and  
	(2) to republish this program, or any work derived, in whole or in part, therefrom, in compiled 
		object form only. Any other publication of this program, in any form, without the explicit  
		permission of the copyright holders is prohibited. 
*/ 
 
#include "stddcls.h" 
#include "driver.h" 
#include  
#include "guids.h" 
#include "usbdi.h" 
#include "fileIO.h" 
 
NTSTATUS AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT pdo); 
VOID DriverUnload(PDRIVER_OBJECT fdo); 
 
struct INIT_STRUCT : public _GENERIC_INIT_STRUCT {}; 
 
// Need a few global variables 
const WCHAR HexCharacter[] = L"0123456789ABCDEF"; 
BOOLEAN win98 = FALSE; 
 
/////////////////////////////////////////////////////////////////////////////// 
 
#pragma INITCODE 
 
extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) { 
	KdPrint((DRIVERNAME "Version 2.1. (John@USB-By-Example.com)\n")); 
 
// We require GENERIC.SYS 1.3 or later. 
	if (GenericGetVersion() < 0x00010003) { 
		KdPrint((DRIVERNAME "Required version (=>1.3) of GENERIC.SYS not installed\n")); 
		return STATUS_UNSUCCESSFUL; 
		} 
 
// See if we're running under Win98 or NT: 
	win98 = IsWin98(); 
	KdPrint((DRIVERNAME "Running under Windows(R) ")); 
	if (win98) KdPrint (("98\n")); else KdPrint(("NT\n")); 
 
// Initialize function pointers.  LoadEz only needs four 
	DriverObject->DriverUnload = DriverUnload; 
	DriverObject->DriverExtension->AddDevice = AddDevice; 
	DriverObject->MajorFunction[IRP_MJ_POWER] = DispatchPower; 
	DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp; 
	 
	return STATUS_SUCCESS; 
	} 
 
 
#pragma PAGEDCODE 
 
VOID DriverUnload(PDRIVER_OBJECT DriverObject) { 
	PAGED_CODE(); 
	KdPrint((DRIVERNAME "Unloading Driver\n")); 
	} 
 
/////////////////////////////////////////////////////////////////////////////// 
 
NTSTATUS AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT pdo) { 
	PAGED_CODE(); 
	KdPrint((DRIVERNAME "Adding Device\n")); 
	NTSTATUS status; 
 
// Create a functional device object to represent the hardware we're managing. 
	PDEVICE_OBJECT fdo; 
	ULONG dxsize = (sizeof(DEVICE_EXTENSION) + 7) & ~7; 
	ULONG xsize = dxsize + GetSizeofGenericExtension(); 
	status = IoCreateDevice(DriverObject, xsize, NULL, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &fdo); 
	if (!NT_SUCCESS(status)) { 
		KdPrint((DRIVERNAME "IoCreateDevice failed with status %X\n", status)); 
		return status; 
		} 
	KdPrint((DRIVERNAME "Device Object (%8.8x) created\n", fdo)); 
 
	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension; 
	BOOLEAN ginit = FALSE; 
 
// From this point forward, any error will have side effects that need to be cleaned up.  
// Using a try-finally block allows easy modification without losing track of the side effects. 
	__try 
		{						// finish initialization 
		pdx->DeviceObject = fdo; 
		pdx->Pdo = pdo; 
 
// Link our device object into the stack leading to the PDO 
		pdx->LowerDeviceObject = IoAttachDeviceToDeviceStack(fdo, pdo); 
		if (!pdx->LowerDeviceObject) { 
			KdPrint((DRIVERNAME "IoAttachDeviceToDeviceStack failed\n")); 
			status = STATUS_DEVICE_REMOVED; 
			__leave; 
			}						// can't attach device 
 
// Set power management flags in the device object 
		fdo->Flags |= DO_POWER_PAGABLE; 
 
// Initialize to use the GENERIC.SYS library 
		pdx->pgx = (PGENERIC_EXTENSION) ((PUCHAR) pdx + dxsize); 
		INIT_STRUCT gis; 
		RtlZeroMemory(&gis, sizeof(gis)); 
		gis.Size = sizeof(gis); 
		gis.DeviceObject = fdo; 
		gis.Pdo = pdo; 
		gis.Ldo = pdx->LowerDeviceObject; 
		gis.RemoveLock = &pdx->RemoveLock; 
		gis.StartDevice = StartDevice; 
		gis.StopDevice = StopDevice; 
		gis.RemoveDevice = RemoveDevice; 
		RtlInitUnicodeString(&gis.DebugName, LDRIVERNAME); 
 
		status = InitializeGenericExtension(pdx->pgx, &gis); 
		if (!NT_SUCCESS(status)) { 
			KdPrint((DRIVERNAME "InitializeGenericExtension failed with status %X\n", status)); 
			__leave; 
			} 
		ginit = TRUE; 
		GenericRegisterInterface(pdx->pgx, &GUID_INTERFACE_LOADEZ); 
 
// Clear the "initializing" flag so that we can get IRPs 
		fdo->Flags &= ~DO_DEVICE_INITIALIZING; 
		}							// finish initialization 
	__finally 
		{							// cleanup side effects 
		if (!NT_SUCCESS(status)) {	// need to cleanup 
			if (ginit) CleanupGenericExtension(pdx->pgx); 
			if (pdx->LowerDeviceObject) IoDetachDevice(pdx->LowerDeviceObject); 
			IoDeleteDevice(fdo); 
			} 
		} 
	return status; 
	} 
 
VOID RemoveDevice(IN PDEVICE_OBJECT fdo) { 
	PAGED_CODE(); 
	KdPrint((DRIVERNAME "Removing Device (%8.8x)\n", fdo)); 
	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension; 
	NTSTATUS status; 
	if (pdx->LowerDeviceObject) IoDetachDevice(pdx->LowerDeviceObject); 
	if (pdx->HexFileBuffer) ExFreePool(pdx->HexFileBuffer);  
	IoDeleteDevice(fdo); 
	} 
 
/////////////////////////////////////////////////////////////////////////////// 
// Plug-and-Play and Power Management is handled, for the most part, by GENERIC.SYS 
 
NTSTATUS DispatchPnp(PDEVICE_OBJECT fdo, PIRP Irp) { 
	PAGED_CODE(); 
	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension; 
	return GenericDispatchPnp(pdx->pgx, Irp); 
	} 
 
NTSTATUS DispatchPower(PDEVICE_OBJECT fdo, PIRP Irp) { 
	PAGED_CODE(); 
	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension; 
	return GenericDispatchPower(pdx->pgx, Irp); 
	} 
 
/////////////////////////////////////////////////////////////////////////////// 
// Declare the support functions 
 
NTSTATUS SendUrbAndWait(PDEVICE_OBJECT fdo, PURB Urb) { 
	PAGED_CODE(); 
	KEVENT Event; 
	IO_STATUS_BLOCK ioStatus; 
	NTSTATUS Status = STATUS_SUCCESS; 
	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension; 
	KeInitializeEvent(&Event, NotificationEvent, FALSE); 
	PIRP Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_SUBMIT_URB, 
		pdx->LowerDeviceObject, NULL, 0, NULL, 0, TRUE, &Event, &ioStatus); 
	PIO_STACK_LOCATION Stack = IoGetNextIrpStackLocation(Irp); 
	Stack->Parameters.Others.Argument1 = (PVOID) Urb; 
	Status = IoCallDriver(pdx->LowerDeviceObject, Irp); 
	if (Status == STATUS_PENDING) { 
		KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 
		Status = ioStatus.Status; 
		} 
	return Status; 
	} 
 
NTSTATUS GetIdentity(PDEVICE_OBJECT fdo) { 
	PAGED_CODE(); 
// Need to discover the VID and PID currently in use 
	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension; 
	USB_DEVICE_DESCRIPTOR Descriptor; 
	NTSTATUS Status; 
	URB LocalUrb; 
	PURB Urb = &LocalUrb; 
	RtlZeroMemory(Urb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST)); 
	Urb->UrbHeader.Length = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST); 
	Urb->UrbHeader.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE; 
	Urb->UrbControlDescriptorRequest.TransferBufferLength = sizeof(Descriptor); 
	Urb->UrbControlDescriptorRequest.TransferBuffer = &Descriptor; 
	Urb->UrbControlDescriptorRequest.TransferBufferMDL = NULL; 
	Urb->UrbControlDescriptorRequest.DescriptorType = 1; 
	Status = SendUrbAndWait(fdo, Urb); 
	pdx->VID = Descriptor.idVendor; 
	pdx->PID = Descriptor.idProduct; 
	KdPrint((DRIVERNAME "Current VID = %4.4x and PID = %4.4x\n", pdx->VID, pdx->PID));  
	return Status; 
	} 
 
NTSTATUS SetEZUSBMemory(PDEVICE_OBJECT fdo, USHORT StartLocation, USHORT Length, PVOID DataBytes) { 
	PAGED_CODE(); 
// Need to build a Vendor Request and send it to the development board 
	URB LocalUrb; 
	PURB Urb = &LocalUrb; 
	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.TransferFlags = USBD_TRANSFER_DIRECTION_OUT; 
	Urb->UrbControlVendorClassRequest.TransferBufferLength = Length; 
	Urb->UrbControlVendorClassRequest.TransferBuffer = DataBytes; 
	Urb->UrbControlVendorClassRequest.TransferBufferMDL = NULL; 
	Urb->UrbControlVendorClassRequest.Request = 0x0A0; // "Anchor Load" 
	Urb->UrbControlVendorClassRequest.Value = StartLocation;	 
	return SendUrbAndWait(fdo, Urb); 
	} 
 
NTSTATUS EZUSB_Reset(PDEVICE_OBJECT fdo, UCHAR ResetBit) { 
	PAGED_CODE(); 
// EZUSB_Reset is a special case of SetEZUSBMemory 
	return SetEZUSBMemory(fdo, 0x07F92, 1, &ResetBit); 
	} 
 
NTSTATUS GetFirmware(PDEVICE_OBJECT fdo) { 
	PAGED_CODE(); 
// Open the Firmware file and load it into a local buffer 
// First create the name of the file that we need to open 
	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension; 
	NTSTATUS Status; 
	Status = GetIdentity(fdo); 
	if (Status != STATUS_SUCCESS) { 
		KdPrint((DRIVERNAME "Could not get VID and PID from IO device\n")); 
		return Status; 
		} 
// Create a filename from the current VID and PID	 
	WCHAR Filename[] = L"\\SystemRoot\\system32\\drivers\\vvvvpppp.hex"; 
	Filename[29] = HexCharacter[(pdx->VID >> 12) & 0x0F]; 
	Filename[30] = HexCharacter[(pdx->VID >> 8) & 0x0F]; 
	Filename[31] = HexCharacter[(pdx->VID >> 4) & 0x0F]; 
	Filename[32] = HexCharacter[pdx->VID & 0x0F]; 
	Filename[33] = HexCharacter[(pdx->PID >> 12) & 0x0F]; 
	Filename[34] = HexCharacter[(pdx->PID >> 8) & 0x0F]; 
	Filename[35] = HexCharacter[(pdx->PID >> 4) & 0x0F]; 
	Filename[36] = HexCharacter[pdx->PID & 0x0F]; 
// Need to use Walter Oney's portable file subsystem here since this driver may be running before 
// the file system is running 
	HANDLE FileHandle; 
	Status = OpenFile(Filename, TRUE, &FileHandle); 
	KdPrint((DRIVERNAME "OpenFile returned with status = %8.8x\n", Status)); 
	if (!NT_SUCCESS(Status)) return Status; 
	 
	pdx->HexFileLength = (ULONG) GetFileSize(FileHandle); 
	pdx->HexFileBuffer = (PCHAR) ExAllocatePool(NonPagedPool, pdx->HexFileLength); 
	if (!pdx->HexFileBuffer) return STATUS_NO_MEMORY; 
	ULONG BytesReturned; 
	Status = ReadFile(FileHandle, pdx->HexFileBuffer, pdx->HexFileLength, &BytesReturned); 
	if (!NT_SUCCESS(Status)) KdPrint((DRIVERNAME "ReadFile failed with status = %8.8x\n", Status)); 
	else KdPrint((DRIVERNAME "ReadFile returned %d bytes\n", BytesReturned)); 
	CloseFile(FileHandle); 
	return Status; 
	} 
 
bool GetNextCharacter(PDEVICE_OBJECT fdo, PCHAR BufferPtr) { 
	PAGED_CODE(); 
	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension; 
	*BufferPtr = pdx->HexFileBuffer[pdx->ByteOffset]; 
	if (pdx->ByteOffset++ < pdx->HexFileLength) return true; 
	return false; 
	} 
 
bool GetNextLine(PDEVICE_OBJECT fdo, PCHAR BufferPtr) { 
	PAGED_CODE(); 
// Get the next line from the input file, return FALSE if EOF 
// First find the ':' 
	do { if (!GetNextCharacter(fdo, BufferPtr)) return false; } while (*BufferPtr != ':'); 
// Then read until the end of the line 
	do { if (!GetNextCharacter(fdo, ++BufferPtr)) return false; } while (*BufferPtr != 10); // EOL 
	return true; 
	} 
 
SHORT value(char Entry) { 
	PAGED_CODE(); 
	for (SHORT i = 0; iDeviceExtension; 
	KdPrint((DRIVERNAME "Starting IO device\n")); 
// Starting the device involves downloading firmware into the EZ-USB component 
 
// Open the HEX file and read it into a local buffer 
	NTSTATUS Status = GetFirmware(fdo); 
	if (Status != STATUS_SUCCESS) { 
		KdPrint((DRIVERNAME "Could not get device firmware (%8.8x)\n", Status)); 
		return Status; 
		} 
 
// Loading is done in two passes since AnchorLoad only operates on internal memory addresses 
// Load external memory first using a helper "mover" program 
// First ensure that the EZ-USB 8051 is RESET before downloading 
	Status = EZUSB_Reset(fdo, 1); 
	if (Status != STATUS_SUCCESS) return Status; 
// Since we are still here (previous line did not return) no need to check this Status further 
 
	UCHAR MoverCode[] = 	// 8051 Object code for the Mover program 
		{0x90, 0x7F, 0x9E, 0x74, 0x0C0, 0x0F0, 0x90, 0x7F, 0x95, 0x0F0, 0x75, 0x92, 0,  
		0x78, 0x24, 0x0E2, 0x60, 0x10, 0x0FF, 8, 0x0E2, 0xF5, 0x83, 8, 0x0E2, 0x0F5, 0x82, 
		8, 8, 0x0E2, 0x0F0, 0x0A3, 0x0DF, 0x0FA, 0x80, 0x0FE, 0x0F, 0x0FF, 0x0F0, 0, 0x4D, 
		0x6F, 0x76, 0x65, 0x72, 0x20, 0x49, 0x6E, 0x73, 0x74, 0x61, 0x6C, 0x6C, 0x65, 0x64}; 
	SetEZUSBMemory(fdo, 0, sizeof(MoverCode), MoverCode); 
	EZUSB_Reset(fdo, 0); // unRESET the EZUSB CPU so that it executes this code 
 
	UCHAR Record[40]; 
	char Buffer[80]; 
	int Pass, i; 
	for (Pass = 1; Pass<3; Pass++) { 
		pdx->ByteOffset = 0;	// Start at the beginning of the Hex data file 
		EZUSB_Reset(fdo, 1);	// Stop the EZUSB CPU 
		USHORT ByteCount, LoadAddress, RecordType; 
// Read the HEX records one at a time and load them onto the development board 
		while (GetNextLine(fdo, Buffer)) { 
			ByteCount = Record[0] = (value(Buffer[1]) << 4) + value(Buffer[2]); 
			for (i = 1; i 0x1FFF)) { 
//					KdPrint((DRIVERNAME "Loading %2.2xH bytes at upper address %4.4xH\n", ByteCount, LoadAddress)); 
					SetEZUSBMemory(fdo, 0x24, ByteCount+4, Record); 
					EZUSB_Reset(fdo, 0);	// unRESET EZUSB CPU so that it will move the data 
					EZUSB_Reset(fdo, 1);	// Stop the EZUSB CPU again 
					} 
				if ((Pass == 2) && (LoadAddress + ByteCount) < 0x1B3F) { 
//					KdPrint((DRIVERNAME "Loading %2.2xH bytes at lower address %4.4xH\n", ByteCount, LoadAddress)); 
					SetEZUSBMemory(fdo, LoadAddress, ByteCount, &Record[4]); 
					} 
				} 
			} 
		} 
// All done, allow the EZ-USB CPU to 'renumerate' 
	KdPrint((DRIVERNAME "Firmware downloaded!\n")); 
	EZUSB_Reset(fdo, 0); 
// Interesting philosophical point - the original device that caused this driver to run no longer  
// exists, since the driver has downloaded it with a new identity.  
// It would be preferrable to return UNSUCCESSFUL so the OS will mark us STOPPED. (this also prevents "Surprize Removal" messages on Win2K) 
// However, the USDB.SYS driver will Suspend our I/O device if we do.  So return SUCCESS 
	return STATUS_SUCCESS; 
	} 
 
 
VOID StopDevice(IN PDEVICE_OBJECT fdo, BOOLEAN oktouch /* = FALSE */) { 
	PAGED_CODE(); 
	KdPrint((DRIVERNAME "Device Stopped\n")); 
	} 
 
/////////////////////////////////////////////////////////////////////////////// 
 
#pragma LOCKEDCODE 
 
extern "C" void __declspec(naked) __cdecl _chkesp() { 
	_asm je okay 
	ASSERT(!DRIVERNAME "Stack pointer mismatch!"); 
okay: 
	_asm ret 
	}