Driver guide for USB devices under WinCE

Source: Internet
Author: User

With the increasing number of USB devices, we have become more involved in driver development for USB devices. However, many beginners have the following three difficulties:
First, we have little knowledge about the driver structure of wince and cannot focus on the development of the driver;
Second, I did not understand the examples of the USB driver that comes with wince, and found a lot of folder structures and confused thinking of the source program;
Third, there is almost no reference material for Chinese. I don't know how to start.
Article 3 many developers have met each other. I am the same. Many friends asked me if I have any information. I can only say sorry, because I also have this problem, everything depends on your own dark, so this article will not talk about the third article.
The first article is to find information, such as Windows CE. Net System Analysis and Experiment tutorial. Therefore, this article does not intend to spend a lot of ink here.
In this way, the focus of this article is on the second article. Through this article, I hope that more friends can understand the implementation process of the USB driver model and the sample program in Windows CE, based on the sample code, straighten out the development idea of the driver for the USB device. Similarly, the readers in this article are expected to be the readers and those who are ready to start USB driver development. The driver development experts should naturally smile. At the same time, I wrote this article to fulfill my promise to many friends half a year ago and apologize for my laziness.
Well, before we look at the sample program, we need to know something about it. Let's look at it first:

In this figure, we can clearly see the structure between the host and physical peripherals. On the host end, the usbd module and the HCD module use the default pipe to access a common logical device, in fact, usbd and HCD are a set of abstract logical interfaces for accessing all USB devices. They are responsible for managing the connection, loading, removal, data transmission, and general configurations of all USB devices. HCd is a host control driver and provides underlying function access services for usbd. usbd is a USB bus driver and is located on the upper layer of HCD. the HCD Service provides high-level Abstract Functions.
Because both HCD and usbd are oriented to the same logical device interface, a unique device driver is required for a variety of physical devices, this is the physical device and USB device driver connected by the top-most special pipe.
With our understanding of this structure, we can make it clear that we want to write the top-end USB device driver, which is also called the USB client driver in the sample program of wince, it works on usbd, so in fact our work is to use the interfaces provided by usbd to complete the USB device driver for specific physical devices. It is not related to other parts for the time being.
Okay. Come here first, and you'll be ready to read some specific things next!
Next, let's analyze the sample program in CE. I use version 4.2, so the content below is the program in version 4.2. The program is organized together in the form of folders, so we should first understand the folder structure related to this, as we used to learn ce, for example.

