Windows XP下usbport.sys驱动内部实现解析(二)

Windows XP USB启动安装全攻略:驱动注入原理与实战 操作系统安装的核心在于引导程序对硬件驱动的识别与加载。Windows XP等早期系统在安装阶段,其文本模式安装环境默认不包含USB大容量存储驱动,导致无法直接从USB设备启动安装。通过修改安装源文件中的关键配置文件,如TXTSETUP.SIF和DOSNET.INF,可以将USB存储驱动(如usbstor.sys)的加载时机提前至系统引导的初始阶段,这一过程被称为“驱动注入”。这项技术的价值在于突破了原生安装程序的限制,使得为老旧工业设备、嵌入式系统或特定兼容性测试创建便携式、隔离的Windows XP工作环 阅读详情

http://hi.baidu.com/jlgwxq/blog/item/e0f223312c0aa548ac4b5f67.html

 Windows XP下usbport.sys驱动内部实现解析(二)
2010-01-22 18:15
(接上一篇)

4. 处理USB请求(URB)

在进入下一个主题之前我总结几个事实让大家注意:

1. 对于每个usb总线上的设备,usbport在usbhub的帮助下为其创建一个device handle,并把这些device handle链接到一起,并为endpoint 0 创建一个pipe handle。

2. 在进行select configuration的时候,usbport创建一个config handle结构,保存其指针到对应的device handle,然后创建若干个interface handle,全部链接到config handle上去。对于每个interface里面的全部endpoint,为其创建一个pipe handle,全部连接到对应的device handle上面去。对于每个pipe handle,为其创建一个endpoint结构,保存其指针到pipe handle,并把所有创建的endpoint全部链接到一起。

3. 客户驱动必须要保存由select configuration所返回的pipe handle,并在随后的urb里面恰当的填写这个值。

前面的结构中的若干个LIST_ENTRY就是usbport维护管理这些结构的关键。维护管理用的基础结构了解好了,接下来就是urb的处理问题了。

说到urb的处理,就不能不提一些internal io control的问题。都知道urb是通过一个internal io control提交的,除了这个以外还有若干个其他的internal io control,比如用于获取port状态的、比如用于reset port的、等等等等。这些处理这里先不提,因为大部分的处理都是由usbhub完成的,usbport单独完成的功能很少,还有部分是两个配合完成的 -- 这个留到usbhub的地方再回头来说。

首先明白一个事实,客户驱动把urb提交给的是自己的pdo,这个pdo作一些过滤动作以后,直接提交给了root hub的pdo。至于是不是这样的一个情况,等到说起usbhub的时候就明白了,现在先假定如此。

usbport在一份数据结构的帮助下对每个urb作一些检查,然后转到特定的处理函数,先看这个数据结构的定义:

struct URB_DISPATCH_TABLE // sizeof=0X14
{
PVOID DispatchRoutine; // process routine
USHORT TransferLen; //
UCHAR reserved[2];
UCHAR bmRequestDirection; // setup packet
UCHAR bmRequestType;
UCHAR Recipient;
UCHAR bRequest;
UCHAR Flags;
UCHAR data[3];
ULONG FunctionCode;
};

很简单的一个结构。TransferLen用于固定大小的传输,用来检查说提交的buffer大小是否正确,如果是0,则不检查大小信息。接下来的几个成员用于control transfer用来填充setup packet。许多的urb都不需要你完全的填充所有的setup packet成员,usbport在这里会为你填充这些已知的固定的成员。flags则是控制usbport的操作方式的,下面会详细的解释。 function code则是指明这份数据是对应哪个function的。理所当然的,usbport为每个function code准备一个这样的结构构成一个数组。

下面是处理URB的代码:

