分类: LINUX
2015-03-25 20:06:21
原文地址:usb message 处理 作者:steven_miao
谨以此文纪念过往的岁月
一. 前言
在前文中看过urb的实现的机制,在该文中咱们来看msg的实现。
二. msg
在ldd中说msg是一种轻量级的usb数据传输,个人以为不然,其本质还是采用了urb来实现的,那我们来看其具体的实现,除了iso的没有msg其余的三种usb传输都有。那一一来看其实现。
在该函数的说明中就说明该函数不能使用在中断上下文中。因为该函数会睡眠等待。那先来看其具体的参数:
dev:usb设备
pipe: 管道 包括一些传输的信息
request :usb请求的命令,该值在usb协议中定义
requesttype :请求类型
value :usb信息值
index :usb信息索引值
data :指向需要发送的数据指针
size:数据大小
timeout:等待时间
int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
__u8, __u16 value, __u16 , void *data,
__u16 size, int timeout)
{
struct usb_ctrlrequest *dr;
int ret;
dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
if (!dr)
return -ENOMEM;
dr->bRequestType = requesttype;
dr->bRequest = request;
dr->wValue = cpu_to_le16(value);
dr->wIndex = cpu_to_le16(index);
dr->wLength = cpu_to_le16(size);
ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
kfree(dr);
return ret;
}
static int usb_internal_control_msg(struct usb_device *usb_dev,
unsigned int pipe,struct usb_ctrlrequest *cmd,
void *data, int len, int timeout)
{
struct urb *urb;
int retv;
int length;
urb = usb_alloc_urb(0, GFP_NOIO);
if (!urb)
return -ENOMEM;
usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char *)cmd, data,
len, , NULL);
retv = (urb, timeout, &length);
if (retv < 0)
return retv;
else
return length;
}
从上面的源码可以看出,其实所谓的message就是一个马甲,其就是自己私自创建一个urb用于传输。那我们来看其中还具有一点隐私的函数,咱们不看其具体的实现来猜猜其的作用。嘿嘿,其中一点调用了usb_submit_urb来提交urb不过还应该有一个类似于信号量的东东用来等待urb完成,而在填充urb中complet域的函数usb_api_blocking_completion中一定会唤醒或完成的东东来唤醒在usb_start_wait_urb中等待的东东。咱们还是来看源码。
static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
{
struct api_context ctx;
unsigned long expire;
int retval;
init_completion(&ctx.done); --新建和初始化一个完成量
urb->context = &ctx; --存储,要不然怎么完成
urb->actual_length = 0;
retval = usb_submit_urb(urb, GFP_NOIO); --提交urb
if (unlikely(retval))
goto out;
expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;
if (!wait_for_completion_timeout(&ctx.done, expire)) { --如果等待没有结果就…
usb_kill_urb(urb);
retval = (ctx.status == -ENOENT ? -ETIMEDOUT : ctx.status);
} else
retval = ctx.status;
out:
if (actual_length)
*actual_length = urb->actual_length;
usb_free_urb(urb);
return retval;
}
其实上面的等待将在下面的函数中唤醒。
static void usb_api_blocking_completion(struct urb *urb)
{
struct api_context *ctx = urb->context;
ctx->status = urb->status;
complete(&ctx->done);
}
这里理解了为什么msg不能在中断上下文中了吧,呵呵。
而int和bulk的msg传输与上面类似咱就不看了,不过函数定义还是来看一下。
int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe,
void *data, int len, int *actual_length, int timeout)
int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
void *data, int len, int *actual_length, int timeout)
这儿说到了请求,那这儿就来看看usb请求的具体的格式以及具体的请求有什么。
下面结构体定义控制类型传输的格式
struct usb_ctrlrequest {
__u8;
__u8 bRequest;
__le16 wValue;
__le16 wIndex;
__le16 wLength;
} __attribute__ ((packed));
bRequestType:
bit7 :数据传输方向 0 主机->设备 1 设备->主机
bit6~bit5 :类型 0 标准 1 类 2 私有 3 保留
bit4~bit0 :接受者 0 usb设备 1 usb接口 2 usb端点 其余保留
如何理解请求的类型,这个很好理解就是0表示是所有usb设备都必须支持的标准请求命令,1表示一类设备所支持的请求命令而2就是该usb设备所特定的请求。Bit4~bit0则表明了数据所对应的目的地。其实在这几个参数中wIndex这个比较难理解。也许下面的表格比较好理解一点。
bRequestType中bit4~bit0值为2时即目的地是端点wIndex则代表:
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
|
保留(0) |
Direction |
保留(0) |
Endpoint number |
当bRequestType中bit4~bit0值为1时即目的地是接口wIndex则代表:
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
保留(0) |
Interface number |
上面的表格够清晰了吧!呵呵。
在usb协议中有几种标准的usb请求如下:
#define USB_REQ_GET_STATUS 0x00 -- 获取状态
#define USB_REQ_CLEAR_FEATURE 0x01 --清除或禁止某一特定功能
#define USB_REQ_SET_FEATURE 0x03 --设定或使能某一特定功能
#define USB_REQ_SET_ADDRESS 0x05 --设定地址
#define USB_REQ_GET_DESCRIPTOR 0x06 --获取描述符
#define USB_REQ_SET_DESCRIPTOR 0x07 --设定描述符
#define USB_REQ_GET_CONFIGURATION 0x08 --获取配置
#define USB_REQ_SET_CONFIGURATION 0x09 --设定配置
#define USB_REQ_GET_INTERFACE 0x0A --获取接口
#define USB_REQ_SET_INTERFACE 0x0B --设定接口
#define USB_REQ_SYNCH_FRAME 0x0C --同步帧
关于上述的请求命令其实在看hub的时候都涉及到了,只不过在这里单独来看了。
三. 总结
本文主要是看usb中message的实现以及其具体的参数说明。