The USB folder is divided into several folders, including class, clients, common, HCD, Inc, and usbd. the INC and common folders have a lock. C program, this program is obviously a lock to be used by other USB-related drivers, the code is very simple, just an encapsulation body similar to the critical section, it can protect the read/write access of multiple threads to the same memory area. The clients folder may have been originally used by Microsoft developers to place device drivers, but it was not released and was not deleted at the time of release, it is an empty folder, so it is useless. Usbd and HCD are the aforementioned underlying drivers, which contain many subfolders and programs. Because we only use USB drivers, we will not analyze these two parts, if you are not interested, you can learn about it yourself.
The focus is on the class folder. To expand it, it contains the common, hid, printer, and storage folders. Similarly, the source programs stored in common are shared by hid, printer, and storage. Hid is a sample driver for a USB input device such as a keyboard or mouse, printer is a sample driver for a USB printer, and storage is a sample program for a USB storage device such as a USB flash drive.
Take the USB storage device as an example. Expand the storage folder. The INC folder contains the header file, the class is the driver of the USB storage device, and the disk is the disk driver. Here is why there are two drivers. Let me briefly explain them.
The driver works between the hardware and the operating system. It has two functions. One is to forward the operation of the operating system to control the hardware in the form of a specified hardware device, the other is to provide this access interface to the operating system. For example, the USB flash drive, on the one hand, the driver needs to convert the operating system's identification, reading, and writing operations on the USB flash drive into a USB flash drive, and on the other hand, it tells the operating system that this is a USB flash drive, it can be used as a folder or file system and can accept standard file operation commands. Therefore, there are two drivers.
There is also a folder, wince420 \ public \ common \ DDK \ Inc, which is a header file related to the device driver. For USB devices, the related files include USB 100.h and USB types. h, usbdi. h. The definition of USB in the front two items is completely in line with the USB specification, not just defined, but USB di. the content in the hfile is the interface description provided by the usbd bus driver to the USB driver. This header file must be included in the development of the USB driver, in this way, the prototype of the usbd interface can be obtained.
Previously, we learned about the location structure of the USB driver in CE and the folder structure of the sample driver. Next, we need to know which interfaces usbd provides for us to implement Device Access and driver management functions. Find usbdi. h. Don't tell me you can't find it. No matter what Editor, notepad, Pb, Vc, EVC, or vs you use, open it, let's take a look at what usbd provides for us.
The first large struct we see is _ usb_driver_settings. Note that this struct is not a description of the USB device in the USB specification, but is created for the convenience of the CE Device Manager to load the USB device driver. The supplier description, device description, and interface description in this struct are used to match the registry key of the USB device driver in the registry, when the device manager finds that the values of your device match those in the registry, it loads your driver. That is to say, it is a unique identifier that corresponds to your device. The supplier description of this struct must be based on the supplier information of your device. The device categories, subclasses, protocols, and other descriptions can be found in the USB specification, in the USB 100.h header file, a part is also defined in the following sample program.
The following three functions must be implemented by the USB driver, which we can see in msdn or other CE documents. These functions are:
USB deviceattach: called by the system when the device is loaded
Usbinstalldriver: This is called by the system when the device is loaded for the first time. It is used to install registry configuration to search for devices.
Usbuninstalldriver: After the device is removed, the Registry configuration written by the previous function is cleared.
In this way, we must follow the prototype of the three functions in our driver, otherwise it cannot be recognized by the Device Manager. In fact, in addition to the three, I think the fourth is also necessary. This is the function pointed to by a function pointer:
* Lpdevice_policy_routine
The Pointer Points to a function that is used to receive notification messages. Since Microsoft says that any USB device must respond to the message of usb_close_device, then the function pointed to by this pointer is naturally necessary to be implemented.
Looking down, this is the prototype of a group of functions. These functions are the service interfaces that usbd provides to the device driver. Some functions can be called at will, these functions are used to read version information, perform registry operations, and register device drivers:
Getusbdversion registerclientdriverid unregisterclientdriverid registerclientsettings
Unregisterclientsettings openclientregistrykey
A large number of functions must be called through pointers. Generally, they can only be called in the driver. For example, a _ usb_funcs struct is provided here, each struct member corresponds to a function pointer, so that you can only use one struct variable to use the usbd function in the driver. here we need to remember the struct name, microsoft also defines the struct variable as follows:
Typedef struct _ usb_funcs, * pusb_funcs, * lpusb_funcs;
Typedef struct _ usb_funcs const * pcusb_funcs;
Typedef struct _ usb_funcs const * lpcusb_funcs;
Now, we find that most of the USB work has been completed by usbd. to implement our own device driver, we only need to use these pointers or functions, to implement four of our own functions, and then match our own device in it. Is it simple? Yes, you can't scare yourself at the beginning, so you can't do it later.
After learning about all usbd interface functions last time, we have gained a lot of basic knowledge. Review the folder structure of the USB sample, we can still remember that the USB \ class \ common folder contains the source code of the public part, it is the structure and function encapsulation specially abstracted by Microsoft to serve drivers of most USB devices. Let's take a rough look at the source program here.
Three programs are included:
Remlock USB client utils
Next, let's take a look at the functions and interfaces of these three programs. Obviously, the USB driver will certainly use some of these functions, therefore, we do not need to understand every line of the line, but at least we need to have an impression on these functions, so that we do not know the source of the function when reading the driver.
The remlock program is a lock used to remove the device.
Typedef struct _ remove_lock
{
Bool removed;
Long iocount;
Handle removeevent;
} Remove_lock, * premove_lock
To implement synchronization control when the device is removed. Among them, the removed member is the identifier for whether the device has been removed, and the iocount member is the number of accesses to the device, which is also a common behavior in the driver, just like the lock program we saw earlier, removeevent is a kernel event, which should be clear to anyone familiar with Win32 programming. It is a way for the kernel to notify the application, it is also a means of thread concurrency control. If you are not familiar with it, you must find a book such as Windows Advanced Programming as I mentioned in previous articles to understand it, otherwise, it is difficult to control the driver.
The functions implemented by using it are not mentioned, and they are used in the same way as those in the critical section. In addition, there is a function like interlockedincrement in this program. This function is a Win32 API function designed to provide synchronous access to the same variable by multiple threads. You can use msdn to find detailed usage.
The USB client program is a function interface used to package usbd for USB device drivers. h. We can find that the definition of a group of functions about data transmission, attribute setting, status description, and resetting is in the original form. Let's look at the USB client again. in the c file, most of these functions have a parameter of the lpcusb_funcs type. Looking back at our previous understanding of usbd, we can see that this parameter can be used to access the service functions provided by usbd, through the implementation of the function, we can find that every function uses this parameter to call the usbd function and then process the called result. Therefore, there is only one more encapsulation, this makes the compilation of the driver clearer and easier to maintain.
In addition, we should pay attention to the issuebulktransfer (), issueinterrupttransfer (), and issuevendortransfer () functions, which implement general bulk transmission, interrupted transmission, and custom transmission modes, to be used in the driver.
Utils is a simple program that encapsulates registry operations. Using the _ reg_value_descr struct and the getsetkeyvalues () function, you can easily access the registry and use more in driver installation.
After talking about so many things, although we haven't looked at many programs, we are a little closer to the driver. At least we know that many functions are used in the driver, if you are interested, you can read the implementation methods of each function, but I don't think this will affect the development of the driver. If I write the driver, I will copy these public source programs without special circumstances. This can greatly shorten the development cycle!

