USB core(一) - rh_queue_status与rh_call_control
2015-11-03 18:11
856 查看
rh_call_control
为了说明rh_call_control,先来看看是如何通过usb_control_msg,接着usb_submit_urb,然后rh_urb_enqueue,最终在调用rh_call_control的过程。hub信息获取函数
get_hub_descriptor(struct usb_device *hdev, void *data) usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0), USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB, dtype << 8, 0, data, size, USB_CTRL_GET_TIMEOUT); clear_hub_feature(struct usb_device *hdev, int feature) usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), USB_REQ_CLEAR_FEATURE, usb_control_msg, feature, 0, NULL, 0, 1000); usb_clear_port_feature(struct usb_device *hdev, int port1, int feature) usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port1, NULL, 0, 1000); set_port_feature(struct usb_device *hdev, int port1, int feature) usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port1, NULL, 0, 1000);
以上是hub的一些控制传输,基本都通过usb_control_msg来获取信息,面向两个对象USB_RT_HUB和USB_RT_PORT,来看看usb_control_msg
usb_control_msg
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, usb_api_blocking_completion, NULL); retv = usb_start_wait_urb(urb, timeout, &length); if (retv < 0) return retv; else return length; } int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, 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; }
usb_control_msg将8个字节的request信息填写到结构体struct usb_ctrlrequest
usb_internal_control_msg将这个usb_ctrlrequest与data赋值给urb,最终通过usb_start_wait_urb提交urb,在usb_start_wait_urb中调用了usb_submit_urb
usb_submit_urb
int usb_submit_urb(struct urb *urb, gfp_t mem_flags) usb_hcd_submit_urb(urb, mem_flags); if (is_root_hub(urb->dev)) { status = rh_urb_enqueue(hcd, urb); } else { status = hcd->driver->urb_enqueue(hcd, urb, mem_flags); }
由于这里提交urb的是hub,所以会执行rh_urb_enqueue
rh_urb_enqueue
static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb) { if (usb_endpoint_xfer_int(&urb->ep->desc)) return rh_queue_status (hcd, urb); if (usb_endpoint_xfer_control(&urb->ep->desc)) return rh_call_control (hcd, urb); return -EINVAL; }
可见对于rh的数据传输,一般分为两部分,int传输和control传输,这个int传输是虚构的int端点的传输,就是起一个rh_timer,然后调用usb_hcd_poll_rh_status不停的polling roothub的status,int传输放到后面再讲
这里说明control传输。
rh_call_control
static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) { struct usb_ctrlrequest *cmd; u16 typeReq, wValue, wIndex, wLength; cmd = (struct usb_ctrlrequest *) urb->setup_packet; typeReq = (cmd->bRequestType << 8) | cmd->bRequest; wValue = le16_to_cpu (cmd->wValue); wIndex = le16_to_cpu (cmd->wIndex); wLength = le16_to_cpu (cmd->wLength); switch (typeReq) { case DeviceRequest | USB_REQ_GET_STATUS: ... case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: ... case DeviceOutRequest | USB_REQ_SET_FEATURE: case DeviceRequest | USB_REQ_GET_CONFIGURATION: ... case EndpointRequest | USB_REQ_GET_STATUS: ... case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: ... case EndpointOutRequest | USB_REQ_SET_FEATURE: ... ... /* CLASS REQUESTS (and errors) */ default: status = hcd->driver->hub_control (hcd, typeReq, wValue, wIndex, tbuf, wLength); }
如果是standard request则rh_call_control根据不同的case对所需的情况赋值,而如果是class specific的request,则会调用底层提供的hub_control函数来获取hub的信息。
当底层调用hub_control函数的时候,之前传递的USB_RT_HUB和USB_RT_PORT就派上用场了,
ohci_hub_control
#define USB_RT_HUB (USB_TYPE_CLASS | USB_RECIP_DEVICE) //0x20 #define USB_RT_PORT (USB_TYPE_CLASS | USB_RECIP_OTHER) //0x23 //上面的是requestType,左移8位和request相与之后得到下面 #define ClearHubFeature (0x2000 | USB_REQ_CLEAR_FEATURE) #define ClearPortFeature (0x2300 | USB_REQ_CLEAR_FEATURE) #define GetHubDescriptor (0xa000 | USB_REQ_GET_DESCRIPTOR) #define GetHubStatus (0xa000 | USB_REQ_GET_STATUS) #define GetPortStatus (0xa300 | USB_REQ_GET_STATUS) #define SetHubFeature (0x2000 | USB_REQ_SET_FEATURE) #define SetPortFeature (0x2300 | USB_REQ_SET_FEATURE) static int ohci_hub_control ( struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength ) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); int ports = ohci->num_ports; u32 temp; int retval = 0; if (unlikely(!HCD_HW_ACCESSIBLE(hcd))) return -ESHUTDOWN; switch (typeReq) { case ClearHubFeature: switch (wValue) { case C_HUB_OVER_CURRENT: ohci_writel (ohci, RH_HS_OCIC, &ohci->regs->roothub.status); case C_HUB_LOCAL_POWER: break; default: goto error; } break; case ClearPortFeature: if (!wIndex || wIndex > ports) goto error; wIndex--; switch (wValue) { case USB_PORT_FEAT_ENABLE: temp = RH_PS_CCS; break; case USB_PORT_FEAT_C_ENABLE: temp = RH_PS_PESC; break; case USB_PORT_FEAT_SUSPEND: temp = RH_PS_POCI; break; case USB_PORT_FEAT_C_SUSPEND: temp = RH_PS_PSSC; break; case USB_PORT_FEAT_POWER: temp = RH_PS_LSDA; break; case USB_PORT_FEAT_C_CONNECTION: temp = RH_PS_CSC; break; case USB_PORT_FEAT_C_OVER_CURRENT: temp = RH_PS_OCIC; break; case USB_PORT_FEAT_C_RESET: temp = RH_PS_PRSC; break; default: goto error; } ohci_writel (ohci, temp, &ohci->regs->roothub.portstatus [wIndex]); // ohci_readl (ohci, &ohci->regs->roothub.portstatus [wIndex]); break; case GetHubDescriptor: ohci_hub_descriptor (ohci, (struct usb_hub_descriptor *) buf); break; case GetHubStatus: temp = roothub_status (ohci) & ~(RH_HS_CRWE | RH_HS_DRWE); put_unaligned_le32(temp, buf); break; case GetPortStatus: if (!wIndex || wIndex > ports) goto error; wIndex--; temp = roothub_portstatus (ohci, wIndex); put_unaligned_le32(temp, buf); dbg_port (ohci, "GetStatus", wIndex, temp); break; case SetHubFeature: switch (wValue) { case C_HUB_OVER_CURRENT: // FIXME: this can be cleared, yes? case C_HUB_LOCAL_POWER: break; default: goto error; } break; case SetPortFeature: if (!wIndex || wIndex > ports) goto error; wIndex--; switch (wValue) { case USB_PORT_FEAT_SUSPEND: ohci_writel (ohci, RH_PS_PSS, &ohci->regs->roothub.portstatus [wIndex]); break; case USB_PORT_FEAT_POWER: ohci_writel (ohci, RH_PS_PPS, &ohci->regs->roothub.portstatus [wIndex]); break; case USB_PORT_FEAT_RESET: retval = root_port_reset (ohci, wIndex); break; default: goto error; } break; default: error: /* "protocol stall" on error */ retval = -EPIPE; } return retval; }
rh_queue_status
static void rh_timer_func (unsigned long _hcd)
{
usb_hcd_poll_rh_status((struct usb_hcd *) _hcd);
}
static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb)
{
int retval;
unsigned long flags;
unsigned len = 1 + (urb->dev->maxchild / 8);
spin_lock_irqsave (&hcd_root_hub_lock, flags);
if (hcd->status_urb || urb->transfer_buffer_length < len) {
dev_dbg (hcd->self.controller, "not queuing rh status urb\n");
retval = -EINVAL;
goto done;
}
retval = usb_hcd_link_urb_to_ep(hcd, urb);
if (retval)
goto done;
hcd->status_urb = urb;
urb->hcpriv = hcd; /* indicate it's queued */
if (!hcd->uses_new_polling)
mod_timer(&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4));
/* If a status change has already occurred, report it ASAP */
else if (HCD_POLL_PENDING(hcd))
mod_timer(&hcd->rh_timer, jiffies);
retval = 0;
done:
spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
return retval;
}
static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb) { if (usb_endpoint_xfer_int(&urb->ep->desc)) return rh_queue_status (hcd, urb); if (usb_endpoint_xfer_control(&urb->ep->desc)) return rh_call_control (hcd, urb); return -EINVAL; }
int端点是虚拟的中断端点,driver通过他不断去polling hub的状态,usb_hcd_poll_rh_status就是这个polling调用的函数。
相关文章推荐
- Deploy .Net project automatically with MsBuild and MsDeploy (0)
- uitableview使用优化
- View requires API level 14 (current min is 8)
- View requires API level 14 (current min is 8)
- EasyUI DataGrid 应用示例
- UITextField在弹出的键盘上方,加一个带有完成按钮的toolBar工具栏
- [LeetCode]Longest Increasing Subsequence
- [LeetCode]Longest Increasing Subsequence
- iOS之自动生成UUID
- android ui的几个概念:px,dip(dp),sp,dpi,分辨率等
- EAS BOS代码添加F7Query
- Week1-7Linguistics
- Building fw printenv and fw setenv
- Web Service单元测试工具实例介绍之SoapUI
- Easyui的一些简单用法
- 关于论文Silhouteete-based human action recognition using sequences of key poses
- ios UITextView的placeHolder的设置
- easyUI datagrid导出excel(所见即所得)
- Codeforces Round #328 (Div. 2)B. The Monster and the Squirrel
- UITableView和UITableViewCell 图解