Ejemplo n.º 1
0
int main(int argc, char ** argv) { 
  libusb_context * ctx = NULL;
  libusb_device_handle * dev = NULL;

  setup_libusb(&ctx, &dev);

  ///
  if (!InitGSCommsNoisy(dev, RETRIES, 1)) {
    fprintf(stderr, "init failed\n");
    exit(-1);
  }

  // check for Neon64 already present
  unsigned char check_sig[4] = {0xff,0xff,0xff,0xff};
//  ReadRAM(dev, check_sig, 0x80000404UL, 4);
  //ReadRAM(dev, check_sig, 0xA07919B0UL, 4);
  //ReadRAM(dev, check_sig, 0x80300000UL, 4);
  ReadRAM(dev, check_sig, 0xA0787CD8, 4);
  printf("%02x%02x%02x%02x\n", check_sig[0], check_sig[1], check_sig[2], check_sig[3]);

  Disconnect(dev);
 
  cleanup_libusb(ctx, dev);
  dev = NULL;
  ctx = NULL;

  return 0;
}
/*******************************************************************************
* Function Name  : MainTrim
* Description : STC3115 internal register configuration function
* This function has to be called at stable battery voltage during the application magnufacturing
* This function is checking itself the propper configuration of the device.
*******************************************************************************/
int MainTrim(struct i2c_client *client)
{
	unsigned char IDCode; 
	int ii,error,testnbr;

	if (client)	
		sav_client = client;
	else 
		return STC_CONFIG_CLIENT_FAIL;
	
    //Check the cut v ersion
	I2C_ReadByte(0xE0,0x18,&IDCode,1); //read IDcode
	if(IDCode == 0x13)
	{
		return STC_CONFIG_IDCODE_NOTMATCH;
	}

	ReadRAM(); //Enter test mode
	ReadSector(0, Sector0);  //read sector 0
	ExitTest(); //exit test mode

    if ( (Sector0[1] & 0x01) == 0 )
    {	
      testnbr=0;
      do
      {
        ReadRAM(); //Enter test mode
		ReadSector(0, Sector0);  //read sector 0
		ExitTest(); //exit test mode

        Sector0	[1] = Sector0[1] | 0x01 ;
        PreWriteNVN(0x40);     //Enter test mode 
		WriteSector(6,Sector0);//write sector 0 in 6
        ExitTest();

        ReadRAM(); //Enter test mode
		ReadSector(6, Sector6);  //read sector 6
		ExitTest(); //exit test mode
        
        error=0;
        for(ii=0;ii<8;ii++)
        {
          if(Sector0[ii] != Sector6[ii]) error++;
        }
        testnbr++;
      }
      while(error > 0 && testnbr < 5);
      if (testnbr >= 3)
          return STC_CONFIG_TEST_FAIL;

      testnbr=0;
      do
      {
        PreWriteNVN(0x01);     //Enter test mode 
		WriteSector(0,Sector6);//write sector 0 in 0
        ExitTest();

        ReadRAM(); //Enter test mode
		ReadSector(0, Sector0);  //read sector 0
		ExitTest(); //exit test mode
        
        error=0;
        for(ii=0;ii<8;ii++)
        {
          if(Sector0[ii] != Sector6[ii]) error++;
        }
        testnbr++;
      }
      while(error > 0 && testnbr < 5);
    }



    //Check sector 6 status
#if defined (CONFIG_MACH_HENDRIX) ||		\
	defined (CONFIG_MACH_LT02) ||			\
	defined (CONFIG_MACH_COCOA7)
		Sector3	[	0	]=0x82	;
		Sector3	[	1	]=0x8C	;
		Sector3	[	2	]=0xA0	;
		Sector3	[	3	]=0xB4	;
		Sector3	[	4	]=0xC8	;

		Sector3	[	5	]=0x70	;
		Sector3	[	6	]=0x17	;
		Sector3	[	7	]=0x27	;
		Sector4	[	0	]=0x19	;
		Sector4	[	1	]=0xB2	;
		Sector4	[	2	]=0x19	;
		Sector4	[	3	]=0xFA	;
		Sector4	[	4	]=0x19	;
		Sector4	[	5	]=0x3E	;
		Sector4	[	6	]=0x1A	;
		Sector4	[	7	]=0x6D	;
		Sector5	[	0	]=0x1A	;
		Sector5	[	1	]=0x9D	;
		Sector5	[	2	]=0x1A	;
		Sector5	[	3	]=0xB7	;
		Sector5	[	4	]=0x1A	;
		Sector5	[	5	]=0xD5	;
		Sector5	[	6	]=0x1A	;
		Sector5	[	7	]=0x01	;
		Sector6	[	0	]=0x1B	;
		Sector6	[	1	]=0x6F	;
		Sector6	[	2	]=0x1B	;
		Sector6	[	3	]=0xB1  ;
		Sector6	[	4	]=0x1B	;
		Sector6	[	5	]=0xE7	;
		Sector6	[	6	]=0x1B	;
		Sector6	[	7	]=0x59	;

    ReadRAM(); //Enter test mode
	ReadSector(7, Sector0);  //read sector 7
    ReadSector(7, Sector7);  //read sector 7
	ExitTest(); //exit test mode

		Sector7	[	0	]=0x1C	;
		Sector7	[	1	]=0xF3	;
		Sector7	[	2	]=0x1C	;
		Sector7	[	3	]=0xA8	;
		Sector7	[	4	]=0x1D	;

    error=0;
    for(ii=0;ii<8;ii++)
    {
      if(Sector0[ii] != Sector7[ii]) error++;
    }

    testnbr=0;
    while(error > 0 && testnbr < 5)
    {
        PreWriteNVN(0x80);     //Enter test mode
			  WriteSector(7,Sector7);//write sector 7 in 7
        ExitTest();

        ReadRAM(); //Enter test mode
		ReadSector(7, Sector0);  //read sector 7
		ExitTest(); //exit test mode

        error=0;
        for(ii=0;ii<8;ii++)
        {
          if(Sector7[ii] != Sector0[ii]) error++;
        }
        testnbr++;
    }



    //write sector 3 in 3
    ReadRAM(); //Enter test mode
	ReadSector(3, Sector0);  //read sector 3
	ExitTest(); //exit test mode

    error=0;
    for(ii=0;ii<8;ii++)
    {
      if(Sector0[ii] != Sector3[ii]) error++;
    }

    testnbr=0;
    while(error > 0 && testnbr < 5)
    {
        PreWriteNVN(0x08);     //Enter test mode
		WriteSector(3,Sector3);//write sector 3 in 3
        ExitTest();

        ReadRAM(); //Enter test mode
		ReadSector(3, Sector0);  //read sector 3
		ExitTest(); //exit test mode

        error=0;
        for(ii=0;ii<8;ii++)
        {
          if(Sector3[ii] != Sector0[ii]) error++;
        }
        testnbr++;
    }


    //write sector 4 in 4
    ReadRAM(); //Enter test mode
	  ReadSector(4, Sector0);  //read sector 4
	  ExitTest(); //exit test mode

    error=0;
    for(ii=0;ii<8;ii++)
    {
      if(Sector0[ii] != Sector4[ii]) error++;
    }

    testnbr=0;
    while(error > 0 && testnbr < 5)
    {
        PreWriteNVN(0x10);     //Enter test mode
		WriteSector(4,Sector4);//write sector 4 in 4
        ExitTest();

        ReadRAM(); //Enter test mode
		ReadSector(4, Sector0);  //read sector 4
		ExitTest(); //exit test mode

        error=0;
        for(ii=0;ii<8;ii++)
        {
          if(Sector4[ii] != Sector0[ii]) error++;
        }
        testnbr++;
    }

    //write sector 5 in 5
    ReadRAM(); //Enter test mode
	  ReadSector(5, Sector0);  //read sector 5
	  ExitTest(); //exit test mode

    error=0;
    for(ii=0;ii<8;ii++)
    {
      if(Sector0[ii] != Sector5[ii]) error++;
    }

    testnbr=0;
    while(error > 0 && testnbr < 5)
    {
        PreWriteNVN(0x20);     //Enter test mode
		WriteSector(5,Sector5);//write sector 5 in 5
        ExitTest();

        ReadRAM(); //Enter test mode
		ReadSector(5, Sector0);  //read sector 5
		ExitTest(); //exit test mode

        error=0;
        for(ii=0;ii<8;ii++)
        {
          if(Sector5[ii] != Sector0[ii]) error++;
        }
        testnbr++;
    }

    //write sector 6 in 6
      ReadRAM(); //Enter test mode
	  ReadSector(6, Sector0);  //read sector 6
	  ExitTest(); //exit test mode
#else
    Sector6	[	0	]=0x1B	;
	Sector6	[	1	]=0xCD	;
	Sector6	[	2	]=0x1B	;
	Sector6	[	3	]=0x13	;
	Sector6	[	4	]=0x1C	;
	Sector6	[	5	]=0x57	;
	Sector6	[	6	]=0x1C	;
	Sector6	[	7	]=0x09	;

    ReadRAM(); //Enter test mode
	ReadSector(6, Sector0);  //read sector 0
	ExitTest(); //exit test mode
#endif

    error=0;
    for(ii=0;ii<8;ii++)
    {
      if(Sector0[ii] != Sector6[ii]) error++;
    }

    testnbr=0;
    while(error > 0 && testnbr < 5)
    {
		PreWriteNVN(0x40);     //Enter test mode 
		WriteSector(6,Sector6);//write sector 6 in 6
		ExitTest();

		ReadRAM(); //Enter test mode
	    ReadSector(6, Sector0);  //read sector 0
	    ExitTest(); //exit test mode

		error=0;
		for(ii=0;ii<8;ii++)
		{
			if(Sector0[ii] != Sector6[ii]) error++;
		}
		testnbr++;
    }

	return -1;
}
/*******************************************************************************
* Function Name  : MainTrim
* Description : STC3115 internal register configuration function
* This function has to be called at stable battery voltage during the application magnufacturing
* This function is checking itself the propper configuration of the device.
*******************************************************************************/
int MainTrim(struct i2c_client *client)
{
	unsigned char IDCode,RAMBuffer[16];
	int ii,error,testnbr;

	if (client)
		sav_client = client;
	else
		return STC_CONFIG_CLIENT_FAIL;

	//Check the cut v ersion
	I2C_ReadByte(0xE0,0x18,&IDCode,1); //read IDcode
	if(IDCode == 0x13)
	{
		return STC_CONFIG_IDCODE_NOTMATCH;
	}

	I2C_ReadByte(0xE0,0x20,RAMBuffer,16); //read RAM memory content

	ReadRAM(); //Enter test mode
	ReadSector(0, Sector0);  //read sector 0
	ExitTest(); //exit test mode

	if ( (Sector0[1] & 0x01) == 0 )
	{
		testnbr=0;
		do
		{
			ReadRAM(); //Enter test mode
			ReadSector(0, Sector0);  //read sector 0
			ExitTest(); //exit test mode

			Sector0	[1] = Sector0[1] | 0x01 ;
			PreWriteNVN(0x40);     //Enter test mode
			WriteSector(6,Sector0);//write sector 0 in 6
			ExitTest();

			ReadRAM(); //Enter test mode
			ReadSector(6, Sector6);  //read sector 6
			ExitTest(); //exit test mode

			error=0;
			for(ii=0;ii<8;ii++)
			{
				if(Sector0[ii] != Sector6[ii]) error++;
			}
			testnbr++;
		}
		while(error > 0 && testnbr < 5);
		if (testnbr >= 3)
		{
			I2C_WriteByte(0xE0,0x20,RAMBuffer,16);//restore RAM memory content
			return STC_CONFIG_TEST_FAIL;
		}

		testnbr=0;
		do
		{
			PreWriteNVN(0x01);     //Enter test mode
			WriteSector(0,Sector6);//write sector 0 in 0
			ExitTest();

			ReadRAM(); //Enter test mode
			ReadSector(0, Sector0);  //read sector 0
			ExitTest(); //exit test mode

			error=0;
			for(ii=0;ii<8;ii++)
			{
				if(Sector0[ii] != Sector6[ii]) error++;
			}
			testnbr++;
		}
		while(error > 0 && testnbr < 5);
	}

	//Check sector 6 status
	Sector6	[	0	]=0x1B	;
	Sector6	[	1	]=0xCD	;
	Sector6	[	2	]=0x1B	;
	Sector6	[	3	]=0x13  ;
	Sector6	[	4	]=0x1C	;
	Sector6	[	5	]=0x57	;
	Sector6	[	6	]=0x1C	;
	Sector6	[	7	]=0x09	;

	ReadRAM(); //Enter test mode
	ReadSector(6, Sector0);  //read sector 7
	ExitTest(); //exit test mode

	error=0;
	for(ii=0;ii<8;ii++)
	{
		if(Sector0[ii] != Sector6[ii]) error++;
	}

	testnbr=0;
	while(error > 0 && testnbr < 5)
	{
		PreWriteNVN(0x40);     //Enter test mode
		WriteSector(6,Sector6);//write sector 7 in 7
		ExitTest();

		ReadRAM(); //Enter test mode
		ReadSector(6, Sector0);  //read sector 7
		ExitTest(); //exit test mode

		error=0;
		for(ii=0;ii<8;ii++)
		{
			if(Sector0[ii] != Sector6[ii]) error++;
		}
		testnbr++;
	}

	I2C_WriteByte(0xE0,0x20,RAMBuffer,16);//restore RAM memory content

	return -1;
}
Ejemplo n.º 4
0
// 并行处理
VOID CY001Drv::DeviceIoControlParallel(IN WDFQUEUE  Queue,
						IN WDFREQUEST  Request,
						IN size_t  OutputBufferLength,
						IN size_t  InputBufferLength,
						IN ULONG  IoControlCode)
{
	NTSTATUS status = STATUS_SUCCESS;
	ULONG ulRetLen = 0;

	size_t size = 0;
	void* pBufferInput = NULL;
	void* pBufferOutput = NULL;

	KDBG(DPFLTR_INFO_LEVEL, "[DeviceIoControlParallel] CtlCode:0x%0.8X", IoControlCode);

	// 取得输入缓冲区,判断其有效性
	if(InputBufferLength){
		status = WdfRequestRetrieveInputBuffer(Request, InputBufferLength, &pBufferInput, &size);
		if(status != STATUS_SUCCESS || pBufferInput == NULL || size < InputBufferLength){
			WdfRequestComplete(Request, STATUS_INVALID_PARAMETER);
			return;
		}
	}

	// 取得输出缓冲区,判断其有效性
	if(OutputBufferLength){
		status = WdfRequestRetrieveOutputBuffer(Request, OutputBufferLength, &pBufferOutput, &size);
		if(status != STATUS_SUCCESS || pBufferOutput == NULL || size < OutputBufferLength){
			WdfRequestComplete(Request, STATUS_INVALID_PARAMETER);
			return;
		}
	}

	//
	// 下面是主处理过程。
	//
	switch(IoControlCode)
	{
		// 取得驱动的版本信息
	case IOCTL_GET_DRIVER_VERSION:
		{
			PDRIVER_VERSION pVersion = (PDRIVER_VERSION)pBufferOutput;
			ULONG length;
			char tcsBuffer[120];
			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_GET_DRIVER_VERSION");

			if(OutputBufferLength < sizeof(DRIVER_VERSION)){
				status = STATUS_BUFFER_TOO_SMALL;
				break;
			}

			pVersion->DriverType = DR_WDF;
			pVersion->FirmwareType = FW_NOT_CY001;
			ulRetLen = sizeof(DRIVER_VERSION);// 告示返回长度

			// 根据String描述符,判断Firmware代码是否已经被加载。
			GetStringDes(2, 0, tcsBuffer, 120, &length);

			if(length){
				WCHAR* pCyName = L"CY001 V";
				size_t len;
				int nIndex;

				if(length < 8)
					break;

				RtlStringCchLengthW(pCyName, 7, &len);
				for(nIndex = 0; nIndex < len; nIndex++){
					if(pCyName[nIndex] != ((WCHAR*)tcsBuffer)[nIndex])
						break;
				}

				if(nIndex == len)
					pVersion->FirmwareType = FW_CY001; // 完全相符,说明新版Firmware已经加载到开发板。
			}
			break;
		}
		
		// 收到App发送过来的一个同步Request,我们应该把它保存到同步Queue中,等到有同步事件发生的时候再从Queue中取出并完成。
	case IOCTL_USB_SYNC:
		KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_SYNC");
		status = WdfRequestForwardToIoQueue(Request, m_hAppSyncManualQueue);

		// 直接返回,不调用WdfRequestComplete函数。
		// 请求者将不会为此而等待;请求的完成在将来的某个时刻。
		// 这就是所谓的异步处理之要义了。
		if(NT_SUCCESS(status))
			return;
		break;

		// 清空同步队列中的所有请求
	case IOCTL_USB_SYNC_RELEASE:
		KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_SYNC");
		ClearSyncQueue();
		break;

		// 应用程序退出,取消所有被阻塞的请求。
	case IOCTL_APP_EXIT_CANCEL: 
			
		// 取消USB设备的所有IO操作。它将连带取消所有Pipe的IO操作。
		//WdfIoTargetStop(WdfUsbTargetDeviceGetIoTarget(m_hUsbDevice), WdfIoTargetCancelSentIo);
		break;

		// 取得当前的配置号.总是设置为0,因为在WDF框架中,0以外的配置是不被支持的。
	case IOCTL_USB_GET_CURRENT_CONFIG:
		{
			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_CURRENT_CONFIG");
			if(InputBufferLength < 4){
				status = STATUS_INVALID_PARAMETER;
				break;
			}

			*(PULONG)pBufferInput = 0;// 直接赋值0,即总是选择0号配置。也可以发送URB到总线获取当前配置选项。
			ulRetLen = sizeof(ULONG);
			break;
		}

	case IOCTL_USB_ABORTPIPE:
		{
			ULONG pipenum = *((PULONG) pBufferOutput);
			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_ABORTPIPE");

			status = AbortPipe(pipenum);
		}      
		break;

		// 获取Pipe信息
	case IOCTL_USB_GET_PIPE_INFO:
		{
			// 遍历获取Pipe信息,复制到输出缓冲中。
			BYTE byCurSettingIndex = 0;
			BYTE byPipeNum = 0;
			BYTE index;
			USB_INTERFACE_DESCRIPTOR  interfaceDescriptor;
			WDF_USB_PIPE_INFORMATION  pipeInfor;

			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_PIPE_INFO");

			// 取得Pipe数。根据Pipe数计算缓冲区长度
			byCurSettingIndex = WdfUsbInterfaceGetConfiguredSettingIndex(m_hUsbInterface); 
			WdfUsbInterfaceGetDescriptor(m_hUsbInterface, byCurSettingIndex, &interfaceDescriptor);
			byPipeNum = WdfUsbInterfaceGetNumConfiguredPipes(m_hUsbInterface);		

			if(OutputBufferLength < byPipeNum * sizeof(pipeInfor)){
				status = STATUS_BUFFER_TOO_SMALL; // 缓冲区不足
			}else{

				ulRetLen = byPipeNum*sizeof(pipeInfor);

				// 遍历获取全部管道信息,拷贝到输出缓冲中。
				// 应用程序得到输出缓冲的时候,也应该使用WDF_USB_PIPE_INFORMATION结构体解析缓冲区。
				for(index = 0; index < byPipeNum; index++)
				{
					WDF_USB_PIPE_INFORMATION_INIT(&pipeInfor);
					WdfUsbInterfaceGetEndpointInformation(m_hUsbInterface, byCurSettingIndex, index, &pipeInfor);
					RtlCopyMemory((PUCHAR)pBufferOutput + index*pipeInfor.Size, &pipeInfor, sizeof(pipeInfor));
				}
			}
		}

		break;

		// 获取设备描述符
	case IOCTL_USB_GET_DEVICE_DESCRIPTOR:
		{
			USB_DEVICE_DESCRIPTOR  UsbDeviceDescriptor;
			WdfUsbTargetDeviceGetDeviceDescriptor(m_hUsbDevice, &UsbDeviceDescriptor);
			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_DEVICE_DESCRIPTOR");

			// 判断输入缓冲区的长度是否足够长
			if(OutputBufferLength < UsbDeviceDescriptor.bLength)
				status = STATUS_BUFFER_TOO_SMALL;
			else{
				RtlCopyMemory(pBufferOutput, &UsbDeviceDescriptor, UsbDeviceDescriptor.bLength);
				ulRetLen = UsbDeviceDescriptor.bLength;
			}

			break;
		}

		// 获取字符串描述符
	case IOCTL_USB_GET_STRING_DESCRIPTOR:
		{
			PGET_STRING_DESCRIPTOR Input = (PGET_STRING_DESCRIPTOR)pBufferInput;
			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_STRING_DESCRIPTOR");
			status = GetStringDes(Input->Index, Input->LanguageId, pBufferOutput, OutputBufferLength, &ulRetLen);
			
			// 由字符长度调整为字节长度
			if(NT_SUCCESS(status) && ulRetLen > 0)
				ulRetLen *= (sizeof(WCHAR)/sizeof(char));
			break;
		}

		// 获取配置描述信息。
	case IOCTL_USB_GET_CONFIGURATION_DESCRIPTOR:
		{
			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_CONFIGURATION_DESCRIPTOR");

			// 首先获得配置描述符的长度。
			status = WdfUsbTargetDeviceRetrieveConfigDescriptor(m_hUsbDevice, NULL, (USHORT*)&size);
			if(!NT_SUCCESS(status) && status != STATUS_BUFFER_TOO_SMALL)
				break;

			// 输出缓冲区不够长
			if(OutputBufferLength < size)
				break;

			// 正式取得配置描述符。
			status = WdfUsbTargetDeviceRetrieveConfigDescriptor(m_hUsbDevice, pBufferOutput, (USHORT*)&size);
			if(!NT_SUCCESS(status))
				break;

			ulRetLen = size;
			break;
		}

		// 根据可选值配置接口
	case IOCTL_USB_SET_INTERFACE:
		{
			BYTE byAlterSetting = *(BYTE*)pBufferInput;
			BYTE byCurSetting = WdfUsbInterfaceGetConfiguredSettingIndex(m_hUsbInterface); // 当前Alternate值

			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_SETINTERFACE");

			if(InputBufferLength < 1 || OutputBufferLength < 1)
			{
				status = STATUS_BUFFER_TOO_SMALL;
				break;
			}
			
			// 如果传入的可选值与当前的不同,则重新配置接口;
			// 否则直接返回。
			if(byCurSetting != byAlterSetting)
			{
				WDF_USB_INTERFACE_SELECT_SETTING_PARAMS par;
				WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_INIT_SETTING(&par, byAlterSetting);
				status = WdfUsbInterfaceSelectSetting(m_hUsbInterface, NULL, &par);
			}

			*(BYTE*)pBufferOutput = byCurSetting;
			break;
		}

		// 固件Rest。自定义命令,与Port Rest是两码事。
	case IOCTL_USB_FIRMWRAE_RESET:
		{
			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_FIRMWRAE_RESET");
			if(InputBufferLength < 1 || pBufferInput == NULL)
				status = STATUS_INVALID_PARAMETER;
			else
				status = FirmwareReset(*(char*)pBufferInput);

			break;
		}

		// 重置USB总线端口
	case IOCTL_USB_PORT_RESET:
		{
			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_PORT_RESET");			
			WdfUsbTargetDeviceResetPortSynchronously(m_hUsbDevice);
			break;
		}

		// 管道重置
	case IOCTL_USB_PIPE_RESET:
		{
			UCHAR uchPipe;
			WDFUSBPIPE pipe = NULL;

			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_PIPE_RESET");			

			if(InputBufferLength < 1){
				status = STATUS_INVALID_PARAMETER;
				break;
			}

			// 根据ID找到对应的Pipe
			uchPipe = *(UCHAR*)pBufferInput;
			pipe = WdfUsbInterfaceGetConfiguredPipe(m_hUsbInterface, uchPipe, NULL);
			if(pipe == NULL){ 
				status = STATUS_INVALID_PARAMETER;
				break;
			}

			status = WdfUsbTargetPipeResetSynchronously(pipe, NULL, NULL);
			break;
		}

		// 中断管道,放弃管道当前正在进行的操作
	case IOCTL_USB_PIPE_ABORT:
		{
			UCHAR uchPipe;
			WDFUSBPIPE pipe = NULL;

			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_PIPE_ABORT");

			if(InputBufferLength < 1){
				status = STATUS_INVALID_PARAMETER;
				break;
			}

			// 根据ID找到对应的Pipe
			uchPipe = *(UCHAR*)pBufferInput;
			pipe = WdfUsbInterfaceGetConfiguredPipe(m_hUsbInterface, uchPipe, NULL);
			if(pipe == NULL){ 
				status = STATUS_INVALID_PARAMETER;
				break;
			}
			
			status = WdfUsbTargetPipeAbortSynchronously(pipe, NULL, NULL);
			break;
		}

		// 取得驱动错误信息,驱动总是把最后一次发现的错误保存在设备对象的环境块中。
		// 这个逻辑虽然实现了,但目前的版本中,应用程序并没有利用这个接口。
	case IOCTL_USB_GET_LAST_ERROR:
		{
			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_LAST_ERROR");

			if (OutputBufferLength >= sizeof(ULONG))
				*((PULONG)pBufferOutput) = m_ulLastUSBErrorStatusValue;
			else
				status = STATUS_BUFFER_TOO_SMALL;

			ulRetLen = sizeof(ULONG);
			break;
		}

		// Clear feature命令
	case IOCTL_USB_SET_CLEAR_FEATURE:
		{
			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_SET_CLEAR_FEATURE");
			status = UsbSetOrClearFeature(Request);
			break;
		}

		// 为USB设备加载固件程序。带有偏移量参数,用这个分支;不带偏移量,可用下一个分支。
		// 带偏移量的情况下,固件代码是一段一段地加载;
		// 不带偏移量的情况,固件代码作为一整块一次性被加载。
	case IOCTL_FIRMWARE_UPLOAD_OFFSET:
		{
			void* pData = pBufferOutput;
			WORD offset = 0;

			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_FIRMWARE_UPLOAD_OFFSET");

			if(InputBufferLength < sizeof(WORD)){
				status = STATUS_INVALID_PARAMETER;
				break;
			}

			offset = *(WORD*)pBufferInput;
			status = FirmwareUpload((PUCHAR)pData, OutputBufferLength, offset);
			break;
		}

		// 为USB设备加载固件程序。
	case IOCTL_FIRMWARE_UPLOAD:
		{
			void* pData = pBufferOutput;
			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_FIRMWARE_UPLOAD");
			status = FirmwareUpload((PUCHAR)pData, InputBufferLength, 0);
			break;
		}

		// 读取开发板设备的RAM内容。RAM也就是内存。
		// 每次从同一地址读取的内容可能不尽相同,开发板中固件程序在不断运行,RAM被用来储数据(包括临时数据)。
	case IOCTL_FIRMWARE_READ_RAM:
		{
			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_FIRMWARE_READ_RAM");
			status = ReadRAM(Request, &ulRetLen);// inforVal中保存读取的长度
			break;
		}

		// 其他的请求
	default:
		{
			// 一律转发到SerialQueue中去。			
			WdfRequestForwardToIoQueue(Request, m_hIoCtlSerialQueue);

			// 命令转发之后,这里必须直接返回,千万不可调用WdfRequestComplete函数。
			// 否则会导致一个Request被完成两次的错误。
			return;
		}
	}

	// 完成请求
	WdfRequestCompleteWithInformation(Request, status, ulRetLen);
}