As expected, go to the drivers \ USB \ class \ storage \ class folder and access the driver of the USB device.
Let's first understand the two header files: storage \ Inc \ usbmsc. H and storage \ class \ usbmscp. h. The former is the header file shared by the USB storage device, and the latter is the header file that needs to be changed according to your own device. Let's first look at the former.
In the header file usbmsc. H, many constants are defined on the front side, including subclasses and Protocol constants. Where does this come from? As we have mentioned above, these values are derived from the USB device specification and are defined in the specification. Therefore, the values here must be consistent with those in the USB specification. The downstream command block struct and data block struct are used to communicate with USB devices. data can be transmitted through these two struct instances and USB devices. The following function prototype will not be mentioned. As mentioned above, only these functions can be remembered here.
Let's take a look at the USB mscp. h header file, which needs to be modified according to your own needs and the USB device. For example, driver_name_sz is the name of the driver, and reset_timeout is the default value for timeout. Another important thing is the setting of usbmsc_driver_settings, which is different from that of usbdi. in H, the usb_driver_settings struct corresponds to each other. To meet the needs of my own devices, we usually need to set dwvendorid and dwproductid to the corresponding values of the devices. For example, the vendorid Of My USB flash drive is 0x058f, if productid is 0x9321, I will write the corresponding values in the corresponding positions. At the same time, the system registry also uses these two values to modify the registry key so that the Device Manager can smoothly find my device driver.
There is also a _ usbmsc_device struct, which is used to describe your own USB storage device, it is the most important data structure that encapsulates usbd function table pointers, disk device pointers, pipelines, and configuration items. In driver implementation, this data structure is the key parameter, given that the sample program makes a clear comment on each struct element, I will not describe it one by one here, just like the class in C ++, is the final structure that can be used to combine some small classes.
Well, after learning about these two header files, we will go to the most critical part, the source program. Let's take a look at the usbmsc. c file. Why should I read this file first instead of several other files in the same folder? Let me explain it. In this folder, there is a usbmsc. def file, we all know that it defines the export function, usually a program file with the same name as it will contain the dllentry entry, since the entry is here, then we should first look at this file. If other files are used, it is not too late.
This is a source program with more than 1000 lines, but don't be afraid. Let's just look at the most important ones. You can study the implementation of other functions by yourself. First, we can see that the dllentry entry in the file has five function prototype definitions, and the function functions can be known from the function name, obviously, these functions are called in the program implementation process. Therefore, you only need to know the function and do not need to know the implementation method. I forgot to say that this program contains the bot. H and cbit. H Two header files. It can be seen that their functions are used in the program, but ignore them and continue to look down.
Below the dllentry entry function is the usbinstalldriver () function, which is used to perform registry operations related to the USB device. The main statement is:
BRC = registerclientdriverid (wsusbdeviceid );
BRC = registerclientsettings (szdriverlibfile, wsusbdeviceid, null, & usbdriversettings );
That is, first register the device category, and then the device details. Similarly, the usbuninstalldriver () function removes Registration Information in reverse order. These registration-related functions are provided by the usbd interface. Here we can see the importance of usbd to the device driver.
Looking down, we found the USB deviceattach () function, which is the most important thing. After a USB device is inserted into the plug-in, how does the operating system identify it, how can I access it as a folder? Let's solve the mystery here.
For our convenience, I simplified this program as follows:

