Giáo trình môn Lập trình hệ thống

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ả.

pdf371 trang | Chia sẻ: nguyenlam99 | Lượt xem: 986 | Lượt tải: 0download
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:

  • pdflap_trinh_he_thong_4888.pdf
Tài liệu liên quan