Chương trình Thư viện Học liệu Mở Việt Nam (Vietnam Open Educational Resources
– VOER) được hỗ trợ bởi Quỹ Việt Nam. Mục tiêu của chương trình là xây dựng kho
Tài nguyên giáo dục Mở miễn phí của người Việt và cho người Việt, có nội dung phong
phú. Các nội dung đểu tuân thủ Giấy phép Creative Commons Attribution (CC-by) 4.0
do đó các nội dung đều có thể được sử dụng, tái sử dụng và truy nhập miễn phí trước
hết trong trong môi trường giảng dạy, học tập và nghiên cứu sau đó cho toàn xã hội.
Với sự hỗ trợ của Quỹ Việt Nam, Thư viện Học liệu Mở Việt Nam (VOER) đã trở thành
một cổng thông tin chính cho các sinh viên và giảng viên trong và ngoài Việt Nam. Mỗi
ngày có hàng chục nghìn lượt truy cập VOER (www.voer.edu.vn) để nghiên cứu, học
tập và tải tài liệu giảng dạy về. Với hàng chục nghìn module kiến thức từ hàng nghìn
tác giả khác nhau đóng góp, Thư Viện Học liệu Mở Việt Nam là một kho tàng tài liệu
khổng lồ, nội dung phong phú phục vụ cho tất cả các nhu cầu học tập, nghiên cứu của
độc giả.
371 trang |
Chia sẻ: nguyenlam99 | Lượt xem: 1168 | Lượt tải: 0
Bạn đang xem trước 20 trang tài liệu Giáo trình môn Lập trình hệ thống, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
ong thói quen này, bạn khởi tạo các DRIVER_OB ¬ JECT cấu trúc dữ liệu
với kết đến AddDevice và DriverUnload thói quen cũng như để dispatch thói quen
cho 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ấu
HID_MINIDRIVER_REGISTRATION và gọi HidRegister ¬ ¬ Mini driver, đó là một
trong những chức năng xuất khẩu do HIDCLASS.SYS. Bảng 13-2 mô tả các lĩnh vực
trong 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ên
trườ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.
DevicesArePolled (BOOLEAN) TRUE nếu minidriver của các thiết bị cần phải được
hỏ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ầu
hế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) đang
hoạt động để đọc báo cáo. Minidriver mong muốn của bạn là để xếp hàng và hoàn tất
các IRPs họ trong đặt hàng khi điện thoại interrupts.
326/369
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ết
lập các DevicesArePolled cờ để TRUE. HIDCLASS sau đó sẽ vấn đề IRPs để đọc báo
cá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ằng
cách sử dụng giao diện DirectX, có thể chỉ định các polling chuyến. Nghĩ rằng hai lần
trước khi cài đặt để DevicesArePolled TRUE: hầu hết các thiết bị cần thiết để nó được
FALSE. Đây là ví dụ gần hoàn thành của DriverEntry chức năng trong một HIDCLASS
minidriver:
extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject,
PUNICODE_STRING RegistryPath)
{
DriverObject->DriverExtension->AddDevice = AddDevice;
DriverObject->DriverUnload = DriverUnload;
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
DispatchInternalControl;
DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp;
DriverObject->MajorFunction[IRP_MJ_POWER] = DispatchPower;
HID_MINIDRIVER_REGISTRATION reg;
RtlZeroMemory(®, sizeof(reg));
reg.Revision = HID_REVISION;
reg.DriverObject = DriverObject;
reg.RegistryPath = RegistryPath;
reg.DeviceExtensionSize = sizeof(DEVICE_EXTENSION);
reg.DevicesArePolled = FALSE; // <== depends on your hardware
return HidRegisterMinidriver(®);
}
327/369
Driver 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ọi
HidRegisterMinidriver, 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 trong
HID_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 WDM
trì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ại
nhữ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_OBJECT
fdo); Có hai khác biệt quan trọng giữa các minidriver gọi thường xuyên và các chức
nă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ấu
trú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;
PDEVICE_OBJECT NextDeviceObject;
PVOID 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;
328/369
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) \
((fdo)->DeviceExtension))->MiniDeviceExtension)
#define PDO(fdo) (((PHID_DEVICE_EXTENSION) ((fdo)->DeviceExtension)) \
->PhysicalDeviceObject)
#define LDO(fdo) (((PHID_DEVICE_EXTENSION) ((fdo)->DeviceExtension)) \
->NextDeviceObject)
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;
pdx->AddDeviceStatus = status; // <== whatever is left over
return status; // in case you're running in >= XP
}
Điểm lại một thực tế tình trạng mã từ AddDevice là trong Windows XP và các hệ thống
sau này, HIDCLASS sẽ không thành công riêng của mình AddDevice gọi nếu bạn làm
gì, và đó sẽ ngắn mạch các sở khởi của điện thoại của bạn. Nhưng kể từ khi HIDCLASS
không màng biết mã trong các phiên bản cũ của hệ điều hành, bạn cần phải cung cấp
một cách cho StartDevice chức năng của bạn để trở về một mã lỗi.
Có hai trường hợp ngoại lệ:
329/369
• 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ủa
Windows trước khi Windows XP.
• IRP_MN_REMOVE_DEVICE handler của bạn không gọi IoDetach ¬ thiết bị hay
IoDeleteDevice. 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)
{
return GenericDispatchPnp(PDX(fdo)->pgx, Irp);
}
Ngoài bằng cách sử dụng PDX vĩ mô để xác định vị trí của thiết bị mở rộng cơ cấu, mã
này cũng giống như sẽ xuất hiện trong một chức năng thường xuyên sử dụng trình điều
khiển GENERIC.SYS. Các RemoveDevice, StartDevice, và StopDevice đang có chức
năng khác nhau từ những người thân thường xuyên, mặc dù:
VOID RemoveDevice(PDEVICE_OBJECT fdo)
{
}
NTSTATUS StartDevice(PDEVICE_OBJECT fdo,
PCM_PARTIAL_RESOURCE_LIST raw,
PCM_PARTIAL_RESOURCE_LIST translated)
{
PDEVICE_EXTENSION pdx = PDX(fdo);
if (!NT_SUCCESS(pdx->AddDeviceStatus))
330/369
return pdx->AddDeviceStatus;
return STATUS_SUCCESS;
}
VOID StopDevice(PDEVICE_OBJECT fdo, BOOLEAN oktouch)
{
}
HIDFAKE chính nó không có mã số tại các điểm có nhãn A, B, và C. Nếu bạn sử dụng
mẫu này như là một mẫu cho minidriver riêng của bạn, bạn sẽ viết mã để thực hiện như
sau: A. Xóa các bất kỳ nguồn tài nguyên (chẳng hạn như bộ nhớ, lookaside danh sách,
và 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 dispatch
IRP_MJ_POWER, 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 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ác
IRP 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ợ).
Nế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ển
tiế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ản
piggybacked trên những IRPs để gửi yêu cầu thêm xuống PnP stack, do đó bạn sẽ không
cầ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:
331/369
Nếu bạn minidriver sử dụng GENERIC.SYS, cân nhắc việc sử dụng các
GenericCacheControlRequest và GenericUncacheControlRequest chức năng để theo
dõ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)
{
PDEVICE_EXTENSION pdx = PDX(fdo);
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
IoCopyCurrentIrpStackLocationToNext(Irp);
if (stack->MinorFunction == IRP_MN_SET_POWER
&& stack->Parameters.Power.Type == DevicePowerState)
{
DEVICE_POWER_STATE newstate =
stack->Parameters.Power.State.DeviceState;
if (newstate == PowerDeviceD0)
{
IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE)
PowerUpCompletionRoutine, (PVOID) pdx, TRUE, TRUE, TRUE);
}
else if (pdx->devpower == PowerDeviceD0)
{
// TODO save context information, if any
pdx->devpower = newstate;
}
332/369
}return PoCallDriver(LDO(fdo), Irp);
}
NTSTATUS PowerUpCompletionRoutine(PDEVICE_OBJECT fdo, PIRP Irp,
PDEVICE_EXTENSION pdx)
{
// TODO restore device context without blocking this thread
pdx->devpower = PowerDeviceD0;
return STATUS_SUCCESS;
}
1. Bạn không cần phải làm bất cứ điều gì đặc biệt với bất kỳ quyền lực IRP ngoại
trừ một SET_POWER cho một thiết bị quyền lực nhà nước.
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ển
tiếp các IRP. Để đối phó với những khả năng có thể thấp hơn HIDCLASS rằng
sức mạnh trong bước (ví dụ, lần đầu tiên sau D2 và D3), bạn cũng cần phải
theo 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ủa
bạ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ụ.
4. Như thường lệ, bạn gọi PoCallDriver để chuyển tiếp các IRP. Bạn không cần
phả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ể đảo
ngượ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 dispatch
IRP_MJ_INTERNAL_DEVICE_CONTROL, bằng cách đặt một yếu tố trong mảng,
333/369
driver của đối tượng MajorFunction bảng. HIDCLASS cuộc gọi của bạn như là một thói
quen 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ình
thườ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ó
là USB
IOCTL_HID_GET_DEVICE_DESCRIPTOR trả lại một tiêu chuẩn USB-HID
descriptor IOCTL_HID_GET_FEATURE lần đọc một tính năng báo cáo
IOCTL_HID_GET_INDEXED_STRING trả lại một tiêu chuẩn USB-string descriptor
IOCTL_HID_GET_STRING trả lại một tiêu chuẩn USB-string descriptor
IOCTL_HID_GET_REPORT_DESCRIPTOR trả lại một báo cáo tiêu chuẩn-USB
descriptor Có IOCTL_HID_READ_REPORT lần đọc báo cáo conforming để báo cáo
descriptor IOCTL_HID_SEND_IDLE_NOTIFICATION Idles điện thoại (mới trong
Windows XP) IOCTL_HID_SET_FEATURE về một tính năng báo cáo
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ác
DispatchInternalControl gọi tổng kết ở cuối của phần trước ngày gọi thói quen. Trong
phầ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ểm
soát, theo thứ tự trong đó HIDCLASS bình thủ tục bày cho họ. Lưu ý rằng HIDCLASS
khô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ột
IRP_MN_START_DEVICE yêu cầu.
IOCTL_HID_GET_DEVICE_ATTRIBUTES HIDCLASS gửi một yêu cầu
IOCTL_HID_GET_DEVICE_ATTRIBUTES là một phần của các chế biến của
IRP_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ên
hoàn tất:
typedef struct _HID_DEVICE_ATTRIBUTES {
334/369
ULONG Size;
USHORT VendorID;
USHORT ProductID;
USHORT VersionNumber;
USHORT Reserved[11];
} HID_DEVICE_ATTRIBUTES, * PHID_DEVICE_ATTRIBUTES;
Ví dụ, bạn có thể hoàn tất các cơ cấu trong bối cảnh của các skeletal
DispatchInternalControl hiển thị sớm hơn thường lệ:
case IOCTL_HID_GET_DEVICE_ATTRIBUTES:
{
if (cbout < sizeof(HID_DEVICE_ATTRIBUTES))
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
#define p ((PHID_DEVICE_ATTRIBUTES) buffer)
RtlZeroMemory(p, sizeof(HID_DEVICE_ATTRIBUTES));
p->Size = sizeof(HID_DEVICE_ATTRIBUTES);
p->VendorID = 0;
p->ProductID = 0;
p->VersionNumber = 1;
#undef p
info = sizeof(HID_DEVICE_ATTRIBUTES);
335/369
break;
}
Nếu điện thoại của bạn là nonstandard chỉ đơn giản là một thiết bị USB, điều đó rõ ràng
các giá trị mà bạn nên cung cấp cho các VendorID, ProductID, và VersionNumber lĩnh
vực này cơ cấu: các idVendor, idProduct, bcdDevice lĩnh vực và thực sự từ điện thoại
descriptor. Nếu điện thoại của bạn isn'ta thiết bị USB, bạn cần phải đi lên với dummy
giá trị. Tôi đã sử dụng 0, 0, và 1, tương ứng, trong mã này fragment, và những sự lựa
chọn sẽ đủ cho tất cả các loại hình HID thiết bị ngoại trừ một phím điều khiển. Để có
một phím điều khiển điện thoại, bạn cần phải chọn duy nhất giá trị phù hợp với những gì
bạn chỉ định trong đăng ký subkey OEM bạn tạo ra cho các phím điều khiển. Tôi không
có 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à đơn
giản nếu bạn chỉ định duy nhất giá trị cho các VendorID và ProductID lĩnh vực
của HID_DEVICE_ATTRIBUTES cơ cấu. Giả, ví dụ, các công ty của bạn sở hữu
USB 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âu
IOCTL_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úc
vớ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()
{
GUID hidguid;
HidD_GetHidGuid(&hidguid);
CDeviceList devlist(hidguid);
int ndevices = devlist.Initialize();
for (int i = 0; i < ndevices; ++i)
{
336/369
HANDLE h = CreateFile(devlist.m_list[i].m_linkname, 0,
FILE_SHARE_READ │ FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, 0, NULL);
if (h == INVALID_HANDLE_VALUE)
continue;
HIDD_ATTRIBUTES attr = {sizeof(HIDD_ATTRIBUTES)};
BOOLEAN okay = HidD_GetAttributes(h, &attr);
CloseHandle(h);
if (!okay)
continue;
if (attr.VendorID != HIDFAKE_VID ││
attr.ProductID != HIDFAKE_PID)
continue;
return CreateFile(devlist.m_list[i].m_linkname,
GENERIC_READ │ GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, 0, NULL);
}
return INVALID_HANDLE_VALUE;
}
1. HidD_GetHidGuid sử dụng để xác định giao diện toàn cầu nhận biết duy nhất
(GUID) cho các thiết bị HID.
2. Chúng tôi enumerate tất cả các thiết bị HID. Trong thực tế, các Enumeration
không bao gồm các thiết bị tiêu chuẩn, như con chuột và bàn phím.
3. Mở ra một cách xử lý này (mà không có quyền truy cập đầy đủ quyền và cho
phép chia sẻ) cho phép chúng tôi vấn đề truy vấn. Không giống như hầu hết các
337/369
trình điều khiển thiết bị, HIDCLASS trả gần quan tâm đến quyền truy cập và
chia sẻ với IRP_MJ_CREATE thuộc tính được xác định, và chúng tôi đang lợi
dụng các tính linh hoạt mà rằng hành vi tạo ra bằng cách mở ra một một thiết bị
xử 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ác
thiế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ở snuck
trong 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ơn
mộ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ần
cứng của bạn.
HIDCLASS gửi một yêu cầu IOCTL_HID_GET_DEVICE_DESCRIPTOR là một phần
của các chế biến của IRP_MN_START_DEVICE yêu cầu và conceivably, vào những
thời gian khác, để có được một mô tả của điện thoại của HID đặc điểm. UserBuffer các
lĩ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;
USHORT bcdHID;
UCHAR bCountry;
UCHAR bNumDescriptors;
struct _HID_DESCRIPTOR_DESC_LIST {
UCHAR bReportType;
USHORT wReportLength;
338/369
} DescriptorList [1];
} HID_DESCRIPTOR, * PHID_DESCRIPTOR;
Mặc dù, rõ ràng tổng quát của cấu trúc này, hiện nay HIDCLASS trữ đầy đủ các
không gian cho chỉ có một yếu tố trong DescriptorList mảng, và nó phải được báo cáo
descriptor. Phát triển của Microsoft khuyên bạn nên kiểm tra công tác song le kích cỡ
của sản lượng buffer và sắp xếp mã của bạn để sao chép thêm nào descriptors-như là
một vật chất descriptor-rằng bạn có thể có.
Cô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ụ:
case IOCTL_HID_GET_DEVICE_DESCRIPTOR:
{
#define p ((PHID_DESCRIPTOR) buffer)
if (cbout < sizeof(HID_DESCRIPTOR))
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
RtlZeroMemory(p, sizeof(HID_DESCRIPTOR));
p->bLength = sizeof(HID_DESCRIPTOR);
p->bDescriptorType = HID_HID_DESCRIPTOR_TYPE;
p->bcdHID = HID_REVISION;
p->bCountry = 0;
p->bNumDescriptors = 1;
p->DescriptorList[0].bReportType = HID_REPORT_DESCRIPTOR_TYPE;
p->DescriptorList[0].wReportLength = sizeof(ReportDescriptor);
339/369
#undef p
info = sizeof(HID_DESCRIPTOR);
break;
}
Cá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 đơn
DescriptorList mục mà bạn cung cấp. Giá trị này nên là chiều dài nào thực sự hay
dummy báo cáo descriptor bạn sẽ cung cấp, đáp ứng yêu cầu
IOCTL_HID_GET_REPORT_DESCRIPTOR.
Chú thích:
HIDCLASS gửi một yêu cầu IOCTL_HID_GET_REPORT_DESCRIPTOR là một
phần của các chế biến của IRP_MN_START_DEVICE yêu cầu và conceivably, vào
nhữ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êu
cầ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áo
descriptor ở đị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))
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
RtlCopyMemory(buffer, ReportDescriptor,
sizeof(ReportDescriptor));
340/369
info = sizeof(ReportDescriptor);
break;
}
Bước đầu tiên của bạn trong việc xây dựng các báo cáo descriptor được thiết kế để bố
trí các báo cáo. USB HID đặc điểm kỹ thuật cho các thiết bị làm cho nó có vẻ rằng bạn
đang khá nhiều thiết kế miễn phí cho bất kỳ loại báo cáo bạn muốn, với các Windows sẽ
thực hiện rằng con số nào đó chỉ ra những gì để làm với các dữ liệu kết quả. Trong kinh
nghiệm của tôi, tuy nhiên, bạn thật sự không có đủ tự do. Một trong những lựa chọn nào
khi bạn tiết kiệm trong công việc của bạn HID Công cụ là tạo ra một C-ngôn ngữ tiêu
đề 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)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x75, 0x07, // REPORT_SIZE (7)
0x81, 0x03, // INPUT (Cnst,Var,Abs)
341/369
0xc0, // END_COLLECTION
0xa1, 0x02, // COLLECTION (Logical)
0x85, 0x02, // REPORT_ID (2)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x30, // USAGE (X)
0x25, 0xff, // LOGICAL_MAXIMUM (-1)
0x75, 0x20, // REPORT_SIZE (32)
0xb1, 0x02, // FEATURE (Data,Var,Abs)
0xc0, // END_COLLECTION
0xa1, 0x02, // COLLECTION (Logical)
0x85, 0x03, // REPORT_ID (3)
0x05, 0x09, // USAGE_PAGE (Button)
0x09, 0x01, // USAGE (Button 1)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0xb1, 0x02, // FEATURE (Data,Var,Abs)
0x75, 0x07, // REPORT_SIZE (7)
0xb1, 0x03, // FEATURE (Cnst,Var,Abs)
0xc0, // END_COLLECTION
0xc0 // END_COLLECTION
};
Bạn có thể chỉ đơn giản này bao gồm các tập tin tiêu đề của bạn trong trình điều khiển để
xác định ReportDescriptor bạn trở về từ IOCTL_HID_GET_REPORT_DESCRIPTOR.
342/369
IOCTL_HID_READ_REPORT Workhorse có IOCTL_HID_READ_REPORT các hoạt
động của một HIDCLASS mini ¬ driver. HIDCLASS vấn đề về yêu cầu này để
có được một nguyên HID báo cáo. HIDCLASS sử dụng nguyên liệu để báo cáo
IRP_MJ_READ và IOCTL_HID_GET_INPUT_REPORT đáp ứng yêu cầu phát hành
cho 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ặc
IDirectInputDevice8:: 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ác
bá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ới
truyền thống xe buýt như phần ngoại vi Interconnect (PCI), có lẽ bạn có thể thực hiện
phần cứng abstraction layer (HAL) chức năng cho các cuộc gọi derive cấu trúc dữ liệu
cho một báo cáo. Bạn sẽ ngay lập tức sau đó hoàn thành IOCTL_HID_READ_REPORT
yê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ột
phầ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êu
cầ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 đi
mộ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ầu
củ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ường
hợ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 USB
trê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ại
STATUS_SUCCESS để cho phép các IRP để hoàn thành.
• Trong vẫn còn những tình huống khác, bạn có thể cần phải pend các
IOCTL_HID_READ_REPORT yêu cầu trong khi bạn thực hiện một hoặc nhiều I / O
hoạt động để tìm nạp dữ liệu thô từ điện thoại của bạn, sau đó mà bạn mong muốn
reformat vào báo cáo gói. Với thiết kế này, bạn có các vấn đề thông thường liên kết với
bộ nhớ đệm có IOCTL_HID_READ_REPORT trỏ đến các yêu cầu trong một cách an
toàn-hủy bỏ và hủy bỏ với bất chi nhánh IRPs bạn tạo ra.
Không có vấn đề gì chương trình bạn devise, driver của bạn sẽ thực hiện việc này bằng
cách điền các IRP UserBuffer buffer với một báo cáo. Ví dụ:
343/369
case IOCTL_HID_READ_REPORT:
{
if (cbout )
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
RtlCopyMemory(buffer, , );
info = ;
break;
}
Ghi nhớ rằng nếu báo cáo của bạn descriptor bao gồm nhiều hơn một báo cáo, báo
cáo dữ liệu bạn quay trở lại HIDCLASS bắt đầu với một 1-byte báo cáo định danh.
IOCTL_HID_WRITE_REPORT HIDCLASS vấn đề IOCTL_HID_WRITE_REPORT
các yêu cầu về dịch vụ IRP_MJ_WRITE và IOCTL_HID_SET_OUTPUT_REPORT
yêu cầu cấp từ một thành phần ở cấp cao hơn, chẳng hạn như một người sử dụng-áp dụng
chế độ mà các cuộc gọi WriteFile, HidD_SetOutputReport, hoặc IDirectInputDevice8::
SendDeviceData.
Sản lượng các báo cáo thường được sử dụng để thiết lập chỉ số các loại, chẳng hạn như
LEDs và hiển thị bảng điều khiển. Công việc của bạn trong một minidriver là để truyền
tải dữ liệu báo cáo các sản lượng điện thoại hoặc đến để mô phỏng hoạt động của một
thiết bị HID nhận được một báo cáo như vậy có nghĩa là do một số. Thiết bị USB thực
hiện các lớp học cụ thể kiểm soát-ống lệnh Set_Report_Request (hoặc người nào khác
mà họ xác định một gián đoạn-out endpoint) cho sản lượng nhận được báo cáo, nhưng
kiến trúc của bạn có thể gọi cho một cách tiếp cận khác nhau.
Không giống như các hoạt động kiểm soát nội bộ HIDCLASS,
IOCTL_HID_WRITE_REPORT sử dụng METHOD_BUFFERED. Điều này có nghĩa
là các lĩnh vực AssociatedIrp.SystemBuffer của IRP chứa các địa chỉ của người sản
344/369
xuất dữ liệu và Parameters.DeviceIoControl.OutputBufferLength rằng các lĩnh vực của
IO_STACK_LOCATION chứa chiều dài của nó.
IOCTL_HID_GET_FEATURE và IOCTL_HID_SET_FEATURE
HIDCLASS các vấn đề IOCTL_HID_GET_FEATURE và IOCTL_HID_SET_FEA ¬
TURE yêu cầu để đọc hoặc viết một được gọi là tính năng báo cáo. Một ứng dụng có thể
kích hoạt các yêu cầu bằng cách gọi điện thoại HidD_GetFeature hay HidD_SetFeature,
tương ứng.
Bạn có thể nhúng tính năng báo cáo trong vòng một báo cáo descriptor. Theo nhận
định của các HID đặc điểm kỹ thuật, tính năng hữu ích cho các báo cáo có nhận
được thông tin cấu hình và cài đặt hơn là cho polling điện thoại trên một cơ sở
thường xuyên. Với một USB-tiêu chuẩn thiết bị, driver sử dụng Get_Report_Request và
Set_Report_Request lớp-lệnh cụ thể để thực hiện chức năng này. Trong minidriver cho
một số các loại thiết bị HID, bạn cần phải cung cấp một số loại analogue nếu báo cáo
của bạn descriptor bao gồm các tính năng báo cáo.
Những I / O kiểm soát (IOCTL) hoạt động cũng là một cách Microsoft muốn bạn thực
hiện các out-of-band giao tiếp giữa một ứng dụng và một HID minidriver. Ghi nhớ rằng
HIDCLASS không cho phép bất cứ ai để mở một cửa hàng để xử lý các thiết bị gốc (xử
lý có thể được mở ra chỉ để cấp cao bộ sưu tập) và không kiểm soát bất kỳ hoạt động
nonstandard rằng nó sẽ xảy ra để nhận được. Resorting mà không để sleazy phương
pháp, như là một điều mà tôi sẽ không nói bất cứ điều gì, có thật sự là không có cách
nào khác cho các ứng dụng HIDCLASS minidriver và một để giao tiếp.
Các "đầu ra" đệm cho yêu cầu này là một dụ của các cấu trúc sau đây:
typedef struct _HID_XFER_PACKET {
PUCHAR reportBuffer;
ULONG reportBufferLen;
UCHAR reportId;
} HID_XFER_PACKET, *PHID_XFER_PACKET;
HIDCLASS sử dụng cùng một cơ cấu cho cả hai GET_FEATURE và SET_FEATURE
yêu cầu, và nó đặt IRP-> UserBuffer để trỏ đến nó trong cả hai trường hợp quá. Trong
thực tế, các chỉ có sự khác biệt giữa hai yêu cầu là chiều dài của cơ cấu (một) là trong
InputBufferLength tham số cho SET_FEATURE và trong OutputBufferLength tham số
cho GET_FEATURE. (Bạn sẽ không chăm sóc ngay cả về sự khác biệt này. Kể từ
345/369
HIDCLASS là một chế độ tin cậy hạt nhân-gọi, đặc biệt là không có lý do để xác minh
độ dài của tham số này cơ cấu.)
Xử lý công việc của bạn khi một trong những yêu cầu là để decode reportId các giá trị,
mà designates một trong những tính năng hỗ trợ các báo cáo trình điều khiển của bạn.
Để có một GET_FEATURE yêu cầu, bạn nên đặt tối đa reportBufferLen byte của dữ
liệu trong reportBuffer buffer và hoàn tất các IRP với IoStatus.Information đặt thành số
byte bạn sao chép. Để có một SET_FEATURE yêu cầu, bạn nên trích reportBufferLen
byte của dữ liệu từ reportBuffer đệm.
Đây skeleton để xử lý những yêu cầu hai:
case IOCTL_HID_GET_FEATURE:
{
#define p ((PHID_XFER_PACKET) buffer)
switch (p->reportId)
{
case FEATURE_CODE_XX:
if (p->reportBufferLen < sizeof(FEATURE_REPORT_XX))
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
RtlCopyMemory(p->reportBuffer, FeatureReportXx,
sizeof(FEATURE_REPORT_XX));
info = sizeof(FEATURE_REPORT_XX);
break;
}
346/369
break;
#undef p
}
case IOCTL_HID_SET_FEATURE:
{
#define p ((PHID_XFER_PACKET) buffer)
switch (p->reportId)
{
case FEATURE_CODE_YY:
if (p->reportBufferLen > sizeof(FEATURE_REPORT_YY))
{
status = STATUS_INVALID_PARAMETER;
break;
}
RtlCopyMemory(FeatureReportYy, p->reportBuffer,
p->reportBufferLen);
break;
}
break;
#undef p
}
6.2.3. Ví dụ:
347/369
case IOCTL_GET_PHYSICAL_DESCRIPTOR:
{
if (cbout < sizeof(PhysicalDescriptor))
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
PUCHAR p =
(PUCHAR) MmGetSystemAddressForMdlSafe(Irp->MdlAddress);
if (!p)
{
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
RtlCopyMemory(p,
PhysicalDescriptor, sizeof(PhysicalDescriptor));
info = sizeof(PhysicalDescriptor);
break;
}
Lưu ý rằng IOCTL này sử dụng METHOD_OUT_DIRECT thay vì
METHOD_NEITHER.
Ngoài ra, gấu trong tâm trí bố sau trong HID đặc điểm kỹ thuật: "vật lý descriptors
là hoàn toàn tùy chọn. Họ thêm phức tạp và cung cấp rất ít trong trở lại cho hầu
hết các thiết bị. " IOCTL_HID_GET_STRING HIDCLASS gửi một
348/369
IOCTL_HID_GET_STRING, để lấy một chuỗi mô tả những nhà sản xuất, sản phẩm,
hoặc nối tiếp của một số điện thoại. Một người sử dụng-áp dụng chế độ này có thể
kích hoạt IOCTL bằng cách gọi điện thoại HidD_GetManufacturerString, HidD_Get ¬
ProductString, hoặc HidD_GetSerialNumberString. The strings tương ứng với tùy chọn
xác định bởi những dây điện thoại descriptor tiêu chuẩn của một thiết bị USB. Một tham
số đến hoạt động cho biết chuỗi mà bạn nên trở lại, và trong đó ngôn ngữ. A skeleton để
xử lý kiểm soát hoạt động này là như sau:
case IOCTL_HID_GET_STRING:
{
#define p ((PUSHORT) \
stack->Parameters.DeviceIoControl.Type3InputBuffer)
USHORT istring = p[0];
LANGID langid = p[1];
#undef p
PWCHAR string = NULL;
switch (istring)
{
case HID_STRING_ID_IMANUFACTURER:
string = ;
break;
case HID_STRING_ID_IPRODUCT:
string = ;
break;
case HID_STRING_ID_ISERIALNUMBER:
string = ;
349/369
break;
}
if (!string)
{
status = STATUS_INVALID_PARAMETER;
break;
}
ULONG lstring = wcslen(string);
if (cbout < lstring * sizeof(WCHAR))
{
status = STATUS_INVALID_BUFFER_SIZE;
break;
}
RtlCopyMemory(buffer, string, lstring * sizeof(WCHAR));
info = lstring * sizeof(WCHAR);
if (cbout >= info + sizeof(WCHAR))
{
((PWCHAR) buffer)[lstring] = UNICODE_NULL;
info += sizeof(WCHAR);
}
break;
}
350/369
Một số tin về các điểm chốt này là các mã fragment:
• Giống như hầu hết các minidriver IOCTL yêu cầu này, sử dụng một
METHOD_NEITHER. Trong bối cảnh của DispatchInternalControl gọi lại trình bày
trước, buffer là sản phẩm đệm để được đổ đầy.
• Các số sê-ri, nếu có một, nên được duy nhất cho mỗi điện thoại.
• Các minidriver nên không thành công với các yêu cầu STATUS_INVALID_PARAM
¬ ETER không hợp lệ nếu một chuỗi chỉ mục xuất hiện và STATUS_INVALID_BUF ¬
FER_SIZE nếu được cung cấp một buffer nhưng là quá nhỏ để giữ toàn bộ chuỗi. • Các
minidriver trả lại toàn bộ chuỗi hoặc không có gì. Nó là một appends null Terminator để
chuỗi nếu sản lượng buffer là đủ lớn.
The DDK không chỉ định, không có gì phải làm gì nếu được yêu cầu ngôn ngữ không
phải là một trong những điện thoại của bạn hay minidriver sẽ xảy ra để hỗ trợ. Tôi
sẽ không đề nghị với các yêu cầu STATUS_DEVICE_DATA_ERROR để bắt chước
những gì thực sự là một thiết bị USB là vụ phải làm. Tuy nhiên, nếu không được hỗ trợ
các ngôn ngữ là 0x0409 (Anh Mỹ), tôi đề nghị trả lại một chuỗi mặc định của một số
loại-¬ thậm chí có lẽ là người đầu tiên ngôn ngữ của bạn trong danh sách các ngôn ngữ
được hỗ trợ bởi vì HIDCLASS-0x0409 luôn luôn sử dụng cho các ngôn ngữ id tham số
trong Windows XP và các phiên bản cũ của hệ thống.
IOCTL_HID_GET_INDEXED_STRING HIDCLASS gửi một
IOCTL_HID_GET_INDEXED_STRING, để lấy một chuỗi có USB-tiêu chuẩn định
danh mục các ngôn ngữ và được chỉ định. Một người sử dụng-chế độ có thể kích hoạt
chương trình này IOCTL bằng cách gọi điện thoại HidD_GetIndexedString. Bạn xử lý
yêu cầu này nhiều như IOCTL_HID_GET_STRING ngoại trừ cho hai điểm:
• kiểm soát hoạt động này sử dụng một sự pha trộn kỳ lạ của hai phương pháp buffering:
các dữ liệu đầu vào chỉ mục chứa chuỗi và các ngôn ngữ id là trong stack->
Parameters.DeviceIoControl.Type3InputBuffer (như sẽ là đúng yêu cầu của một
METHOD_NEITHER), và là sản lượng buffer mô tả bởi các danh sách bộ nhớ
descriptor (MDL) tại khách sạn IRP-> MdlAddress, như sẽ là đúng yêu cầu của một
METHOD_OUT_DIRECT. • Các chuỗi chỉ mục trong thấp thứ tự 16-bit của
Type3InputBuffer-USB là một chuỗi mục các tiêu chuẩn thay vì là một ví dụ như
HID_STRING_ID_IMANUFACTURER. Mục đích của yêu cầu này là để cho phép các
ứng dụng, để lấy các chuỗi giá trị tương ứng với chuỗi Usages HID trong một báo cáo.
Thiết bị USB có thể làm cho lên đến 255 trong chuỗi giá trị có thể truy cập bằng cách
này. Với một nonstandard USB hoặc một thiết bị USB không điện thoại, minidriver nhu
cầu của bạn để cung cấp một analogue nếu các báo cáo descriptor chứa chuỗi Usages.
351/369
IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST HIDCLASS gửi một
IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST sức mạnh để xuống một
thiết bị nhàn rỗi. Với một thiết bị USB thực tế, yêu cầu này dovetails với các tính năng
USB chọn lựa tạm ngưng thảo luận trong chương trước.
Các đầu vào đệm cho METHOD_NEITHER yêu cầu này là một dụ của các cấu trúc sau
đây:
typedef struct _HID_SUBMIT_IDLE_NOTIFICATION_CALLBACK_INFO {
HID_SEND_IDLE_CALLBACK IdleCallback;
PVOID IdleContext;
} HID_SUBMIT_IDLE_NOTIFICATION_CALLBACK_INFO,
*PHID_SUBMIT_IDLE_NOTIFICATION_CALLBACK_INFO;
where HID_SEND_IDLE_CALLBACK is declared as follows:
typedef void (*HID_IDLE_CALLBACK)(PVOID Context);
Lưu ý rằng cấu trúc này là giống hệt nhau trong bố trí và ý nghĩa cho một USB được sử
dụng với chọn lựa treo. Trong thực tế, đã xảy ra, nếu điện thoại của bạn phải là một thiết
bị USB, bạn có thể chỉ cần chuyển IRP xuống stack sau khi thay đổi chức năng mã:
case IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST:
{
IoCopyCurrentIrpStackLocationToNext(Irp);
stack = IoGetNextIrpStackLocation(Irp);
stack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION;
return IoCallDriver(pdx->LowerDeviceObject, Irp);
}
Nếu điện thoại của bạn không phải là một thiết bị USB, tuy nhiên, bạn nên gọi lại ngay
để HIDCLASS và hoàn tất các IRP, như được hiển thị ở đây
352/369
case IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST:
{
PHID_SUBMIT_IDLE_NOTIFICATION_CALLBACK_INFO p =
(PHID_SUBMIT_IDLE_NOTIFICATION_CALLBACK_INFO)
stack->Parameters.DeviceIoControl.Type3InputBuffer;
(*p->IdleCallback)(p->IdleContext);
break;
}
HIDCLASS gọi lại cho rằng nó có thể ngay lập tức sức mạnh của thiết bị xuống.
353/369
Bài 22: THỰC HÀNH LẬP TRÌNH HID
Thực hành với các chương trình ví dụ điều khiển cho HID
Bài 1.
Xem xét file HIDCLASS.SYS và rút ra kinh nghiệm trong lập trình HID.
Bài 2.
Tạo cho mình một driver nhỏ về HID.
354/369
Bài 23: THỰC HÀNH LẬP TRÌNH
DRIVER GIAO TIẾP CÁC CỔNG
Thực hành một số bài tập tổng hợp
Bài 1.
Lập trình về cổng COM
Bài 2.
Lập trình cổng LPT.
Bài 3.
Lập trình USB
Bài 4.
Các xử lý IRP
Bài 5.
Các gói tin I/O
Bài 6.
Điều khiển cho thiết bị HID
355/369
TÀI LIỆU THAM KHẢO
Lập trình hệ thống: Tài liệu tham khảo
Sách tham khảo :
[1] O'Reilly, Practical C++ Programming. 2002.
[2] David J. Kruglinski, Programing microsoft Visual C++, 1998.
[3] Walter Oney, "Programming The Windows Driver Model, 2nd Edition (2003)".
[4] Jan Axelson, “USB Complete”
[5] Jan Axelson, “Serial Port Complete”
[6] Kernal Driver programming in Linux
[7] Nguyễn Minh San, Cẩm nang Lập trình hệ thống (bản dịch). NXB Tổng cục Thống
kê.2001.
[8] Ngô Diên Tập, Lập trình Ghép nối máy tính trong Windows. NXB Khoa học và kỹ
thuật. 2001.
356/369
MỤC LỤC
Lập trình hệ thống: Mục lục
Bài 1: TỔNG QUAN VỀ LẬP TRÌNH HỆ THỐNG 1
1.1 Khái niệm về lập trình hệ thống 1
1.2 Tổng quan 1
1.3 Lịch sử 1
1.4 Cấu trúc tổng quan lập trình hệ thống 2
Bài 2: CÔNG CỤ LẬP TRÌNH HỆ THỐNG 2
2.1 Các ngôn ngữ lập trình 2
2.2 Giới thiệu về C++ 3
2.3 Giới thiệu về Visual C++ 5
2.4 Giao bài tập lớn nghiên cứu về C++ và Visual C++ 9
Bài 3: Thực hành một số bài tập cơ bản trên C++ 9
Bài 4: CƠ BẢN VÀ CẤU TRÚC VỀ DRIVER 10
4.1 Tóm lược lịch sử các bộ điều khiển thiết bị 10
4.2 Tổng quan về các Hệ điều hành 13
4.3 Các kiểu Driver 14
4.4 Tổng quan về quản lý và kiểm tra danh sách 18
Bài 5: Thực hành một số bài tập cơ bản trên VC++ 19
Bài 6: CÁC KỸ THUẬT LẬP TRÌNH CƠ BẢN 20
6.1 Môi trường lập trình Kernel – mode 20
357/369
6.2 Xử lý lỗi 21
6.3 Quản lý bộ nhớ 33
6.4 Xử lý chuỗi 44
6.5 Một số kỹ thuật lập trình khác 44
Bài 7: Thực hành một số bài tập cơ bản trên VC++ 55
Bài 8: LẬP TRÌNH GIAO TIẾP QUA CỔNG LPT 56
8.1 Giới thiệu cổng LPT 56
8.2 Cấu trúc cổng LPT 56
8.3 Lập trình cho cổng LPT 59
Bài 9: Thực hành với các chương trình giao tiếp qua cổng LPT 60
Bài 10: Thực hành với các chương trình giao tiếp qua cổng COM 60
10.1 Giới thiệu cổng COM 60
10.2 Cấu trúc cổng COM 60
10.3 Lập trình cho cổng COM 63
Bài 11: Thực hành với các chương trình giao tiếp qua cổng COM 64
Bài 12: VẤN ĐỀ ĐỒNG BỘ 64
12.1 Giới thiệu về vấn đề đồng bộ 64
12.2 Mức yêu cầu Ngắt 66
12.3 Khóa xoay vòng 69
12.4 Các đối tượng Kernel Dispatcher 71
12.5 Một số phương pháp đồng bộ khác 82
Bài 13: Thực hành lập trình driver cơ bản 90
358/369
Bài 14: GÓI DỮ LIỆU VÀO RA 90
14.1 Các cấu trúc dữ liệu 90
14.2 Hàng đợi yêu cầu vào/ra 99
14.3 Hủy bỏ yêu cầu vào/ra 105
14.4 Tóm lược các kịch bản xử lý 117
Bài 15: Thực hành lập trình driver cho xử lý IRP 128
Bài 16: ĐỌC VÀ GHI DỮ LIỆU 128
16.1 Cấu hình thiết bị của bạn 128
16.2 Địa chỉ một Bộ đệm dữ liệu 131
16.3 Các cổng và các thanh ghi 134
16.4 Phục vụ ngắt 139
16.5 Truy nhập bộ nhớ trực tiếp 150
Bài 17: ĐIỀU KHIỂN VÀO/RA VÀ HÀM ĐIỀU KHIỂN PLUG AND PLAY 165
17.1 Hàm DeviceIoControl API 165
17.2 Điều khiển IRP_MJ_DEVICE_CONTROL 168
17.3 Những thao tác bên trong điều khiển vào/ra 169
Bài 18: Thực hành lập trình driver cho điều khiển vào/ra 177
Bài 19: TRÌNH ĐIỀU KHIỂN CHO USB 177
19.1 Giới thiệu cổng USB 177
19.2 Cấu trúc cổng USB 185
19.3 Lập trình cho cổng USB 185
Bài 20: Thực hành điều khiển qua cổng USB 185
359/369
Bài 21: TRÌNH ĐIỀU KHIỂN CHO HID 185
21.1 Những Driver cho những thiết bị HID 185
21.2 Những miêu tả báo cáo và những báo cáo 186
21.3 Những điều khiển nhỏ HIDCLASS 190
Bài 22: Thực hành lập trình HID 206
Bài 23: Thực hành lập trình driver giao tiếp các cổng 206
Tài liệu tham khảo 207
360/369
Tham gia đóng góp
Tài liệu: LẬP TRÌNH HỆ THỐNG
Biên tập bởi: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Khái niệm về lập trình hệ thống
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Tổng quan về lập trình hệ thống
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Lịch sử về lập trình hệ thống
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Cấu trúc tổng quan lập trình hệ thống
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Các ngôn ngữ lập trình
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Giới thiệu về C++
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
361/369
Giấy phép:
Module: Giới thiệu về Visual C++
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Thực hành một số bài tập cơ bản trên C++
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Tóm lược lịch sử các bộ điều khiển thiết bị
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Tổng quan về các Hệ điều hành (An Overview of the Operating Systems)
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Các kiểu Driver
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Tổng quan về quản lý và kiểm tra danh sách
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Thực hành một số bài tập cơ bản trên VC++
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
362/369
Module: Môi trường lập trình kiểu Kernel – Mode
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Trình bày lỗi (Lỗi xử lý)
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Quản lý bộ nhớ (Memory Management )
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Trình bày chuỗi (String Handling)
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Kỹ thuật lập trình hỗn hợp (Miscellaneous Programming Techniques )
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Thực hành một số bài tập cơ bản trên Visual C++
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Giới thiệu cổng LPT
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Cấu trúc cổng LPT
363/369
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Thực hành với các chương trình giao tiếp qua cổng LPT
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Giới thiệu cổng COM
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Cấu trúc cổng COM
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Thực hành với các chương trình giao tiếp qua cổng COM
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Vấn đề đồng bộ hóa nguyên mẫu (An Archetypal Synchronization Problem )
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Mức yêu cầu Ngắt (Interrupt Request Level )
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Khóa xoay vòng (Spin Locks )
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
364/369
URL:
Giấy phép:
Module: Các đối tượng Kernel Dispatcher (Kernel Dispatcher Objects )
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Một số phương pháp đồng bộ khác (Other Kernel-Mode Synchronization
Primitives )
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Thực hành lập trình driver cơ bản
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Các cấu trúc dữ liệu (Data Structures )
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Hàng đợi yêu cầu Vàora (Queuing IO Requests)
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Hủy bỏ yêu cầu vàora (Cancelling IO Requests )
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Tóm lược các kịch bản xử lý (Summary—Eight IRP-Handling Scenarios)
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
365/369
Giấy phép:
Module: Thực hành một số bài lập trình driver cơ bản
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Cấu hình thiết bị của bạn (Configuring Your Device )
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Địa chỉ một Bộ đệm dữ liệu (Addressing a Data Buffer )
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Các cổng và các thanh ghi (Ports and Registers )
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Phục vụ ngắt (Servicing an Interrupt )
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Truy nhập bộ nhớ trực tiếp (Direct Memory Access )
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Hàm DeviceIoControl API (The DeviceIoControl API)
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
366/369
Module: Điều khiển IRP MJ DEVICE CONTROL
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Những thao tác bên trong điều khiển IO (Internal IO Control Operations)
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Thực hành lập trình driver cho điều khiển Vàora
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Giới thiệu cổng USB
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Thực hành với các chương trình ví dụ điều khiển qua cổng USB
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Những bộ điều khiển cho thiết bị HID (Drivers for HID Devices )
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Những mô tả báo cáo và những báo cáo (Reports and Report Descriptors )
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Những điều khiển nhỏ HIDCLASS (HIDCLASS Minidrivers)
367/369
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Thực hành với các chương trình ví dụ điều khiển cho HID
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Thực hành một số bài tập tổng hợp
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Lập trình hệ thống: Tài liệu tham khảo
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
Module: Lập trình hệ thống: Mục lục
Các tác giả: Khoa CNTT ĐHSP KT Hưng Yên
URL:
Giấy phép:
368/369
Chương trình Thư viện Học liệu Mở Việt Nam
Chương trình Thư viện Học liệu Mở Việt Nam (Vietnam Open Educational Resources
– VOER) được hỗ trợ bởi Quỹ Việt Nam. Mục tiêu của chương trình là xây dựng kho
Tài nguyên giáo dục Mở miễn phí của người Việt và cho người Việt, có nội dung phong
phú. Các nội dung đểu tuân thủ Giấy phép Creative Commons Attribution (CC-by) 4.0
do đó các nội dung đều có thể được sử dụng, tái sử dụng và truy nhập miễn phí trước
hết trong trong môi trường giảng dạy, học tập và nghiên cứu sau đó cho toàn xã hội.
Với sự hỗ trợ của Quỹ Việt Nam, Thư viện Học liệu Mở Việt Nam (VOER) đã trở thành
một cổng thông tin chính cho các sinh viên và giảng viên trong và ngoài Việt Nam. Mỗi
ngày có hàng chục nghìn lượt truy cập VOER (www.voer.edu.vn) để nghiên cứu, học
tập và tải tài liệu giảng dạy về. Với hàng chục nghìn module kiến thức từ hàng nghìn
tác giả khác nhau đóng góp, Thư Viện Học liệu Mở Việt Nam là một kho tàng tài liệu
khổng lồ, nội dung phong phú phục vụ cho tất cả các nhu cầu học tập, nghiên cứu của
độc giả.
Nguồn tài liệu mở phong phú có trên VOER có được là do sự chia sẻ tự nguyện của các
tác giả trong và ngoài nước. Quá trình chia sẻ tài liệu trên VOER trở lên dễ dàng như
đếm 1, 2, 3 nhờ vào sức mạnh của nền tảng Hanoi Spring.
Hanoi Spring là một nền tảng công nghệ tiên tiến được thiết kế cho phép công chúng dễ
dàng chia sẻ tài liệu giảng dạy, học tập cũng như chủ động phát triển chương trình giảng
dạy dựa trên khái niệm về học liệu mở (OCW) và tài nguyên giáo dục mở (OER) . Khái
niệm chia sẻ tri thức có tính cách mạng đã được khởi xướng và phát triển tiên phong
bởi Đại học MIT và Đại học Rice Hoa Kỳ trong vòng một thập kỷ qua. Kể từ đó, phong
trào Tài nguyên Giáo dục Mở đã phát triển nhanh chóng, được UNESCO hỗ trợ và được
chấp nhận như một chương trình chính thức ở nhiều nước trên thế giới.
369/369
Các file đính kèm theo tài liệu này:
- lap_trinh_he_thong_4888.pdf