The subsequent program will describe this line number.
Let's take a look at row 4th of the program. Here we have a judgment Statement, which is used to determine whether the inserted device is of the usbmsc_interface_class type. This constant is in usbmsc. the H file defines that if the device is not a USB storage device, the function is terminated, that is, the driver can only process USB storage devices.
When the device meets the requirements of this driver, it will be resolved through the parseusbdescriptors () function, which will be implemented in the following program, let's take a look at the function body of this function. Obviously, it is configuring various configurations for the device, so we will not talk about it much.
Next, allocate the memory, set the flag, and read the information from the registry. Note: The registry information read here is the value under the Registry Key combined by drivers \ USB \ clientdrivers \ mass_storage_class and binterfacesubclass. For details, see the source program, what is placed under this registry key is
[HKEY_LOCAL_MACHINE \ drivers \ USB \ clientdrivers \ mass_storage_class \ 6]
"DLL" = "usbdisk6.dll"
"Prefix" = "DSK"
"Folder" = "USB disk"
"IOCTL" = DWORD: 4
"Iclass" = "{A4E7EDDA-E575-4252-9D6B-4195D48BB865 }"
From this we can see that, through the registry here, the driver can know which form and DLL the device will provide interfaces to the operating system. At the same time, we have prepared for subsequent operations.
The most important part is in the next loaddriver () clause. Load the DLL file of another driver, which is the usbdisk6.dll file in the above registry. Add one to the counter, obtain the address of the usbdiskattach function and the usbdiskdetach function in the file, register the Event Notification processing function, and then call the usbdiskattach function in the DLL file.
It can be seen that the USB device driver has two layers of functions, one is to identify and configure the specified device, and the other is to call a higher-level driver as required to provide interfaces to the operating system. After usbdisk6.dll is called, the operating system processes the program in the file as a disk or as a folder, you can control the read and write operations. We can also take a look at this function of the HID device. It also allows the operating system to recognize the USB device as a mouse device.
As mentioned above, there is also a callback function for notification messages, which we have found in the program body just now:
Usbfuncs-> lpregisternotificationroutine (hdevice, usbdeviceno133, pusbdevice );
The statement has been set for this function. Let's look down at the function body of this function. This function is very simple. You only need to process the message of usb_close_device. Since you want to disable the USB device, it is necessary to call the detach function in usbdisk6.dll to release the driver on the upper layer, then, reduce the reference count by one. If no device references this driver, freelibrary () is the only one.
The rest of the functions can be carefully studied. I will not describe them in detail here. Next we need to understand how the Operating System reads and writes specific devices through an abstract disk?
With the last question, we continue to learn how the Operating System reads and writes USB devices through USB disk. Let's first look at the USB \ class \ storage \ disk \ sci2 \ usbdisk6.def file. In this file, we can see that the DLL has exported a total of 14 functions, two of which are the USB diskattach and USB diskdetach called by the device driver in the previous content, the rest is a set of stream-driven interfaces starting with DSK. It is easy to see that USB disk provides services to the operating system in the form of stream-driven.
For the sake of clarity, we do not learn the following large numbers of programs, but only care about reading and writing devices. So let's look at the program file disk. C. We are disappointed to find the dsk_read and dsk_write functions, because both functions are like
Unreferenced_parameter (pdevice );
Unreferenced_parameter (pbuffer );
Unreferenced_parameter (bufferlength );
Debugmsg (zone_err, (text ("dsk_read \ n ")));
Setlasterror (error_invalid_function );
Return 0;
This implementation means that the user cannot use this device through the regular readfile and writefile functions. What should I do? Does it mean that the disk cannot be read or written? Of course not. We should immediately think of the dsk_iocontrol () function. When some devices cannot use conventional file operation functions, we can use the deviceiocontrol () User Function, this function calls the dsk_iocontrol function in the driver.
In this function, we find the handler for commands such as ioctl_disk_read. The most critical sentence is scsirwsg (pdevice, psgreq, pdevice-> Lun, bread ), that is, a scsirwsg function is called.
In the scsi2.c program, we found this function, in which SG refers to a Data Structure for reading and writing the buffer, which is actually a structure with a buffer and length, it is a general read/write data structure of the disk device under CE, which can be in diskio. h. In this function, we find that it calls scsireadwrite () again to perform read and write operations. Find this function, which contains our most important call line, that is, the usbsdatatransfer () function is called, do you remember where I met this function? That's right, it's in the driver of the USB device.
Through this process, we found that all the SCSI functions are only preparing some buffers and data structures, and they are not operating on the hardware, the driver is used to operate hardware. It can be seen that the device driver has a strong hierarchy, and the lower layer is dedicated to physical devices, the upper layer is an abstract device for the operating system, the lower layer is a physical entity such as a USB flash disk, and the upper layer is a folder. The two complete the normal operation of the device in the operating system through a certain communication or call mechanism.
Return to the usbmsc. C program and find the usbsdatatransfer function. This function is very simple. Call cbit_datatransfer () or bot_datatransfer () based on the transmission protocol.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.