Linux usb子系统(二)(4)

skel_read()
--233-->都是套路,先将藏在file_private_data中的资源对象拿出来
--255-268-->资源对象中的可读标志位,不可读的时候,判断IO是否允许阻塞,如果不允许就直接返回,允许阻塞就使用资源对象中的等待队列头,将进程加入等待队列,使用的是interruptible版本的wait,如果睡眠中的进程是被中断唤醒的,那么rv==-1,函数直接返回。
--286-->执行到这一行只有一个情况:设备可读了!如果缓冲区满执行第一个语句块,否则执行下面的语句块
--288-->缓冲区满时, 获取可拷贝的数据的大小.
--289-->在可拷贝的大小和期望拷贝的大小中取小者给chunk
--291-->可拷贝的数据为0, 而usb_skel->bulk_in_filled被置位才能进入这里, 所以只有一种情况: 缓冲区的数据已经拷贝完了
--292-->既然数据已经拷贝完毕, 调用skel_do_read_io发起请求
--300-->请求了数据,设备也反馈了,但是什么数据都没有,重试
307-->从内核缓冲区usb_skel->bulk_in_buffer + usb_skel->bulk_in_copied开始(就是剩余未拷贝数据的首地址)拷贝chunk byte的数据到应用层
--314-->更新usb_skel->bulk_in_copied的值
--320-->如果可拷贝数据的大小<期望拷贝的大小, 那么显然刚才chunk=availible, 已经将所有的数据拷贝到应用层, 但是还不能满足应用层的需求, 调用skel_do_read_io来继续向设备索取数据, 当然, 索取的大小是没满足的部分, 即count-chunk --324-->usb_skel->bulk_in_filled没有被置位, 表示内核缓冲区没有数据, 调用skel_do_read_io索取数据, 当然, 索取的大小是全部数据, 即count

刚才也说了, 如果缓冲区不能满足应用层需求的时候, 就会调用下面这个函数向bulk usb设备请求数据, 得到数据后将数据放到缓冲区并将相应的标志位置1/置0

189 static int skel_do_read_io(struct usb_skel *dev, size_t count) 190 { 191 int rv; 193 /* prepare a read */ 194 usb_fill_bulk_urb(dev->bulk_in_urb,dev->udev,usb_rcvbulkpipe(dev->udev,dev->bulk_in_endpointAddr),dev->bulk_in_buffer, min(dev->bulk_in_size, count),skel_read_bulk_callback,dev); 204 dev->ongoing_read = 1; 206 207 /* submit bulk in urb, which means no data to deliver */ 208 dev->bulk_in_filled = 0; 209 dev->bulk_in_copied = 0; 210 211 /* do it */ 212 rv = usb_submit_urb(dev->bulk_in_urb, GFP_KERNEL); 223 return rv; 224 }

skel_do_read_io()
--194-->向usb核心提交一个urb, 将资源对象dev藏在urb->context中随着urb实参传入回调函数, 和usb_fill_int_urb不同, usb_fill_bulk_urb注册的时候需要将缓冲区首地址和请求数据的大小和urb绑定到一起一同提交, 这样才知道向bulk设备请求的数据的大小, bulk设备有数据返回的时候才知道放哪.
--204-->将usb_skel->ongoing_read置1, 表示没有数据可读
--208-->将usb_skel->bulk_in_filled置0, 表示内核缓冲区没有数据可读
--209-->将usb_skel->bulk_in_copied置0, 表示没有任何数据已被拷贝
--212-->做好准备工作之后, 命令usb核心发送urb

请求被发出后, usb总线就会静待设备的反馈, 设备有反馈后就会回调urb的注册函数, 我们看看这个回调函数都做了什么

163 static void skel_read_bulk_callback(struct urb *urb) 164 { 165 struct usb_skel *dev; 166 167 dev = urb->context; 168 169 spin_lock(&dev->err_lock); 170 /* sync/async unlink faults aren't errors */ 181 dev->bulk_in_filled = urb->actual_length; 183 dev->ongoing_read = 0; 184 spin_unlock(&dev->err_lock); 185 186 wake_up_interruptible(&dev->bulk_in_wait); 187 }

skel_read_bulk_callback
--167-->套路, 先把资源对象拿出来
--181-->将表示设备反馈的数据长度urb->actual_length赋值给usb_skel->bulk_in_filled, 表示缓冲区有数据了
--183-->将usb_skel->ongoing_read置0, 表示可读了!
--186-->唤醒因为没有数据可读而陷入睡眠的进程

分析到这里, 应用层就可以通过usb_skeleton驱动从USB海量存储设备中获取数据了!!!写入数据的思路是一样的, 我这里就不罗嗦了.

锁的使用

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/b6145cb911cf25495391e7483184a16b.html