您的位置:首页 > 产品设计 > UI/UE

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调用的函数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: