Khi bạn gọiHidRegisterMinidriver, HIDCLASS cài đặt chức năng riêng của mình trong trỏDRIVER_OBJECT của bạn, cũng giống như hầu hết các lớp học sẽ trình điều khiển.Thay vì sử dụng một bộ
Trang 1Những điều khiển nhỏ
HIDCLASS (HIDCLASS
Minidrivers)
Bởi:
Khoa CNTT ĐHSP KT Hưng Yên
Như trước đây đã thảo luận, Microsoft đã cung cấp một trình điều khiển (HIDUSB.SYS)cho bất kỳ thiết bị USB được xây dựng theo HID đặc điểm kỹ thuật Phần này mô tảcách bạn có thể xây dựng một HIDCLASS minidriver cho một số các loại điện thoại màbạn muốn có masquerade như HID
DriverEntry DriverEntry các chức năng cho một HIDCLASS minidriver là tương tự
để rằng trong một trình điều khiển WDM thường xuyên, nhưng chỉ lên đến mộtđiểm Trong thói quen này, bạn khởi tạo các DRIVER_OB ¬ JECT cấu trúc dữ liệuvới kết đến AddDevice và DriverUnload thói quen cũng như để dispatch thói quencho chỉ cần ba loại I / O yêu cầu gói (IRP): IRP_MJ_PNP, IRP_MJ_POWER, vàIRP_MJ_INTERNAL_DEVICE_CON ¬ TROL Sau đó, bạn xây dựng một cơ cấuHID_MINIDRIVER_REGISTRATION và gọi HidRegister ¬ ¬ Mini driver, đó là mộttrong những chức năng xuất khẩu do HIDCLASS.SYS Bảng 13-2 mô tả các lĩnh vựctrong HID_MINIDRIVER_REGI ¬ STRATION cơ cấu
Bảng 13-2 Lĩnh vực trong HID_MINIDRIVER_REGISTRATION Cơ cấu tổ chức Têntrường Mô tả
Revision (ULONG) Minidriver bộ lĩnh vực này để HID_REVISION, mà hiện nay bằng
1 DriverObject (PDRIVER_OBJECT) Minidriver bộ lĩnh vực này cho cùng một giá trịnhư thông qua các đối số DriverObject để DriverEntry
RegistryPath (PUNICODE_STRING) Minidriver bộ lĩnh vực này cho cùng một giá trịnhư thông qua các đối số RegistryPath để DriverEntry
DeviceExtensionSize (ULONG) Kích thước trong byte của điện thoại mở rộng cơ cấu
sử dụng bởi các minidriver
Trang 2DevicesArePolled (BOOLEAN) TRUE nếu minidriver của các thiết bị cần phải đượchỏi cho các báo cáo FALSE nếu các thiết bị spontaneously khi gửi báo cáo dữ liệu sẽtrở thành hiện có.
Các trường chỉ có ý nghĩa là không hoàn toàn thẳng thắn là DevicesArePolled cờ Hầuhết các thiết bị spontaneously sẽ tạo ra một bản báo cáo kết thúc bất cứ khi nào người
sử dụng, không có gì gì đó, và họ sẽ thông báo cho các máy chủ lưu trữ thông qua một
số loại gián đoạn Cho các loại điện thoại này, bạn thiết lập các DevicesArePolled cờ đểFALSE HIDCLASS sau đó sẽ cố gắng để giữ hai IRPs (gọi là ping-pong IRPs) đanghoạt động để đọc báo cáo Minidriver mong muốn của bạn là để xếp hàng và hoàn tấtcác IRPs họ trong đặt hàng khi điện thoại interrupts
Một số thiết bị không spontaneously tạo ra các báo cáo Đối với các loại thiết bị, thiếtlập các DevicesArePolled cờ để TRUE HIDCLASS sau đó sẽ vấn đề IRPs để đọc báocáo trong một thời gian loop Minidriver của bạn đọc báo cáo dữ liệu từ điện thoại chỉ đểphản ứng lại mỗi IRP Ở cấp cao hơn các thành phần, chẳng hạn như một ứng dụng bằngcách sử dụng giao diện DirectX, có thể chỉ định các polling chuyến Nghĩ rằng hai lầntrước khi cài đặt để DevicesArePolled TRUE: hầu hết các thiết bị cần thiết để nó đượcFALSE Đây là ví dụ gần hoàn thành của DriverEntry chức năng trong một HIDCLASSminidriver:
extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject,
Trang 3Driver gọi lại thói quen
HIDCLASS hoạt động cũng như cách này, nhưng với một twist Khi bạn gọiHidRegisterMinidriver, HIDCLASS cài đặt chức năng riêng của mình trong trỏDRIVER_OBJECT của bạn, cũng giống như hầu hết các lớp học sẽ trình điều khiển.Thay vì sử dụng một bộ ¬ có thói quen gọi địa chỉ của bạn minidriver cung cấp trongHID_MINI ¬ DRIVER_REGISTRATION cơ cấu (không có), nó ghi nhớ các thiết bị
và Thêm vào ¬ DriverUnload trỏ và địa chỉ của bạn dispatch thói quen cho PNP, lực,
và yêu cầu INTERNAL_DEVICE_CONTROL Những thói quen nhỏ ¬ driver không
có chính xác cùng một chức năng như đặt tên như-thói quen thường xuyên trong WDMtrình điều khiển, mặc dù Tôi sẽ giải thích trong phần này như thế nào để viết gọi lạinhững thói quen AddDevice goüi
Các AddDevice gọi trong một HIDCLASS minidriver có một tiên tương tự để màAddDevice thường xuyên của một chức năng:
NTSTATUS AddDevice (PDRIVER_OBJECT DriverObject, PDEVICE_OBJECTfdo); Có hai khác biệt quan trọng giữa các minidriver gọi thường xuyên và các chứcnăng:
• Các thiết bị đối tượng luận đề cập đến một chức năng điện thoại đối tượng (FDO) màHIDCLASS đã tạo ra
Vấn đề khác để ý thức của FDO đó là con trỏ DeviceExtension là địa chỉ của một cấutrúc mở rộng điều đó là bí mật đối với HIDCLASS Vài thành viên đầu tiên của điều đócấu trúc riêng được vẽ bản đồ bởi cấu trúc HID_DEVICE_EXTENSION trong DDK:typedef struct _HID_DEVICE_EXTENSION {
PDEVICE_OBJECT PhysicalDeviceObject;
Trang 4PVOID MiniDeviceExtension;
} HID_DEVICE_EXTENSION, *PHID_DEVICE_EXTENSION;
Để tìm thấy thiết bị mở rộng của các bạn, bạn phải đi theo sau dây chuyền con trỏ này:
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) ((PHID_DEVICE_EXTENSION)(fdo->DeviceExtension))->MiniDeviceExtension;
Bạn sử dụng công trình tương tự để có được những PDO địa chỉ và để có được những
gì tôi gọi cho LowerDeviceObject trong cuốn sách này (HIDCLASS cuộc gọi đó là một
NextDeviceObject.) Là một lười typist, tôi thường xác định macros để làm cho cuộc
sống của tôi dễ dàng hơn trong khi tôi đang viết minidriver:
#define PDX(fdo) ((PDEVICE_EXTENSION) ((PHID_DEVICE_EXTENSION) \
Bằng cách sử dụng các macros và trước fragment của một DEVICE_EXTENSION cơ
cấu, của bạn minidriver's AddDevice gọi có thể hình như thế này:
NTSTATUS AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT fdo)
{
PDEVICE_EXTENSION pdx = PDX(fdo);
NTSTATUS status = STATUS_SUCCESS;
<initialization code for DEVICE_EXTENSION members>
pdx->AddDeviceStatus = status; // <== whatever is left over
return status; // in case you're running in >= XP
Trang 5Có hai trường hợp ngoại lệ:
• IRP_MN_START_DEVICE handler nhu cầu của bạn để kiểm tra lỗi bằng cách đặt
cờ của bạn AddDevice gọi (tôi gọi là nó AddDeviceStatus trong sớm hơn fragment) và
để thất bại trong IRP nếu cờ cho biết một lỗi Đây là cách bạn đối phó với thực tế lànhững HIDCLASS không màng biết các mã từ AddDevice trở lại trong phiên bản củaWindows trước khi Windows XP
• IRP_MN_REMOVE_DEVICE handler của bạn không gọi IoDetach ¬ thiết bị hayIoDeleteDevice Thay vào đó, nó phải chỉ đơn giản phát hành bất kỳ nguồn tài nguyên
đã được phân bố bởi các AddDevice gọi HIDCLASS chính nó sẽ chăm sóc detaching
và xóa các FDO
Các mẫu HIDFAKE driver sử dụng GENERIC.SYS DispatchPnp thói quen của nó do
đó trông như thế này:
NTSTATUS DispatchPnp(PDEVICE_OBJECT fdo, PIRP Irp)
VOID RemoveDevice(PDEVICE_OBJECT fdo)
{
}
Trang 6và như vậy trên) phân bố ở AddDevice HIDFAKE không có nguồn tài nguyên như vậy.
B Định cấu hình các thiết bị như thảo luận trong chương trước HIDFAKE không cóphần cứng và do đó đã không có gì để làm trong bước này
C Deconfigure điện thoại do reversing các bước thực hiện trong StartDevice Kể từHIDFAKE không có gì, không có gì trong StartDevice, nó không cần phải làm bất cứđiều gì ở đây cả hai
DispatchPower goüi
Bạn chỉ rõ DispatchPower gọi như nếu nó là những thói quen cho dispatchIRP_MJ_POWER, bằng cách đặt một yếu tố trong mảng, driver của đối tượngMajorFunction bảng HIDCLASS cuộc gọi của bạn gọi như là một subroutine trong khi
xử lý IRPs quyền lực của nhiều loại Trong đa số trường hợp, bạn nên chỉ cần gọi qua cácIRP xuống để tiếp theo bằng driver mà không thực hiện bất kỳ hành động vì HIDCLASS
có tất cả các quản lý nguồn điện hỗ trợ cần thiết do các thiết bị tiêu biểu (bao gồm cảWAIT_WAKE hỗ trợ)
Trang 7Nếu bạn đã đặt ra DevicesArePolled cờ để FALSE trong cuộc gọi của quý vị đểHidRegisterMinidriver, HIDCLASS sẽ hủy bỏ các ping-pong IRPs trước khi chuyểntiếp một máy điện yêu cầu làm giảm sức mạnh Nếu bạn có một cách đơn giảnpiggybacked trên những IRPs để gửi yêu cầu thêm xuống PnP stack, do đó bạn sẽ khôngcần phải lo lắng về việc huỷ bỏ chúng Nếu bạn có bộ nhớ đệm IRPs đến những nơi nào,bạn nên cung cấp cho hủy bỏ một thói quen.
Chú thích:
Nếu bạn minidriver sử dụng GENERIC.SYS, cân nhắc việc sử dụng cácGenericCacheControlRequest và GenericUncacheControlRequest chức năng để theodõi IRPs rằng bạn pend Các chức năng này bao gồm các chủng tộc-an toàn hủy bỏ logic.Đây là một ví dụ của callback DispatchPower trong một HIDCLASS minidriver:
NTSTATUS DispatchPower(PDEVICE_OBJECT fdo, PIRP Irp)
Trang 8else if (pdx->devpower == PowerDeviceD0)
2 Khi khôi phục lại quyền lực, bạn cài đặt một thói quen hoàn tất trước khi
chuyển tiếp các IRP xuống stack
3 Khi xoá bỏ quyền lực, bạn tiết kiệm bối cảnh bất kỳ thông tin trước khi chuyểntiếp các IRP Để đối phó với những khả năng có thể thấp hơn HIDCLASS rằngsức mạnh trong bước (ví dụ, lần đầu tiên sau D2 và D3), bạn cũng cần phảitheo dõi của các thiết bị hiện quyền lực nhà nước Hay không điện thoại củabạn có bối cảnh thông tin để tiết kiệm, điều này cũng là thời gian để hủy bỏ bất
kỳ chi nhánh IRPs rằng driver của bạn đã ban hành, chấm dứt polling threads,and so on HIDCLASS bạn sẽ được gọi điện thoại tại khách sạn
PASSIVE_LEVEL trong một hệ thống sợi rằng bạn đang được cho phép đểchặn nếu cần thiết trong khi thực hiện các nhiệm vụ
Trang 94 Như thường lệ, bạn gọi PoCallDriver để chuyển tiếp các IRP Bạn không cầnphải gọi PoStartNextPowerIrp vì HIDCLASS đã làm như vậy.
5 Các thường được gọi là hoàn thành chỉ sau khi hoàn thành một tài xế xe buýtĐặt-D0 hoạt động Điện thoại của bạn đã được repowered, và bạn có thể đảongược các bước bạn thực hiện khi bạn xoá bỏ quyền lực Kể từ khi bạn đang cókhả năng chạy từ DISPATCH_LEVEL và trong một sợi arbitrary, tuy nhiên,bạn cần phải thực hiện các bước sau mà không ngăn chặn hiện nay sợi
DispatchInternalControl goüi
Bạn chỉ rõ DispatchInternalControl gọi như nếu nó là những thói quen cho dispatchIRP_MJ_INTERNAL_DEVICE_CONTROL, bằng cách đặt một yếu tố trong mảng,driver của đối tượng MajorFunction bảng HIDCLASS cuộc gọi của bạn như là một thóiquen gọi subroutine để được báo cáo và các thông tin khác hoặc để cung cấp hướng dẫn
để minidriver của bạn Bạn có thể gọi chương trình này như thể nó là một thói quen bìnhthường IRP dispatch xử lý sự kiểm soát mã số liệt kê trong bảng 13-3
Bảng 13-3 HIDCLASS Minidriver kiểm soát hoạt động
Mô tả kiểm soát nội bộ Mã số
IOCTL_GET_PHYSICAL_DESCRIPTOR Gets USB-tiêu chuẩn vật chất descriptor
IOCTL_HID_GET_DEVICE_ATTRIBUTES trả lại thông tin về các thiết bị như thể nó
IOCTL_HID_WRITE_REPORT về một báo cáo
Nội IOCTL giao diện
Các giao diện giữa HIDCLASS và một minidriver là thông qua cácDispatchInternalControl gọi tổng kết ở cuối của phần trước ngày gọi thói quen Trongphần này, tôi sẽ mô tả làm thế nào để thực hiện mỗi phòng trong số hoạt động kiểmsoát, theo thứ tự trong đó HIDCLASS bình thủ tục bày cho họ Lưu ý rằng HIDCLASS
Trang 10không gọi này cho đến khi gọi tại tất cả các minidriver sau khi hoàn thành mộtIRP_MN_START_DEVICE yêu cầu.
IOCTL_HID_GET_DEVICE_ATTRIBUTES HIDCLASS gửi một yêu cầuIOCTL_HID_GET_DEVICE_ATTRIBUTES là một phần của các chế biến củaIRP_MN_START_DEVICE yêu cầu và conceivably, vào những thời gian khác, để cóđược thông tin rằng một thiết bị USB các bản ghi trong một loạt các thiết bị descriptor.UserBuffer các lĩnh vực của IRP điểm đến một dụ sau đây của các cơ cấu, mà bạn nênhoàn tất:
typedef struct _HID_DEVICE_ATTRIBUTES {
Trang 11có tư vấn về việc làm thế nào để chọn những giá trị.
Mở ra một bộ sưu tập giấu trong chế độ Thành viên
Mở ra một bộ sưu tập HID xử lý các thành viên trong chế độ chính nó là đơngiản nếu bạn chỉ định duy nhất giá trị cho các VendorID và ProductID lĩnh vựccủa HID_DEVICE_ATTRIBUTES cơ cấu Giả, ví dụ, các công ty của bạn sở hữuUSB bán hàng rong ID 0x1234 và rằng bạn đã được giao cho 0x5678 ID sản phẩmđiện thoại của bạn Bạn sẽ sử dụng những giá trị khi trả lời câuIOCTL_HID_GET_DEVICE_ATTRIBUTES yêu cầu
MFC là một ứng dụng sử dụng các lớp học CDeviceList đề cập đến trong Chương 2 cóthể mở ra một để xử lý một trong những bộ sưu tập driver của bạn bằng cách tiếp xúcvới các mã như sau đây (xem các chương trình TEST HIDFAKE mẫu đi kèm với trìnhđiều khiển):
HANDLE CtestDlg::FindFakeDevice()
{
Trang 12GUID hidguid;
HidD_GetHidGuid(&hidguid);
CDeviceList devlist(hidguid);
int ndevices = devlist.Initialize();
for (int i = 0; i < ndevices; ++i)
HIDD_ATTRIBUTES attr = {sizeof(HIDD_ATTRIBUTES)};
BOOLEAN okay = HidD_GetAttributes(h, &attr);
Trang 13xử lý để có thể không thực sự có thể truy cập được với một bình thường mở
4 HidD_GetAttributes trở về một thuộc tính cơ cấu thu được từ các
HID_DEVICE_ATTRIBUTES điền vào bởi các minidriver
5 Đây là tuyên bố quan trọng trong ví dụ này Nếu điện thoại và ID sản phẩm phùhợp với những gì chúng tôi đang tìm kiếm, chúng tôi sẽ bỏ thuốc lá quét cácthiết bị và mở một thực tế để xử lý một này
6 Điều này sẽ mở ra cuộc gọi đến CreateFile độc quyền, nonoverlapped xử lý chođọc và viết Đây là quyền hành động cho các thử nghiệm của HIDFAKE dụng
để thực hiện Bạn có thể chia sẻ cho các yêu cầu khác nhau, quyền truy cập,chồng chéo và I / O Lưu ý rằng các cuộc gọi đến CreateFile có thể bị thất bại,thậm chí nếu trước đó một thành công, nếu có một ứng dụng khác, để mở snucktrong một xử lý
Ứng dụng của bạn có thể tìm hiểu thêm phức tạp, nếu điện thoại của bạn có nhiều hơnmột cấp đầu thu thập hoặc nếu bạn cần phải cung cấp cho nhiều hơn một dụ của phầncứng của bạn
HIDCLASS gửi một yêu cầu IOCTL_HID_GET_DEVICE_DESCRIPTOR là một phầncủa các chế biến của IRP_MN_START_DEVICE yêu cầu và conceivably, vào nhữngthời gian khác, để có được một mô tả của điện thoại của HID đặc điểm UserBuffer cáclĩnh vực của IRP điểm đến một dụ của một tiêu chuẩn USB-HID descriptor cơ cấu, màbạn nên hoàn tất:
typedef struct _HID_DESCRIPTOR {
UCHAR bLength;
UCHAR bDescriptorType;
Trang 14Công việc của bạn trong minidriver là để điền trong cơ cấu descriptor như nếu bạn làmột USB-HID thiết bị tiêu chuẩn Ví dụ:
Trang 15Các chỉ khía cạnh của mã này là không có được từ một trong cùng một điều khiển
để tiếp theo là chiều dài bạn chỉ định cho các wReportLength thành viên của đơnDescriptorList mục mà bạn cung cấp Giá trị này nên là chiều dài nào thực sự haydummy báo cáo descriptor bạn sẽ cung cấp, đáp ứng yêu cầuIOCTL_HID_GET_REPORT_DESCRIPTOR
Chú thích:
HIDCLASS gửi một yêu cầu IOCTL_HID_GET_REPORT_DESCRIPTOR là mộtphần của các chế biến của IRP_MN_START_DEVICE yêu cầu và conceivably, vàonhững thời gian khác, để có được một USB-HID tiêu chuẩn báo cáo descriptor.UserBuffer các lĩnh vực của IRP điểm đến như là một buffer lớn như bạn chỉ định sẽ làcần thiết để trả lời của bạn trong một IOCTL_HID_GET_DEVICE_DESCRIPTOR yêucầu
Giả sử bạn có một dữ liệu tĩnh khu vực có tên ReportDescriptor có chứa một báo cáodescriptor ở định dạng chuẩn Bạn có thể xử lý yêu cầu này theo cách này:
case IOCTL_HID_GET_REPORT_DESCRIPTOR:
{
if (cbout < sizeof(ReportDescriptor))
Trang 16đề tập tin, như thế này một (tương ứng với các descriptor hiển thị trong Hình 13-3):char ReportDescriptor[64] = {
0x05, 0x05, // USAGE_PAGE (Gaming Controls)
0x09, 0x03, // USAGE (Gun Device )
0xa1, 0x01, // COLLECTION (Application)
0xa1, 0x02, // COLLECTION (Logical)
0x85, 0x01, // REPORT_ID (1)
0x05, 0x09, // USAGE_PAGE (Button)
0x09, 0x01, // USAGE (Button 1)
0x15, 0x00, // LOGICAL_MINIMUM (0)
Trang 18có được một nguyên HID báo cáo HIDCLASS sử dụng nguyên liệu để báo cáoIRP_MJ_READ và IOCTL_HID_GET_INPUT_REPORT đáp ứng yêu cầu phát hànhcho nó từ ở cấp cao hơn các thành phần, bao gồm cả người sử dụng chế độ ứng dụng
mà gọi ReadFile, HidD_GetInputReport, IDirectInputDevice8: GetDeviceData, hoặcIDirectInputDevice8:: Thăm dò ý kiến
Một minidriver có thể là nhân viên của bất kỳ của một số chiến lược để cung cấp cácbáo cáo: • Nếu điện thoại của bạn là một lập trình I / O (Pio) loại điện thoại gắn bó vớitruyền thống xe buýt như phần ngoại vi Interconnect (PCI), có lẽ bạn có thể thực hiệnphần cứng abstraction layer (HAL) chức năng cho các cuộc gọi derive cấu trúc dữ liệucho một báo cáo Bạn sẽ ngay lập tức sau đó hoàn thành IOCTL_HID_READ_REPORTyêu cầu
• Nếu điện thoại của bạn gắn với một truyền thống của các tuyến xe buýt và sử dụng mộtphần cứng gián đoạn để thông báo cho các máy chủ lưu trữ dữ liệu báo cáo khi có sẵn,bạn cần phải thực hiện một chương trình, đáp ứng yêu cầu với các báo cáo khi chúng trởnên sẵn có Interlocked bằng cách sử dụng một danh sách cho phép bạn đọc và lưu dữliệu báo cáo trong một gián đoạn dịch vụ thông thường (ISR) Các chương trình sẽ yêucầu của bạn ISR để xếp hàng chậm là một thủ tục gọi (DPC), sau đó mà có thể đọc vàlưu dữ liệu báo cáo
• Nếu điện thoại của bạn là một nonstandard thiết bị USB, có lẽ bạn có thể gửi đimột Urb derive dữ liệu để từ đó bạn có thể soạn một cấu trúc ¬ báo cáo Bạn có thểpiggyback các Urb IOCTL_HID_READ_REPORT trên điện thoại của bạn, nếu yêu cầucủa nguyên liệu báo cáo, không có báo cáo lớn hơn HIDCLASS là mong Trong trườnghợp này, bạn sẽ presumably dispatch thường lệ phân bổ bộ nhớ cho Urb từ nonpaged bộnhớ, cài đặt một hoàn thành thói quen, và chuyển IRP xuống PnP stack với cổng USBtrên bus driver Hoàn thành thói quen của bạn sẽ miễn phí trong Urb, reformat báo cáo
dữ liệu và thiết lập IoStatus.Information bằng kích cỡ của reformatted báo cáo, và trở lạiSTATUS_SUCCESS để cho phép các IRP để hoàn thành