libusb简要记录

来源:互联网 发布:shadowsocks mac 编辑:程序博客网 时间:2024/06/03 08:41

大致意思:libusb是kernel借助usbfs对usb的支持,主要是让application可直接透过usbfs对device发出usb transfer,实做于devio .c, inode.c, and devices.c 等三个kernel sources.

in libusb-0.1.12:
: :
usb_urb_transfer()

usb_urb_transfer() 大致上,仅仅提供了synchronous 的传送方式(就是呼叫之后就等待它完成)。还有asynchronous 的方式(就是呼叫后就离开,将来urb 收/送完成后,系统会呼叫complete function)。

注意:这是libusb-0.1.12 并没有提供asynchronous 的函数,但是kernel 的IOCTL_USB_SUBMITURB 工作方式却都是asynchronous 的动作,等下追踪kernel 的部份时就会知道。

usb_urb_transfer() 用IOCTL_USB_SUBMITURB 送出urb 之后,一直重复使用IOCTL_USB_REAPURBNDELAY 来收取completed urb ,并且把使用者传入的timeout 切成1ms 的单位用select() 来等待。结果有几种:

1. select() 等到了I/O 动作,REAPURB 得到了某个completed urb ,返回值是所收送的data 长度。

2. select() 等不到I/O 动作,重复1ms 的select()等待,一直到timeout 了,返回值是-ETIMEDOUT

继续往kernel 的devio.c 追踪. 首先从IOCTL_USB_SUBMITURB 开始找线索,因为这个是libusb 定义的I/O control code,kernel 里相对应的是USBDEVFS_SUBMITURB I/O control code,负责处理这个I/O control code 的是proc_submiturb(ps, p); 其中ps 与p 分别是

struct dev_state *ps = file->private_data;
void __user *p = (void __user *)arg;

arg 是user 由ioctl system call 传入的argument pointer,这里传入user urb。
ps是usbdev_open()时allocated得到的 ,定义为:

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;
};

可以把这个结构看成process对于这个device的传送urb的状态纪录.其中两个list分别是urb送出后就把对应的async由async_pending纪录,等urb complete之后就把对应的async由async_completed纪录,async是什么呢?对于每个urb都有一个对应的async data structure,是在proc_do_submiturb()时allocate得到的async的资料结构为:

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;
};

对每个urb都有一个async纪录,在proc_do_submiturb()时allocate得到,同时它也会纪录user urb的位置,将来可以把urb所得的资料copy回user urb。

整个urb的流程为:
proc_submiturb():把user's urb(user space)拷贝一份到我们的uurb (kernel space)
->proc_do_submiturb():根据bulk,interrupt..等type分别initial一些栏位,然后allocate async data structure (里面还包含urb),然后放入ps->async_pending queue做纪录,接着呼叫usb_submit_urb() (之后就交给usb host controller处理)然后不等结果就返回,所以我们说kernel这里是以asynchronous的方式处理urb !

等usb host controller把urb处理完后,会呼叫async_complete(),async_complete()将async纪录从ps->async_pending移到ps->completed.

另一方面user要透过IOCTL_USB_REAPURBNDELAY "收割"已完成的urb ,对应到kernel为USBDEVFS_REAPURBNDELAY。这个I/O control会呼叫proc_reapurbnonblock(),它会巡视ps->completed是否有async纪录,若无则返回-EAGAIN,若有则把找到的urb (kernel space)资料拷贝到user space,并设定IOCTL_URB_REAPURBNDELAY时传入的arg指向user space urb,至此,kernel传送的部份已经完成。


0 0
原创粉丝点击