USB转串口驱动代码分析.docx
- 文档编号:27134180
- 上传时间:2023-06-27
- 格式:DOCX
- 页数:22
- 大小:25.47KB
USB转串口驱动代码分析.docx
《USB转串口驱动代码分析.docx》由会员分享,可在线阅读,更多相关《USB转串口驱动代码分析.docx(22页珍藏版)》请在冰豆网上搜索。
USB转串口驱动代码分析
USB转串口驱动代码分析
分类:
windowxp驱动(USB)/FireFox插件/汇编2012-08-0915:
55 3467人阅读 评论
(1) 收藏 举报
代码分析extensioninterfacebufferresourcesio
目录(?
)[+]
1、USB插入时,创建设备
[plain] viewplaincopy
1.DriverObject->DriverExtension->AddDevice = USB2COM_PnPAddDevice;
步一、调用USB2COM_CreateDeviceObject创建功能设备对象(FDO)
(1)IoCreateDevice系统API的原理为:
[plain] viewplaincopy
1.NTKERNELAPI
2.NTSTATUS
3.IoCreateDevice(
4. IN PDRIVER_OBJECT DriverObject,
5. IN ULONG DeviceExtensionSize,
6. IN PUNICODE_STRING DeviceName OPTIONAL,
7. IN DEVICE_TYPE DeviceType,
8. IN ULONG DeviceCharacteristics,
9. IN BOOLEAN Reserved,
10. OUT PDEVICE_OBJECT *DeviceObject
11. );
在之前真实的USB驱动中我们是这样创建的:
[cpp] viewplaincopy
1.ntStatus = IoCreateDevice(
2. DriverObject, // our driver object
3. sizeof(DEVICE_EXTENSION), // extension size for us
4. NULL, // name for this device
5. FILE_DEVICE_UNKNOWN,
6. FILE_AUTOGENERATED_DEVICE_NAME, // device characteristics
7. FALSE, // Not exclusive
8. &deviceObject); // Our device object
就是第三个参数为NULL,第四个参数为FILE_DEVICE_UNKNOWN,意味着我们驱动想附加的设备是空的,且未知。
由于我们是创建虚拟串口驱动,因此调用IoCreateDevice创建时在指定串口设备的名字,且指定设备类型。
[cpp] viewplaincopy
1.ntStatus = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION),
2. &deviceObjName, FILE_DEVICE_SERIAL_PORT,
3. FILE_DEVICE_SECURE_OPEN, TRUE, DeviceObject);
(2)为自定义的扩展设备中的设备名字段指定设备名
[cpp] viewplaincopy
1.// deviceExtension->DeviceName为UNICODE_STRING类型
2.RtlZeroMemory(&deviceExtension->DeviceName, sizeof(UNICODE_STRING));
3.deviceExtension->DeviceName.MaximumLength = deviceObjName.Length + sizeof(WCHAR);
4.// Buffer重新分配
5.deviceExtension->DeviceName.Buffer = USB2COM_ExAllocatePool(NonPagedPool, deviceObjName.Length + sizeof(WCHAR));
6.RtlZeroMemory(deviceExtension->DeviceName.Buffer,
7. deviceObjName.Length+sizeof(WCHAR));
8.RtlAppendUnicodeStringToString(&deviceExtension->DeviceName, &deviceObjName);
(3)初始化事件、串口控件对象、关键代码段、自旋锁、读写队列链表。
[cpp] viewplaincopy
1. // this event is triggered when there is no pending io of any kind and device is removed
2.KeInitializeEvent(&deviceExtension->RemoveEvent, NotificationEvent, FALSE);
3.
4.// this event is triggered when self-requested power irps complete
5.KeInitializeEvent(&deviceExtension->SelfRequestedPowerIrpEvent, NotificationEvent, FALSE);
6.
7.// this event is triggered when there is no pending io (pending io count == 1 )
8.KeInitializeEvent(&deviceExtension->NoPendingIoEvent, NotificationEvent, FALSE);
9.
10.// spinlock used to protect inc/dec iocount logic
11.KeInitializeSpinLock (&deviceExtension->IoCountSpinLock);
12.
13. deviceExtension->BaudRate = 19200;
14./* Set line control */
15.deviceExtension->SerialLineControl.StopBits = STOP_BIT_1;
16.deviceExtension->SerialLineControl.Parity = NO_PARITY;
17.deviceExtension->SerialLineControl.WordLength = 8;
18.
19.deviceExtension->SpecialChars.XonChar = SERIAL_DEF_XON;
20.deviceExtension->SpecialChars.XoffChar = SERIAL_DEF_XOFF;
21.
22.deviceExtension->HandFlow.ControlHandShake = SERIAL_DTR_CONTROL;
23.deviceExtension->HandFlow.FlowReplace = SERIAL_RTS_CONTROL;
24.deviceExtension->HandFlow.XoffLimit = 300;
25.deviceExtension->HandFlow.XonLimit = 100;
26.InitializeCircularBuffer(&deviceExtension->InputBuffer, 512);
27.InitializeCircularBuffer(&deviceExtension->OutputBuffer, 512);
28.KeInitializeSpinLock(&deviceExtension->InputBufferLock);
29.KeInitializeSpinLock(&deviceExtension->OutputBufferLock);
30.InitializeListHead(&deviceExtension->ReadQueue);
31.KeInitializeSpinLock(&deviceExtension->ReadQueueSpinLock);
32.InitializeListHead(&deviceExtension->WriteQueue);
33.KeInitializeSpinLock(&deviceExtension->WriteQueueSpinLock);
34.InitializeListHead(&deviceExtension->PurgeQueue);
35.KeInitializeSpinLock(&deviceExtension->PurgeQueueSpinLock);
步二、让设备对象支持直接读写IO和并设置DO_POWER_PAGABLE
设置DO_POWER_PAGABLE的目的是在suspend期间不接收一个IRP_MN_STOP_DEVICE,
在resume时不接收一个IRP_MN_START_DEVICE消息。
[cpp] viewplaincopy
1.// we support direct io for read/write
2. //
3. deviceObject->Flags |= DO_DIRECT_IO;
4.
5.
6. //Set this flag causes the driver to not receive a IRP_MN_STOP_DEVICE
7. //during suspend and also not get an IRP_MN_START_DEVICE during resume.
8. //This is neccesary because during the start device call,
9. // the GetDescriptors() call will be failed by the USB stack.
10. deviceObject->Flags |= DO_POWER_PAGABLE;
步三、附加FDO到物理设备对象上,并创建SymbolLink,并通过IoRegisterDeviceInterface来设备绑定让设备可见。
[cpp] viewplaincopy
1.deviceExtension->TopOfStackDeviceObject =
2. IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject);
[cpp] viewplaincopy
1.status = IoRegisterDeviceInterface(PDevExt->PhysicalDeviceObject, (LPGUID)&GUID_CLASS_COMPORT,
2. NULL, &PDevExt->DeviceClassSymbolicName);
步四、获得物理设备的性能的一份复制,保存在extension中,以此来获得电源级别
(1)建立IRP来产生一个发往FDO的内部查询请求;
[cpp] viewplaincopy
1.irp = IoAllocateIrp(LowerDeviceObject->StackSize, FALSE);
(2)设置IRP要发往的设备栈Location(是更低层的设备,在这里就是它附加下的USB)的信息,
eg:
MajorFunction、MinorFunction、Parameters.DeviceCapabilities.Capabilities
[cpp] viewplaincopy
1.nextStack = IoGetNextIrpStackLocation(irp);
2.nextStack->MajorFunction= IRP_MJ_PNP;
3.nextStack->MinorFunction= IRP_MN_QUERY_CAPABILITIES;
在以上代码中的IoGetNextIrpStackLocation是一个宏,它的定义如下:
[cpp] viewplaincopy
1.#define IoGetNextIrpStackLocation( Irp ) (\
2. (Irp)->Tail.Overlay.CurrentStackLocation - 1 )
从以上宏可以看出:
IRP结构体中存有当前的栈LocationCurrentStackLoctation,而我们的IRP要发往的栈Location的获得方法就是原有栈的地址-1。
(3)设置IRP的完成例程;(在完成全程中就是把事件激活,这样KeWaitForSingleObject就能走下来)
(4)把IRP发送下去,并等待完成;
[cpp] viewplaincopy
1.ntStatus = IoCallDriver(LowerDeviceObject,
2. irp);
3.
4. USB2COM_KdPrint( DBGLVL_MEDIUM,(" USB2COM_QueryCapabilities() ntStatus from IoCallDriver to PCI = 0x%x\n", ntStatus));
5.
6. if (ntStatus == STATUS_PENDING) {
7. // wait for irp to complete
8.
9. KeWaitForSingleObject(
10. &event,
11. Suspended,
12. KernelMode,
13. FALSE,
14. NULL);
当完成全程返回时, nextStack->Parameters.DeviceCapabilities.Capabilities=DeviceCapabilities;指针就存着我们的性能信息。
步五、获得USB的版本信息;
直接调用系统API:
[cpp] viewplaincopy
1.USBD_GetUSBDIVersion(&versionInformation);
2、处理系统PNP和电源管理请求的派遣函数
[cpp] viewplaincopy
1.DriverObject->MajorFunction[IRP_MJ_PNP] = USB2COM_ProcessPnPIrp;
在USB2COM_ProcessPnPIrp里case了以下几个消息:
IRP_MN_START_DEVICE 、IRP_MN_QUERY_STOP_DEVICE、IRP_MN_CANCEL_STOP_DEVICE、IRP_MN_STOP_DEVICE、
IRP_MN_QUERY_REMOVE_DEVICE、IRP_MN_CANCEL_REMOVE_DEVICE、IRP_MN_SURPRISE_REMOVAL、IRP_MN_REMOVE_DEVICE
文章<
IRP_MN_START_DEVICE、
IRP_MN_STOP_DEVICE、IRP_MN_EJECT和IRP_MN_SURPRISE_REMOVAL
所以一比较,觉得USB2COM考虑得更全面。
(1)IRP_MN_START_DEVICE
与文章<
(2)IRP_MN_QUERY_STOP_DEVICE
与文章<
(3)IRP_MN_CANCEL_STOP_DEVICE
(4)IRP_MN_STOP_DEVICE、
(5)IRP_MN_QUERY_REMOVE_DEVICE、
(6)IRP_MN_CANCEL_REMOVE_DEVICE、
(7)IRP_MN_SURPRISE_REMOVAL、
(8)IRP_MN_REMOVE_DEVICE
3、当应用程序CreateFile时,调用USB2COM_Create
DriverObject->MajorFunction[IRP_MJ_CREATE]=USB2COM_Create;
步一、判断是否能接收一个新的IO请求
如果不能接收一个新的IO请求,那么直接返回。
[cpp] viewplaincopy
1.if ( !
USB2COM_CanAcceptIoRequests( DeviceObject ) ) {
2. ntStatus = STATUS_DELETE_PENDING;
3.
4.USB2COM_KdPrint( DBGLVL_DEFAULT,("ABORTING USB2COM_Create\n"));
5. goto done;
6. }
在以下的条件不能接收一个新的IO(判断的标志是我们自己标记的):
1)设备已经被移除了,
2)从来没有被启动过,,
3)已经停止了,
4)有一个移除的请求还没处理,
5)有一个停止的请求还没处理。
[cpp] viewplaincopy
1.//flag set when processing IRP_MN_REMOVE_DEVICE
2. if ( !
deviceExtension->DeviceRemoved &&
3. // device must be started( enabled )
4. deviceExtension->DeviceStarted &&
5. // flag set when driver has answered success to IRP_MN_QUERY_REMOVE_DEVICE
6. !
deviceExtension->RemoveDeviceRequested &&
7. // flag set when driver has answered success to IRP_MN_QUERY_STOP_DEVICE
8. !
deviceExtension->StopDeviceRequested ){
9. fCan = TRUE;
10. }
步二:
开始从interface中的Pipe[0]中读(说明Interface的获取是在之前就完成的,是在USB2COM_ProcessPnPIrp
里caseIRP_MN_START_DEVICE:
完成的)
[cpp] viewplaincopy
1.StartReadIntUrb(
2. DeviceObject,
3. &interface->Pipes[0]
4. );
(1)如果判断现在不能接收IO请求,那么就记录在extension中的IRP置为完成状态,然后返回;
(2)分配IRP、URB空间,并存到Extension->ReadIntUrbs数组中,再把Pipe句柄、Buffer、传送标志填入到URB结构体成员;
[cpp] viewplaincopy
1.irp = IoAllocateIrp(stackSize, FALSE);
2. if(irp == NULL)
3. {
4. return STATUS_INSUFFICIENT_RESOURCES;
5. }
6. urb = USB2COM_ExAllocatePool(NonPagedPool,
7. sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER));
8. if(urb == NULL)
9. {
10. IoFreeIrp(irp);
11. return STATUS_INSUFFICIENT_RESOURCES;
12. }
13. deviceExtension->ReadIntUrbs[i].Irp = irp;
14. deviceExtension->ReadIntUrbs[i].Urb = urb;
15. deviceExtensi
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- USB 串口 驱动 代码 分析