For project purposes, Greg KH's article titled [Snooping the USB data stream] mentions support for usb fs by kernel, the application can directly send a USB transfer to the device through the usb fs, which is actually implemented in devio. c, inode. c, and devices. C and other three kernel sources. (Note: The kernel version here is 2.6.26)
On the other hand, in the application library end, is to rely on the help of usbfs, the development of [libusb project] version 1.0.0, but in the Debian testing suite of packages, but only to the libusb-0.1.12, to configure library header libraries, install libusb-Dev.
Many changes have been made from 0.1.12 to 1.0.0. In addition to API re-determination, the most explicit difference is that thread support is added, however, both of them use the I/O control provided by USB FS in the most recent system calls. Because the design of 1.0.0 is too slow, I still try to catch up with it at 0.1.12 (in fact, the skill is not enough !) The following are some tracking notes of 0.1.12:
In libusb-0.1.12:
Usb_bulk_read () usb_interrupt_read ()
Usb_bulk_write () and usb_interrupt_write ()
::
V v
Usb_urb_type_bulk usb_urb_type_interrupt
::
::
V v
Usb_urb_transfer ()
Usb_urb_transfer () indicates that zookeeper provides the synchronous delivery mode for synchronous (that is, wait for it to complete after the call) --- the asynchronous method is not provided on the 0.1.12 interface (that is, the system calls the complete function after the call is made and the request is received/sent by the next urb). Note: this is the libusb-0.1.12 does not provide asynchronous function, but the kernel ioctl_usb_submiturb working method is asynchronous action, wait for the next part of the kernel will know.
After usb_urb_transfer () uses ioctl_usb_submiturb to send urb data, it then retries to use ioctl_usb_reapurbndelay to collect the completed urb data, and splits the timeout input by the user into 1 ms of single bit by select () to wait. Results:
1. When select () reaches the I/O operation, reapurb obtains a completed urb, and the returned value is the length of the received data.
2. Select () and so on won't be able to perform I/O operations. Wait for 1 ms of select () again until timeout. The returned value is-etimedout.
Usb_urb_transfer () has a linear solution. In this case, let's explain it directly:
# Define urb_usercontext_cookie (void *) 0x1)
/*
* Hack: the use of urb. usercontext is a hack to get threaded applications
* Sort of working again. Threaded support is still not recommended,
* This shoshould allow applications to work in the common cases. Basically,
* If we get the completion for an urb we're not waiting for, then we update
* The usercontext pointer to 1 for the other threads urb and it will see
* The change after it wakes up from the timeout. uugly, but it works.
*/
It is said that the threaded application can work! The root segment uses urb. usercontext to "mark" reapped urb --- if it is not our urb, we will set the urb. usercontext is set to urb_usercontext_cookie so that another thread can reap:But can another thread reap the URL of the cookie?
We have to catch up with devio. C of the kernel. We need to understand the mechanism that the kernel provides usb fs to answer this question...
First, start ioctl_usb_submiturb to find the access cable. Because this is the I/O control code specified by libusb, the kernel response corresponds to the usbdevfs_submiturb I/O control code, when processing this I/O control code, proc_submiturb (Ps, P); PS and P are
Struct dev_state * PS = file-> private_data;
Void _ User * P = (void _ User *) ARG;
Arg is the argument pointer that the user enters by IOCTL system call. Here, the user urb is added.
PS is obtained when allocated is usbdev_open ()., Which means:
Struct dev_state {
Struct list_head list;/* state list */
Struct usb_device * dev;
Struct file * file;
Spinlock_t lock;/* protects the async urb lists */
Struct list_head async_pending;
Struct list_head async_completed;
Wait_queue_head_t wait;/* wake up if a request completed */
Unsigned int discsignr;
Struct PID * disc_pid;
Uid_t disc_uid, disc_euid;
Void _ User * disccontext;
Unsigned long ifclaimed;
U32 secid;
};
We can regard this information structure as an example of how the process sends urb traffic to the device. the two lists are sent by the urb, and the corresponding async is sent by the async_pending operator. After the urb is complete, the corresponding async is sent by the async_completed operator, what is async? Each urb has a corresponding async data structure, which is obtained by allocate at proc_do_submiturb. The structure of async is as follows:
Struct async {
Struct list_head asynclist;
Struct dev_state * pS;
Struct PID * PID;
Uid_t uid, EUID;
Unsigned int signr;
Unsigned int ifnum;
Void _ User * userbuffer;
Void _ User * userurb;
Struct urb * urb;
Int status;
U32 secid;
};
Each urb has an async upload protocol, which is obtained by allocate at proc_do_submiturb (). At the same time, it will also change the location of the user urb, in the future, you can copy the information obtained by urb back to user urb.
The whole urb process is as follows:
Proc_submiturb (): copy user's urb (user space) to our uurb (kernel space)
-> Proc_do_submiturb (): Root partition bulk, interrupt .. wait for the type to separate the initial bit, then allocate async data structure (which also includes urb), then place PS-> async_pending queue for failover, and then call usb_submit_urb () (after that, it will be handled by the USB host controller.) then, we will not wait until the result is returned, so we say that the kernel handles the urb in asynchronous!
After the USB Host Controller completes urb processing, it will call async_complete (), and async_complete () to move async slave from PS-> async_pending to PS-> completed.
On the other hand, the user must pass through the ioctl_usb_reapurbndelay "Harvest" completed urb and apply the kernel to usbdevfs_reapurbndelay. This I/O control will call proc_reapurbnonblock (), it will patrol PS-> completed to see if there is async transfer failure, if not, it will return-eagain, if you copy the found urb (kernel space) data to the user space, and set the ARG imported when ioctl_urb_reapurbndelay to point to the user space urb, the part sent by kernel upload has been completed.
Okay. Now we have a general understanding of the kernel part. Next, let's discuss our questions in two situations:
1. Each thread uses the same open handle., That is, the same PS in the kernel:
When ioctl_usb_reapurbndelay is used, in the kernel, the URL of PS-> completd is taken out, but the URL of the thread is unknown. Therefore, libusb uses cookies to record the URL; when usb_urb_transfer (), each thread declares a user space urb on its own thread stack, if the first thread reap reaches its own urb, the cookie will be set and the other URBS from the kernel reap will be uploaded. At this time, when the second thread reap urb, capture another one from PS-> completed... of course,In this case, the second thread will not be able to receive the urb., Just generate them.
2.Each thread has its own Open Handle, That is, apply the respective PS in the kernel:
In this way, each thread corresponds to its own PS-> completed list,The received urb will not be confused. It seems that no cookie is required.! However, there is a deficiency in this case: the claim interface is required before bulk transfer-that is, when every thread needs to use usb_urb_transfer (), claim interface ..., therefore, if the thread that already uses the claim interface needs to be release interface, you must end the urb of the previous thread before releasing it,The intention of Multiple Threads "interleave URBS transfer" is gone!
So the conclusion is: if you want to use the thread usblib-0.1.12, probably to manually change the USB _urb_transfer () part, otherwise directly with the usblib-1.0.0.