接下来看看当机器插入电脑之后是怎么跑的
首先看看这个函数
static irqreturn_t udc_irq(void)
{
struct ci13xxx *udc = _udc;
irqreturn_t retval;
u32 intr;
trace();
// printk("matt-udc_irq\n");
if (udc == NULL) {
err("ENODEV");
return IRQ_HANDLED;
}
//printk("matt-udc_irq+1\n");
spin_lock(udc->lock);
if (udc->udc_driver->in_lpm && udc->udc_driver->in_lpm(udc)) {
spin_unlock(udc->lock);
return IRQ_NONE;
}
//printk("matt-udc_irq++2\n");
if (udc->udc_driver->flags & CI13XXX_REGS_SHARED) {
if (hw_cread(CAP_USBMODE, USBMODE_CM) !=
USBMODE_CM_DEVICE) {
spin_unlock(udc->lock);
return IRQ_NONE;
}
}
//printk("matt-udc_irq++3\n");
intr = hw_test_and_clear_intr_active();
if (intr) {
isr_statistics.hndl.buf[isr_statistics.hndl.idx++] = intr;
isr_statistics.hndl.idx &= ISR_MASK;
isr_statistics.hndl.cnt++;
/* order defines priority - do NOT change it */
if (USBi_URI & intr) {
isr_statistics.uri++;
if (!hw_cread(CAP_PORTSC, PORTSC_PR))
pr_info("%s: USB reset interrupt is delayed\n",
__func__);
printk("matt-udc_irq++5\n");
isr_reset_handler(udc);
}
if (USBi_PCI & intr) {
isr_statistics.pci++;
printk("matt-udc_irq++6\n");
isr_resume_handler(udc);
}
if (USBi_UEI & intr)
isr_statistics.uei++;
if (USBi_UI & intr) {
//printk("matt-udc_irq++7\n");
isr_statistics.ui++;
udc->gadget.xfer_isr_count++;
isr_tr_complete_handler(udc);
}
if (USBi_SLI & intr) {
printk("matt-udc_irq++8\n");
isr_suspend_handler(udc);
isr_statistics.sli++;
}
retval = IRQ_HANDLED;
} else {
printk("matt-udc_irq++4\n");
isr_statistics.none++;
retval = IRQ_NONE;
}
spin_unlock(udc->lock);
return retval;
}
这个irq会一直存在,当usb线插入手机的时候
但是,只有要配置成电脑的usb设备的时候,才会跑到
isr_tr_complete_handler(udc);
这里是好好干事去,不然就是转一圈就出来,不干正事
首先先回顾一下USB设备枚举都要完成那些步骤吧:
(1)设备插入主机,主机检测到设备。复位设备
(2)主机向设备控制端点发送Get_Descriptor来了解设备默认管道的大小。
(3)主机指定一个地址,发送Set_Address标准请求设置设备的地址
(4)主机使用新的地址,再次发送Get_Descriptor或得各种描述符
(5)主机加载一个USB设备驱动
(6)USB设备驱动再发送Set_Confuration标准设备请求配置设备
以上就是USB设备枚举的过程。USB设备必须正确的相应主机的要求才能顺利的完成设备枚举。我们知道USB是主从式总线结构,全部通信都是由主机发起,设备没有一点自主权。msm8916 USB设备控制器,当主机向USB设备发送一个包时,USB设备控制器就会产生相应的中断。当出现传输错误的时候,也会以中断的形式来通知。所以理解USB设备控制器的中断是理解USB通信过程的关键。在设备初始化的时候已经注册了中断处理程序:
static void isr_tr_complete_handler(struct ci13xxx *udc)
__releases(udc->lock)
__acquires(udc->lock)
{
unsigned i;
u8 tmode = 0;
trace("%p", udc);
if (udc == NULL) {
err("EINVAL");
return;
}
// printk("matt-isr_tr_complete_handler hw_ep_max=%d\n ",hw_ep_max);
for (i = 0; i < hw_ep_max; i++) {
struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i]; //先获取endpoint
int type, num, dir, err = -EINVAL;
struct usb_ctrlrequest req;
if (mEp->desc == NULL)
continue; /* not configured */
if (hw_test_and_clear_complete(i)) {
err = isr_tr_complete_low(mEp);
if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
if (err > 0) /* needs status phase */
err = isr_setup_status_phase(udc);
if (err < 0) {
dbg_event(_usb_addr(mEp),
"ERROR", err);
spin_unlock(udc->lock);
if (usb_ep_set_halt(&mEp->ep))
err("error: ep_set_halt");
spin_lock(udc->lock);
}
}
}
//printk("matt-after continue\n ");
if (mEp->type != USB_ENDPOINT_XFER_CONTROL ||
!hw_test_and_clear_setup_status(i))
continue;
//printk("matt-after continue+1\n ");
if (i != 0) {
warn("ctrl traffic received at endpoint");
continue;
}
//printk("matt-after continue+2\n ");
/*
* Flush data and handshake transactions of previous
* setup packet.
*/
_ep_nuke(&udc->ep0out);
_ep_nuke(&udc->ep0in);
/* read_setup_packet */
do {
hw_test_and_set_setup_guard();
memcpy(&req, &mEp->qh.ptr->setup, sizeof(req));
/* Ensure buffer is read before acknowledging to h/w */
mb();
} while (!hw_test_and_clear_setup_guard());
type = req.bRequestType;
udc->ep0_dir = (type & USB_DIR_IN) ? TX : RX;
dbg_setup(_usb_addr(mEp), &req);
printk("matt-bRequest=%d\n",req.bRequest);
switch (req.bRequest) {
case USB_REQ_CLEAR_FEATURE:
if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
le16_to_cpu(req.wValue) ==
USB_ENDPOINT_HALT) {
if (req.wLength != 0)
break;
num = le16_to_cpu(req.wIndex);
dir = num & USB_ENDPOINT_DIR_MASK;
num &= USB_ENDPOINT_NUMBER_MASK;
if (dir) /* TX */
num += hw_ep_max/2;
if (!udc->ci13xxx_ep[num].wedge) {
spin_unlock(udc->lock);
err = usb_ep_clear_halt(
&udc->ci13xxx_ep[num].ep);
spin_lock(udc->lock);
if (err)
break;
}
err = isr_setup_status_phase(udc);
} else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE) &&
le16_to_cpu(req.wValue) ==
USB_DEVICE_REMOTE_WAKEUP) {
if (req.wLength != 0)
break;
udc->gadget.remote_wakeup = 0;
err = isr_setup_status_phase(udc);
} else {
goto delegate;
}
break;
case USB_REQ_GET_STATUS:
if (type != (USB_DIR_IN|USB_RECIP_DEVICE) &&
type != (USB_DIR_IN|USB_RECIP_ENDPOINT) &&
type != (USB_DIR_IN|USB_RECIP_INTERFACE))
goto delegate;
if (le16_to_cpu(req.wValue) != 0)
break;
err = isr_get_status_response(udc, &req);
break;
case USB_REQ_SET_ADDRESS:
if (type != (USB_DIR_OUT|USB_RECIP_DEVICE))
goto delegate;
if (le16_to_cpu(req.wLength) != 0 ||
le16_to_cpu(req.wIndex) != 0)
break;
err = hw_usb_set_address((u8)le16_to_cpu(req.wValue));
if (err)
break;
err = isr_setup_status_phase(udc);
break;
case USB_REQ_SET_CONFIGURATION:
if (type == (USB_DIR_OUT|USB_TYPE_STANDARD))
udc->configured = !!req.wValue;
goto delegate;
case USB_REQ_SET_FEATURE:
if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
le16_to_cpu(req.wValue) ==
USB_ENDPOINT_HALT) {
if (req.wLength != 0)
break;
num = le16_to_cpu(req.wIndex);
dir = num & USB_ENDPOINT_DIR_MASK;
num &= USB_ENDPOINT_NUMBER_MASK;
if (dir) /* TX */
num += hw_ep_max/2;
spin_unlock(udc->lock);
err = usb_ep_set_halt(&udc->ci13xxx_ep[num].ep);
spin_lock(udc->lock);
if (!err)
isr_setup_status_phase(udc);
} else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE)) {
if (req.wLength != 0)
break;
switch (le16_to_cpu(req.wValue)) {
case USB_DEVICE_REMOTE_WAKEUP:
udc->gadget.remote_wakeup = 1;
err = isr_setup_status_phase(udc);
break;
case USB_DEVICE_B_HNP_ENABLE:
udc->gadget.b_hnp_enable = 1;
err = isr_setup_status_phase(udc);
break;
case USB_DEVICE_A_HNP_SUPPORT:
udc->gadget.a_hnp_support = 1;
err = isr_setup_status_phase(udc);
break;
case USB_DEVICE_A_ALT_HNP_SUPPORT:
break;
case USB_DEVICE_TEST_MODE:
tmode = le16_to_cpu(req.wIndex) >> 8;
switch (tmode) {
case TEST_J:
case TEST_K:
case TEST_SE0_NAK:
case TEST_PACKET:
case TEST_FORCE_EN:
udc->test_mode = tmode;
err = isr_setup_status_phase(
udc);
break;
case TEST_OTG_SRP_REQD:
udc->gadget.otg_srp_reqd = 1;
err = isr_setup_status_phase(
udc);
break;
case TEST_OTG_HNP_REQD:
udc->gadget.host_request = 1;
err = isr_setup_status_phase(
udc);
break;
default:
break;
}
default:
break;
}
} else {
goto delegate;
}
break;
default:
delegate:
if (req.wLength == 0) /* no data phase */
udc->ep0_dir = TX;
spin_unlock(udc->lock);
err = udc->driver->setup(&udc->gadget, &req);
spin_lock(udc->lock);
break;
}
if (err < 0) {
dbg_event(_usb_addr(mEp), "ERROR", err);
spin_unlock(udc->lock);
if (usb_ep_set_halt(&mEp->ep))
err("error: ep_set_halt");
spin_lock(udc->lock);
}
}
}
按照USB设备枚举的过程,最先发生的中断是复位。然后USB主机就会发起一次控制传输来获得设备描述符。这个控制传输是Get_Descriptor标准设备请求。我们知道USB控制传输有数据传输的分为三个阶段,没有数据传输的分为两个阶段。而Get_Descriptor是有数据传输的,USB设备要返回设备描述符号。所以有三个阶段:分别是建立阶段,数据阶段,状态阶段。建立阶段分为三个USB数据包:分别是setup包,data包,与握手包。当建立阶段完毕后,data包的数据会写入端点0的FIFO,s3c2410 USB设备控制器就会产生中断,对应的EP0_CSR的SETUP_END 位就会置位。这时可以判断这个状态。然后调用相应的函数读取在FIFO的数据,判断是控制传输的类型,然后针对不同的类型采取不同的操作,或接受数据,或发送数据。这里的req的结构是
struct usb_ctrlrequest {
__u8 bRequestType;
__u8 bRequest;
__le16 wValue;
__le16 wIndex;
__le16 wLength;
} __attribute__ ((packed));这个结构完全对应于 spec 里的 Table 9-2,描述了主机通过控制传输发送给设备的请求(Device Requests)
控制传输最少要有两个阶段的 transaction,SETUP 和 STATUS,SETUP 和 STATUS 中间的那个 DATA阶段是可有可无的。对于 Out 和 Setup Token 包,
里面的地址域指明了接下来要接收 Data 包的端点,对于 In Token 包,地址域指明了接下来哪个端点要发送 Data 包。还有,只有主机才有权利发送 Token 包。
看看define
#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
再看插入之后的log
matthew@matthew:~$ grep -r "matt-bRequest" ./8.30.6log
matt-bRequest=6
matt-bRequest=5
matt-bRequest=6
matt-bRequest=6
matt-bRequest=9
matt-bRequest=1
[ 83.840849] matt-bRequest=6
[ 83.847191] matt-bRequest=0
[ 83.847878] matt-bRequest=6
[ 83.899541] matt-bRequest=254 //这个地方就是跑了default
[ 84.051386] matt-bRequest=6
matt-bRequest=5
[ 95.402275] matt-bRequest=6
[ 95.405278] matt-bRequest=9
[ 95.405747] matt-bRequest=1
[ 95.406265] matt-bRequest=6
[ 95.836284] matt-bRequest=0
[ 95.836918] matt-bRequest=6
[ 95.837117] matt-bRequest=0
[ 95.837390] matt-bRequest=6
所以首先是USB_REQ_GET_DESCRIPTOR ,也就是上文的发起一次控制传输来获得设备描述符。然后是USB_REQ_SET_ADDRESS,因为设备reset之后,是进入了default状态,所以要获取address。只要 hub 使用 core 里定义的一个函数usb_control_msg,发送 SET_ADDRESS 请求给设备,设备就兴高采烈的迈进 Address了。那么设备的这个 address 是什么,就是上面的 devnum 啊。设备从 Address 发展到了 Configured,SET_CONFIGURATION 请求不需要 DATA transaction,而且还是协议里规定所有设备。Address 有点像你合几代人之力辛辛苦苦才弄到的一套新房子,如果不装修,它对你来说的意义也就是你的户口可以从人才中心挪过去了,可以对人说你的地址是哪儿哪儿了,可实际上你在里边儿什么也干不了,你还得想办法去装修它,Configured 就像是已经装修好的都要支持的标准请求,也不是针对端点或者接口什么的,而是针对设备的。然后是USB_REQ_CLEAR_FEATURE,接着USB_REQ_GET_STATUS。
[ 83.899541] matt-bRequest=254 //这个地方就是跑了default,default是什么呢,是err = udc->driver->setup(&udc->gadget, &req);
这个setup一时看不清,但是之前的文章提过,下面这个setup很长,但是里面处理了一个关键的case:USB_REQ_GET_DESCRIPTOR
这个函数首先提取出USB控制请求的各个字段,然后初始化了端点0的struct usb_request结构。设置了完成回调函数composite_setup_complete。这时通过switch语句来判断是何种控制传输。比如这里是Get_Descriptor,而且设备枚举的时候这时只获取设备描述符的前八个字节以了解端点0的FIFO深度。
int
composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
{
struct usb_composite_dev *cdev = get_gadget_data(gadget);
struct usb_request *req = cdev->req;
int value = -EOPNOTSUPP;
int status = 0;
u16 w_index = le16_to_cpu(ctrl->wIndex);
u8 intf = w_index & 0xFF;
u16 w_value = le16_to_cpu(ctrl->wValue);
u16 w_length = le16_to_cpu(ctrl->wLength);
struct usb_function *f = NULL;
u8 endp;
struct usb_configuration *c;
if (w_length > USB_COMP_EP0_BUFSIZ)
return value;
/* partial re-init of the response message; the function or the
* gadget might need to intercept e.g. a control-OUT completion
* when we delegate to it.
*/
req->zero = 0;
req->complete = composite_setup_complete;
req->length = 0;
gadget->ep0->driver_data = cdev;
switch (ctrl->bRequest) {
/* we handle all standard USB descriptors */
case USB_REQ_GET_DESCRIPTOR:
printk("matt-USB_REQ_GET_DESCRIPTOR\n");
if (ctrl->bRequestType != USB_DIR_IN)
goto unknown;
switch (w_value >> 8) {
case USB_DT_DEVICE:
cdev->desc.bNumConfigurations =
count_configs(cdev, USB_DT_DEVICE);
cdev->desc.bMaxPacketSize0 =
cdev->gadget->ep0->maxpacket;
if (gadget_is_superspeed(gadget)) {
if (gadget->speed >= USB_SPEED_SUPER) {
cdev->desc.bcdUSB = cpu_to_le16(0x0300);
cdev->desc.bMaxPacketSize0 = 9;
} else {
cdev->desc.bcdUSB = cpu_to_le16(0x0210);
}
} else if (gadget->l1_supported) {
cdev->desc.bcdUSB = cpu_to_le16(0x0201);
DBG(cdev, "Config HS device with LPM(L1)\n");
}
value = min(w_length, (u16) sizeof cdev->desc);
memcpy(req->buf, &cdev->desc, value);
break;
case USB_DT_DEVICE_QUALIFIER:
if (!gadget_is_dualspeed(gadget) ||
gadget->speed >= USB_SPEED_SUPER)
break;
device_qual(cdev);
value = min_t(int, w_length,
sizeof(struct usb_qualifier_descriptor));
break;
case USB_DT_OTHER_SPEED_CONFIG:
if (!gadget_is_dualspeed(gadget) ||
gadget->speed >= USB_SPEED_SUPER)
break;
/* FALLTHROUGH */
case USB_DT_CONFIG:
value = config_desc(cdev, w_value);
if (value >= 0)
value = min(w_length, (u16) value);
break;
case USB_DT_OTG:
if (!gadget_is_otg(gadget))
break;
c = list_first_entry(&cdev->configs,
struct usb_configuration, list);
if (c && c->descriptors)
value = usb_find_descriptor_fillbuf(req->buf,
USB_COMP_EP0_BUFSIZ,
c->descriptors,
USB_DT_OTG);
break;
case USB_DT_STRING:
value = get_string(cdev, req->buf,
w_index, w_value & 0xff);
if (value >= 0)
value = min(w_length, (u16) value);
break;
case USB_DT_BOS:
if (gadget_is_superspeed(gadget) ||
gadget->l1_supported) {
value = bos_desc(cdev);
value = min(w_length, (u16) value);
}
break;
}
break;
/* any number of configs can work */
case USB_REQ_SET_CONFIGURATION:
if (ctrl->bRequestType != 0)
goto unknown;
if (gadget_is_otg(gadget)) {
if (gadget->a_hnp_support)
DBG(cdev, "HNP available\n");
else if (gadget->a_alt_hnp_support)
DBG(cdev, "HNP on another port\n");
else
VDBG(cdev, "HNP inactive\n");
}
spin_lock(&cdev->lock);
value = set_config(cdev, ctrl, w_value);
spin_unlock(&cdev->lock);
break;
case USB_REQ_GET_CONFIGURATION:
if (ctrl->bRequestType != USB_DIR_IN)
goto unknown;
if (cdev->config)
*(u8 *)req->buf = cdev->config->bConfigurationValue;
else
*(u8 *)req->buf = 0;
value = min(w_length, (u16) 1);
break;
/* function drivers must handle get/set altsetting; if there's
* no get() method, we know only altsetting zero works.
*/
case USB_REQ_SET_INTERFACE:
if (ctrl->bRequestType != USB_RECIP_INTERFACE)
goto unknown;
if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
break;
f = cdev->config->interface[intf];
if (!f)
break;
if (w_value && !f->set_alt)
break;
/*
* We put interfaces in default settings (alt 0)
* upon set config#1. Call set_alt for non-zero
* alternate setting.
*/
if (!w_value && cdev->config) {
value = 0;
break;
}
value = f->set_alt(f, w_index, w_value);
if (value == USB_GADGET_DELAYED_STATUS) {
DBG(cdev,
"%s: interface %d (%s) requested delayed status\n",
__func__, intf, f->name);
cdev->delayed_status++;
DBG(cdev, "delayed_status count %d\n",
cdev->delayed_status);
}
break;
case USB_REQ_GET_INTERFACE:
if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
goto unknown;
if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
break;
f = cdev->config->interface[intf];
if (!f)
break;
/* lots of interfaces only need altsetting zero... */
value = f->get_alt ? f->get_alt(f, w_index) : 0;
if (value < 0)
break;
*((u8 *)req->buf) = value;
value = min(w_length, (u16) 1);
break;
/*
* USB 3.0 additions:
* Function driver should handle get_status request. If such cb
* wasn't supplied we respond with default value = 0
* Note: function driver should supply such cb only for the first
* interface of the function
*/
case USB_REQ_GET_STATUS:
if (!gadget_is_superspeed(gadget))
goto unknown;
if (ctrl->bRequestType != (USB_DIR_IN | USB_RECIP_INTERFACE))
goto unknown;
value = 2; /* This is the length of the get_status reply */
put_unaligned_le16(0, req->buf);
if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
break;
f = cdev->config->interface[intf];
if (!f)
break;
status = f->get_status ? f->get_status(f) : 0;
if (status < 0)
break;
put_unaligned_le16(status & 0x0000ffff, req->buf);
break;
/*
* Function drivers should handle SetFeature/ClearFeature
* (FUNCTION_SUSPEND) request. function_suspend cb should be supplied
* only for the first interface of the function
*/
case USB_REQ_CLEAR_FEATURE:
case USB_REQ_SET_FEATURE:
if (!gadget_is_superspeed(gadget))
goto unknown;
if (ctrl->bRequestType != (USB_DIR_OUT | USB_RECIP_INTERFACE))
goto unknown;
switch (w_value) {
case USB_INTRF_FUNC_SUSPEND:
if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
break;
f = cdev->config->interface[intf];
if (!f)
break;
value = 0;
if (f->func_suspend) {
const u8 suspend_opt = w_index >> 8;
value = f->func_suspend(f, suspend_opt);
DBG(cdev, "%s function: FUNCTION_SUSPEND(%u)",
f->name ? f->name : "", suspend_opt);
}
if (value < 0) {
ERROR(cdev,
"func_suspend() returned error %d\n",
value);
value = 0;
}
break;
}
break;
default:
unknown:
VDBG(cdev,
"non-core control req%02x.%02x v%04x i%04x l%d\n",
ctrl->bRequestType, ctrl->bRequest,
w_value, w_index, w_length);
/* functions always handle their interfaces and endpoints...
* punt other recipients (other, WUSB, ...) to the current
* configuration code.
*
* REVISIT it could make sense to let the composite device
* take such requests too, if that's ever needed: to work
* in config 0, etc.
*/
switch (ctrl->bRequestType & USB_RECIP_MASK) {
case USB_RECIP_INTERFACE:
if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
break;
f = cdev->config->interface[intf];
break;
case USB_RECIP_ENDPOINT:
endp = ((w_index & 0x80) >> 3) | (w_index & 0x0f);
list_for_each_entry(f, &cdev->config->functions, list) {
if (test_bit(endp, f->endpoints))
break;
}
if (&f->list == &cdev->config->functions)
f = NULL;
break;
}
if (f && f->setup)
value = f->setup(f, ctrl);
else {
struct usb_configuration *c;
c = cdev->config;
if (c && c->setup)
value = c->setup(c, ctrl);
}
if (f && value == USB_GADGET_DELAYED_STATUS) {
DBG(cdev,
"%s: interface %d (%s) requested delayed status\n",
__func__, intf, f->name);
cdev->delayed_status++;
DBG(cdev, "delayed_status count %d\n",
cdev->delayed_status);
}
goto done;
}
/* respond with data transfer before status phase? */
if (value >= 0 && value != USB_GADGET_DELAYED_STATUS) {
req->length = value;
req->zero = value < w_length;
value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
if (value < 0) {
DBG(cdev, "ep_queue --> %d\n", value);
req->status = 0;
composite_setup_complete(gadget->ep0, req);
}
} else if (value == USB_GADGET_DELAYED_STATUS && w_length != 0) {
WARN(cdev,
"%s: Delayed status not supported for w_length != 0",
__func__);
}
done:
/* device either stalls (value < 0) or reports success */
return value;
}
这个setup怎么和udc关联起来的呢
static const struct usb_gadget_driver composite_driver_template = {
.bind = composite_bind,
.unbind = composite_unbind,
.setup = composite_setup,
.disconnect = composite_disconnect,
.suspend = composite_suspend,
.resume = composite_resume,
.driver = {
.owner = THIS_MODULE,
},
};
这下看着很熟了吧