processurb(pUrb)
{
检查FunctionCode
检查pUrb->DeviceHandle
if(UrbDispatchTable[FunCode].Flags & 4)
{
// force usbport to use default pipe
get pipe handle from device handle
save it to pUrb
}

if(UrbDispatchTable[FunCode].Flags & 1)
{
// actual transfer needed
if(UrbDispatchTable[FunCode].Flags & 8)
{
// no transfer buffer needed
pUrb->TransferBuffer = 0
pUrb->TransferBufferLength = 0
pUrb->TransferBufferMdl = 0
}
validate pipe handle
if(pUrb->TransferBufferLength !=0 && pUrb->TransferBufferMdl == 0)
{
IoAllocateMdl();
MmBuildMdlForNonPagedPool();
set a flag in UrbHeader,indicates that when we complete this urb,we must free the mdl
}
allocate a transfer struct
}

check transfer length

status = call UrbDispatchTable[FunCode]->DispatchRoutine(...);

if(status != pending)
complete the urb

return status;
}

proccess urb是一个公共的处理函数,他根据dispatch table的flags成员作一些有限度的处理,然后交给真正的dispatch routine处理。

这个dispatch routine就各式各样了,大致分成4类:

1类就是不需要transfer结构了,参考上flags & 1非0的分支。这类urb大多直接完成了,比如select configuration,比如get frame length。

2类属于control 传输,这类就根据dispatch table里面的那些setup packet成员填充自己的setup pack结构,然后将transfer排队。

3类属于interrupt or bulk 传输,直接排队transfer。

4类属于iso transfer,最主要的是要检查各个Packet,而且要设置start frame number,最后还是要排队transfer。

不需要排队的urb大多是一些没有实现的urb,比如set frame length,或者是一些要特别处理的,比如select configuration。其他的最终都是要排队transfer的。特别注意参加排队的是transfer结构,而不是irp或者其他。对照 endpoint结构的那些成员PendingTransferList等等就能明白,排队的对象并不是irp。

transfer 也是一个不小的结构:

struct TRANSFER // sizeof=0XC0
{
ULONG Direction;
ULONG TimeoutInterval;
LARGE_INTEGER SubmitTime;
ULONG TransferedLen;
ULONG Status;
ULONG Irp;
PKEVENT pEvent;
PURB UrbPointer;
LIST_ENTRY TransferListEntry; // link entry
ULONG MappedRegisterBase; // for dma
ULONG NumberOfMappedRegister; //
ULONG TransferDirection;
ULONG TransferBufferLen;
URB_SETUP_PACKET SetupPacket;
PMDL TransferMdl;
LIST_ENTRY AdapterDBList; // for double buffer
PVOID ParentPointer; // split
PVOID EndpointPointer;
PVOID ClientTransferPointer; // passed to miniport
LIST_ENTRY ChildTransferListHead;
LIST_ENTRY SplitTransferListEntry;
PVOID IsoTransferInfo; // iso
SG_LIST sgList; // scatter-gather list
};

留下了一些分析相关的成员:其中如果这个transfer对应有irp则会设置Irp成员,这个是可以选的。如果没有对应irp也是可以的,那么怎么知道这个transfer完成了呢?用irp的话还可以使用complete routine,要是没有irp呢?这就是下面的那个pEvent成员的作用了,他指向一个event,完成的时候会设置这个event。

还有几个list entry,存在的主要原因就是允许传输大于MaxTransferLength的数据,那么就必须把原来的buffer切割成小的buffer,为每个buffer创建一个child transfer,这些list entry就是用来管理这个的。

至于AdapterDBList,则是上面说的某个buffer跨越了非连续的两个物理页的情况下,用于miniport通知的。 miniport必须要使用额外的缓冲而不是transfer所提供的缓冲,所以usbport必须要提供空间来保存这些额外的缓冲信息。

最后的是sgList,usbport把要传输的buffer映射成一个一个的物理页,用sgList这个结构来描述,这个结构会传递给miniport driver使用。

好了,来看真实的排队情况:usbport通过调用_USBPORT_QueueTransferUrb函数来排队某个urb,这个函数很简单。

_USBPORT_QueueTransferUrb(pUrb,pEndpoint)
{
do some check
update some fields in transfer struct
if(transfer associates with an irp)
call _USBPORT_QueuePendingTransferIrp
else
call _USBPORT_QueuePendingUrbToEndpoint

call _USBPORT_FlushPendingList
}

根据transfer是否关联有irp调用不同的函数,在有irp的情况下首先是要设置irp的cancel routine,然后再调用_USBPORT_QueuePendingUrbToEndpoint函数。也其实就是多一个设置cancel routine的步骤,至于cancel部分后面会有专门的讲解,先放一放。主要来看后面这个函数,更是非常简单:

_USBPORT_QueuePendingUrbToEndpoint(pTransfer,pEndpoint)
{
link transfer->TransferListEntry to Endpoint->PendingTransfer
}

接下来当然是_USBPORT_FlushPendingList函数了,看他的名字都知道是在干什么。这个函数显得很复杂,因为是几个很关键的函数之一。

_USBPORT_FlushPendingList(pEndpoint)
{
bContinue = TRUE
do
{
if(Endpoint is not root hub\'s endpoint)
{
check Endpoint->ActiveTransfer list
if(is not empty)
{
get a transfer from active list
bContinue = FALSE
call _USBPORT_CoreEndpointWorker
if return != 0
call _USBPORT_InvalidateEndpoint
}
}
if(bContinue == FALSE)
break;

check Endpoint->PendingTransfer
if(is not empty)
{
reset canel routine
if(irp has not been canceled)
{
bContinue = FALSE
call _USBPORT_QueueActiveUrbToEndpoint
if( return != 0 )
call _USBPORT_FlushMapTransferList
else
{
call _USBPORT_CoreEndpointWorker
if return != 0
call _USBPORT_InvalidateEndpoint
}
}
} while( bContinue );
}

或者看了会很奇怪,先不管,我把全部代码流程都列出来,然后再总体讨论。

_USBPORT_QueueActiveUrbToEndpoint(pTransfer,pEndpoint)
{
bNeedMap = FALSE
if(Endpoint is stopped || Transfer is aborted)
link transfer to pEndpoint->CancelTransfer
else
{
if(Transfer\'s length != 0)
{
link transfer to fdo\'s MapTransferList
bNeedMap = TRUE;
}
else
{
link transfer to pEndpoint->ActiveTransfer
}
}
return bNeedMap
}

这个函数比较简单,作作判断决定transfer该进入什么样子的list,然后返回一个标记表明是否需要进行map,只有在transfer的 transfer length也就是pUrb->TransferBufferLength非0的时候,才需要进行Map。

_USBPORT_FlushMapTransferList
{
while(!pFdoExt->DoMapping)
{
if(pFdoExt->MapTransferList is not empty)
{
pFdoExt->DoMapping = TRUE;
get a transfer from the list
AllocateAdapterChannel(_USBPORT_MapTransfer);
}
else break;
}
}

也是一个不算复杂的函数:首先检查当前是否在map,如果为false,然后检查map transfer list是否是空,不空则取一个处理调用AllocateAdapterChannel,传递的参数是_USBPORT_MapTransfer,在这个函数里面会重新设置pFdo->DoMapping = FALSE。

Windows 7 SP1增强型升级安装实战:USB3.0驱动注入与离线补丁部署 Windows 7作为NT6.x内核的经典操作系统,虽已终止支持,但在工控、教育及嵌入式场景中仍承担关键业务。其升级本质不是版本迭代,而是面向Legacy BIOS环境的系统兼容性工程——需解决USB3.0驱动缺失、NVMe识别失败、SHA-2签名支持不足等底层限制。技术核心在于离线镜像服务(DISM注入)、启动介质定制(Rufus+bootmgr适配)与补丁依赖链管理(KB4474419为前置基点)。该方案兼顾业务连续性与硬件兼容性,适用于戴尔OptiPlex等老平台在不重装系统前提下获得USB3.0识别 阅读详情

相关推荐

USBport.sys驱动修复系统蓝屏问题实战指南

当USB设备插入主机端口后,主机控制器(Host Controller)会检测到物理连接的变化,并启动设备初始化流程。整个流程可以分为以下几个阶段:设备检测与复位主机检测到设备插入后,会向设备发送复位信号(Reset),将设备置于默认状态(Default State),并准备进入地址分配阶段。获取设备描述符复位完成后,主机会通过控制传输(Control Transfer)向设备发送请求,获取设备的基本信息,包括设备支持的USB版本、最大包大小等。分配设备地址。

weixin_35756624的博客 1298

Windows XP下usbport.sys驱动内部实现解析(一)

http://hi.baidu.com/jlgwxq/blog/item/a3bcc30356a3cc057aec2c64.html Windows XP下usbport.sys驱动内部实现解析(一) 2010-01-22 18:10 上一篇讲了USB驱动栈整体结构,说明了usbport.sys的重要作用,现在就具体分析usbport.sys的内部实现细节。 首先再重复一下:

killcpp的专栏 1294

Windows 2000专用USB驱动完整安装包(含INF配置与微端口驱动)

简介:本资源为面向Windows 2000操作系统的USB设备兼容性解决方案,包含经验证的主机控制器驱动、通用USB驱动模型及设备级微端口驱动。核心文件win2000_usb.inf提供标准化安装指引,支持硬件ID识别与自动驱动部署;压缩包集成可执行安装程序、PUDN来源说明文档及完整驱动签名/配置信息,适用于解决Win2000下USB设备无法识别、枚举失败或功能异常等典型问题,助力老旧系统延续USB外设支持能力。

weixin_35755640的博客 255

windows xp 驱动开发(四) USB开发技术概述

转载请标明是引用于 http://blog.csdn.net/chenyujing1234   欢迎大家提出意见,一起讨论!   参考文章: http://blog.csdn.net/xxxluozhen/article/details/4882121   1、  概述 结合LPC2440开发板,编写其USB上位机驱动,旨在增强对USB总线协议的理解和提升WinXP下驱动开发能力

chenyujing1234的专栏 6376

QF9700 USB网卡驱动程序完整安装与配置指南

QF9700 USB网卡驱动是专为基于QF9700芯片组设计的USB接口网络适配器提供的核心软件支持,旨在实现设备与操作系统的无缝通信。该驱动不仅承担硬件识别、资源分配和数据传输调度等基础功能,还通过标准化接口向上层网络协议栈提供稳定的数据链路服务。作为连接物理网络与操作系统之间的桥梁,QF9700驱动在即插即用(Plug and Play)、电源管理(如Suspend/Resume)以及热拔插响应机制中发挥关键作用。

weixin_42600128的博客 843

usbport.sys文件下载 系统蓝屏修复 很管用 已测

usbport.sys文件下载 系统蓝屏修复 很管用 已测

Windows XP下usbport.sys驱动内部实现解析(四)

http://hi.baidu.com/jlgwxq/blog/item/e54543100b5cb7c5c2fd7860.html Windows XP下usbport.sys驱动内部实现解析(四) 2010-01-22 18:16 (接上一篇) 然后来看看实际上的work routine,先看通用的这个。root hub的是一个特殊的函数。 USBPORT_DmaEndpoi

killcpp的专栏 629

USB鼠标所需驱动HIDUSB.SY_ mouhid.sys

安装USB鼠标所需驱动 HIDUSB.SY_ mouhid.sys

Windows XP下usbport.sys驱动内部实现解析(三)

Windows XP下usbport.sys驱动内部实现解析(三) 2010-01-22 18:16 (接上一篇) _USBPORT_MapTransfer是个比较复杂的函数了,他涉及到transfer的切割、sgList结构的填写,少安毋躁。。。哈哈 struct SG_LIST { ULONG Flags; PVOID CurrentVa; PVOID MappedSy

killcpp的专栏 665

一位海外开发者的 OpenSPG KAG 实践分享

KAG 是一个以创建和操作知识图谱为核心的框架。知识图谱是数据之间相互关联的可视化和结构化表示,对于搜索引擎、推荐系统和机器学习等应用至关重要。KAG 的目标是提供一个强大的平台,使开发者能够:轻松构建图谱;通过增强算法丰富数据;集成人工智能,以进行更精确的推理。通过理解 KAG,可以明显看出,这个框架旨在帮助从初学者到专业开发者,在项目中创造更优的解决方案。它在简便性和集成方面的优势,使其成为下一代基于数据的应用程序的前景工具。

金融机器智能社区 3405

智慧工地算法视频分析服务器区域入侵检测AI视频分析技术在煤矿的实战应用

通过实时分析和处理井下视频资料,智慧矿山算法视频分析服务器不仅能够及时发现并预警人员违规行为和设备异常状况,还能够通过智能分析预防潜在的安全风险,从而显著提高煤矿的安全管理水平和生产效率。

EasyDarwin开源社区技术博客 559

USB 驱动程序堆栈体系结构

USB 驱动程序堆栈体系结构 本主题提供了通用串行总线 (USB) 驱动程序堆栈体系结构的概述。 下图显示了 Windows 8 USB 驱动程序堆栈体系结构框图。该图分别显示了 USB 2.0 和 USB 3.0 的 USB 驱动程序堆栈。当设备附加到 xHCI 控制器时,Windows 会加载 USB 3.0 驱动程序堆栈。USB 3.0 堆栈是 Windows 8 中的新功能。 当

M_O_Bz的专栏 2437

3DGS-to-PC实战指南:零代码实现3D高斯场景到点云/Mesh的高效转换

本文详细介绍了3DGS-to-PC工具如何实现3D高斯场景到点云/Mesh的高效转换,无需代码即可完成。通过实战案例和参数调优技巧,帮助用户快速掌握这一开源插件的使用方法,提升3D数据处理效率。特别适合建筑扫描、影视特效等领域的专业人士。

q1w3e5r7t9y的博客 273

Window XP驱动开发(十二) 驱动的应用程序端 (原理分析)

转载请标明是引用于 http://blog.csdn.net/chenyujing1234  欢迎大家提出意见,一起讨论!  在看这篇文章时可参考我的另一篇文章: Window XP驱动开发(九) USB WDM驱动开发实例 bulkusb >> 1、 INF 文件基础 所有的USB设备在设备描述符中都有一个厂商ID(VID)和产品ID(PID)来向Windows 报告。Wind

chenyujing1234的专栏 6457

4G LTE 与 5G 无线网络规划对比:从 BBU/RRU 到 CU/DU/AAU 的架构演进解析

本文深度解析4G LTE与5G无线网络架构的演进差异,从BBU/RRU分立式架构到CU/DU/AAU三级重构,揭示移动通信代际跃迁的技术本质。重点对比了网络规划中的覆盖能力、容量规划、传输网络等九大维度,为通信工程师提供实用的技术对照手册,助力5G网络高效部署。

weixin_32821533的博客 287

从零到一:鲲鹏920服务器上的DeepSeek模型部署全流程解析

本文详细解析了在华为鲲鹏920服务器上部署DeepSeek模型的全流程,包括环境准备、模型服务框架部署、性能优化及生产环境方案。通过ARM架构优化和量化技术,显著提升模型推理效率,适用于企业级AI应用场景,助力国产化技术落地。

weixin_29094775的博客 599

windows的usb体系结构

1.背景知识介绍..一些关于电路理论,计算机组成原理的东西 2.usb相关背景知识 3.windows usb整体架构介绍 4.usbport.sys分析 5.usbuhci.sys分析 6.usbhub.sys分析 usb协议方面的涉及的不算太多..毕竟都是有文档的东西 主要着眼于windows的实现部分.. 过年了..我去买了个logitech的无线光电鼠..正好是个usb接口的..于是就想了

3993

详细推导波特图增益和相位曲线

最近因为项目需求,在回看波特图方面的内容。大三那会,《自动控制原理》这本书里面就讲过这些东西,但是那时候总感觉学这些没啥用,反正以后也用不到,对这种课程的重视度不是很高。 工作后发现,只要你从事的是和本专业相关的工作,大学学过的很多理论课程在后面大概率都会用到。曾经那些我们在学校以为用不上的东西,熟不知在后面用处还多着呢。所以啊,仅仅只是我们的以为而已! 现在还在学校的同学,对待《自动控制理论》、《信号与系统》、《通信原理》这样的核心专业课,建议还是好好学习一下,认真听听课。哪怕是考试完以后就会忘掉,但当我

D_Katter的博客 3936

Windows XP 对USB设备使用的痕迹记录原理

<br />Windows 2000/XP 系统对U盘的处理过程入手,逆向彻底消除U盘使用痕迹<br />2008/06/20 21:55<br />如何彻底消除U盘使用痕迹?网上有许多资料,但是都是难以理解,假设作为操作系统,它不会保存无意义的U盘使用痕迹(如果故意设置后门当然不同),这些相关痕迹实际应该是操作系统快速识别移动存储设备必须的信息。Windows一般使用注册表来存储这样的信息,但是对于系统的重要更改,一般也会保留*.log的日志以方便排错。<br />对于计算机系统来说,U盘这样一个东西,实

Life 1万+

诊断CAPL自动化(5) ——没有CANdela,无法编辑cdd数据库文件,也能轻松完成诊断测试

🍅我们知道cdd数据库文件,是CANoe测试环境的重要组件,它可以让我们更加轻松的完成诊断测试工作;但是创建和编辑cdd文件是需要CANdela 来完成的,一个 liscense 就要将近二十万,成本确实高🍅特别是在处理22/2E/31服务的时候,频繁的增加功能,可能需要频繁的用CANdela 修改CDD,我测试开发过程中,一般很少去修改cdd,有这个时间,纯手撸也开发完了,就一个CANdela,鬼知道此时此刻到了谁手里,我也懒得去找。🍅演示软硬件环境;目录📘前言。

蚂蚁小兵 5756

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

关于解决插入USB设备蓝屏的思路【转】

近日在作维修服务时发现不少用户存在一个问题就是很多电脑在插入部分USB设备时电脑会立刻蓝屏,首先我尝试了卸载了设备管理器里的所有关于USB的项目,然后重启后测试,结果发现在系统自动检测USB设备时再次立刻蓝屏,无法只能试着卸载删除所有的USB驱动文件,最终问题才得已解决,方法如下: 1、进入C:>windows>system32>drives下删掉USBehci.sys usb...

weixin_30768661的博客 1348

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

工厂设备接MES为什么慢:协议识别与点表配置自动化的技术拆解

工业现场设备接 MES 的周期主要消耗在协议识别与点表配置。本文拆解这条链路的四层结构,给出点表映射的数据模型、两种部署架构的对比,以及可直接落地的三项验收口径与校验代码。适合工控集成、MES 实施、设备联网方向的工程师。

emfuture的博客 366

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

list

的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。,因此反向迭代器的实现可以借助正向迭代器,即:反向迭代器内部可以包含一个正向迭代器,对正向迭代器的接口进行包装即可。是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。迭代到该位置,在这段位置上迭代需要线性的时间开销;最大的缺陷是不支持任意位置的随机访问,比如:要访问。还需要一些额外的空间,以保存每个节点的相关联信息。个元素,必须从已知的位置。

xie0510_的博客 262

向 excel、word、pdf 三种文档中占位符插入数据

【代码】向 excel、word、pdf 三种文档中占位符插入数据。

weixin_45934659的博客 42

C++ STL 反向迭代器:从源码框架到适配器实现

在 C++ STL 中,反向迭代器(reverse_iterator)是一个很典型的设计案例:它本身并不直接持有容器数据,而是通过封装一个正向迭代器,把「前进」变成「后退」,从而让同一个容器既能正序遍历,也能逆序遍历。本文从 SGI-STL 3.0 的源码框架出发,梳理反向迭代器的设计思路,再手写一个通用的迭代器适配器,并在vector和list中完成适配与测试。在 SGI-STL 3.0 中,反向迭代器的核心源码位于。反向迭代器是一个适配器,各个容器再基于它适配出自己的反向迭代器类型。下面截取list。

Godbro的博客 227
上一篇: Windows XP下usbport.sys驱动内部实现解析(一)
下一篇: Windows XP下usbport.sys驱动内部实现解析(三)
killcpp
博客等级 码龄20年 13粉丝 16原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值