设备连上主机之后,设备驱动做了的事.
设备连上host的port之后,主机端会有一套策略发送请求获取device的一系列描述符.进行枚举过程.找到适合该device的驱动. 这样就可以与device进行通信.
usb device这边收到主机的请求,会进入中断处理函数.可以说usb device 控制器的活动都是从中断开始的.
#号之间的都是udc驱动中做的事,大部分与硬件相关,原理应该差不多.
########################nuc900_udc##########################
nuc9xx系列的中断处理函数:
1 static irqreturn_t nuc900_udc_irq(int irq, void *_dev) 2 { 3 struct nuc900_udc *dev; 4 struct nuc900_ep *ep; 5 u32 volatile IrqStL, IrqEnL; 6 u32 volatile IrqSt, IrqEn; 7 int i=0, j; 8 9 dev=(struct nuc900_udc *)(_dev); 10 11 IrqStL = __raw_readl(controller.reg + REG_USBD_IRQ_STAT_L); /* 0x000 register get interrupt status */ 12 IrqEnL = __raw_readl(controller.reg + REG_USBD_IRQ_ENB_L); 13 14 IrqStL = IrqStL & IrqEnL ; 15 if (!IrqStL) { 16 printk("Not our interrupt ! "); 17 return IRQ_HANDLED; 18 } 19 20 if (IrqStL & IRQ_USB_STAT) { 21 IrqSt = __raw_readl(controller.reg + REG_USBD_IRQ_STAT); 22 IrqEn = __raw_readl(controller.reg + REG_USBD_IRQ_ENB); 23 __raw_writel(IrqSt, controller.reg + REG_USBD_IRQ_STAT); 24 25 IrqSt = IrqSt & IrqEn ; 26 27 if (IrqSt && dev->driver) { 28 for (i=0; i<6; i++) { 29 if (IrqSt&(1<<i)) { 30 paser_irq_stat(1<<i,dev); 31 break; 32 } 33 } 34 } 35 36 }//end IRQ_USB_STAT 37 38 39 if (IrqStL & IRQ_CEP) { 40 IrqSt = __raw_readl(controller.reg + REG_USBD_CEP_IRQ_STAT); 41 IrqEn = __raw_readl(controller.reg + REG_USBD_CEP_IRQ_ENB); 42 //printk("cep:%x, %x ", IrqSt, IrqEn); 43 IrqSt = IrqSt & IrqEn ; 44 __raw_writel(IrqSt, controller.reg + REG_USBD_CEP_IRQ_STAT); 45 46 if (IrqSt && dev->driver) { 47 //for(i=12;i>=0;i--) 48 if (IrqSt&CEP_STS_END) { //deal with STS END 49 if (dev->ep0state == EP0_OUT_DATA_PHASE) 50 IrqSt &= 0x1BF7; 51 paser_irq_cep(CEP_STS_END,dev,IrqSt); 52 } 53 for (i=0; i<13; i++) { 54 if (i == 10) 55 continue; 56 if (IrqSt&(1<<i)) { 57 paser_irq_cep(1<<i,dev,IrqSt); 58 //break; 59 } 60 } 61 } 62 } 63 64 if (IrqStL & IRQ_NCEP) { 65 IrqStL >>= 2; 66 67 for (j = 0; j < 6; j++) { //6 endpoints 68 if (IrqStL & (1 << j)) { 69 //in-token and out token interrupt can deal with one only 70 IrqSt = __raw_readl(controller.reg + REG_USBD_EPA_IRQ_STAT + 0x28 * j); 71 IrqEn = __raw_readl(controller.reg + REG_USBD_EPA_IRQ_ENB + 0x28 * j); 72 73 IrqSt = IrqSt & IrqEn ; 74 if (IrqSt && dev->driver) { 75 ep = &dev->ep[j+1]; 76 77 for (i=12; i>=0; i--) { 78 if (IrqSt&(1<<i)) { 79 if ((1<<i) == EP_BO_SHORT_PKT) 80 IrqSt &= 0x1FCF;//clear out token/RxED intr 81 if ((ep->EP_Type == EP_TYPE_BLK) || (ep->EP_Type == EP_TYPE_ISO)) 82 paser_irq_nep(1<<i, ep, IrqSt); 83 else if (ep->EP_Type == EP_TYPE_INT) 84 paser_irq_nepint(1<<i, ep, IrqSt); 85 break; 86 } 87 } 88 } 89 } 90 } 91 }//if end 92 93 return IRQ_HANDLED; 94 95 96 }
基本原理就是从一些相关寄存器中读取出中断的类型,分别进入相应的处理流程.
20行 if (IrqStL & IRQ_USB_STAT) {
就是usb Suspend Resume 等中断发生时会进入该if
39行 if (IrqStL & IRQ_CEP) {
中断是控制端口中断,进入该if语句.
usb host会通过控制端口获取一系列描述符. 所以device这边会先进入这里.
然后再读取中断的子类型
进入 51或57行的
paser_irq_cep(1<<i,dev,IrqSt);
1 void paser_irq_cep(int irq, struct nuc900_udc *dev, u32 IrqSt) 2 { 3 struct nuc900_ep *ep = &dev->ep[0]; 4 struct nuc900_request *req; 5 int is_last=1; 6 7 if (list_empty(&ep->queue)) { 8 req = 0; 9 } else { 10 req = list_entry(ep->queue.next, struct nuc900_request, queue); 11 } 12 13 switch (irq) { 14 case CEP_SUPPKT://receive setup packet 15 dev->ep0state=EP0_IDLE; 16 dev->setup_ret = 0; 17 18 udc_isr_ctrl_pkt(dev); 19 break; 20 21 case CEP_DATA_RXD: 22 23 24 if (dev->ep0state == EP0_OUT_DATA_PHASE) { 25 if (req) 26 is_last = read_fifo(ep,req, 0); 27 28 __raw_writel(0x400, controller.reg + REG_USBD_CEP_IRQ_STAT); 29 30 if (!is_last) 31 __raw_writel(0x440, controller.reg + REG_USBD_CEP_IRQ_ENB);//enable out token and status complete int 32 else { //transfer finished 33 __raw_writel(0x04C, controller.reg + REG_USBD_CEP_IRQ_STAT); 34 __raw_writel(CEP_NAK_CLEAR, controller.reg + REG_USBD_CEP_CTRL_STAT); // clear nak so that sts stage is complete 35 __raw_writel(0x400, controller.reg + REG_USBD_CEP_IRQ_ENB); // suppkt int//enb sts completion int 36 dev->ep0state = EP0_END_XFER; 37 } 38 } 39 40 return; 41 42 case CEP_IN_TOK: 43 44 if ((IrqSt & CEP_STS_END)) 45 dev->ep0state=EP0_IDLE; 46 47 if (dev->setup_ret < 0) { // == -EOPNOTSUPP) 48 printk("CEP send zero pkt "); 49 __raw_writel(CEP_ZEROLEN, controller.reg + REG_USBD_CEP_CTRL_STAT); 50 __raw_writel(0x400, controller.reg + REG_USBD_CEP_IRQ_ENB); //enb sts completion int 51 } 52 53 else if (dev->ep0state == EP0_IN_DATA_PHASE) { 54 55 56 if (req) { 57 is_last = write_fifo(ep,req); 58 } 59 60 61 if (!is_last) 62 __raw_writel(0x408, controller.reg + REG_USBD_CEP_IRQ_ENB); 63 else { 64 if (dev->setup_ret >= 0) 65 __raw_writel(CEP_NAK_CLEAR, controller.reg + REG_USBD_CEP_CTRL_STAT); // clear nak so that sts stage is complete 66 __raw_writel(0x402, controller.reg + REG_USBD_CEP_IRQ_ENB); // suppkt int//enb sts completion int 67 68 if (dev->setup_ret < 0)//== -EOPNOTSUPP) 69 dev->ep0state=EP0_IDLE; 70 else if (dev->ep0state != EP0_IDLE) 71 dev->ep0state=EP0_END_XFER; 72 } 73 } 74 75 return; 76 77 case CEP_PING_TOK: 78 79 __raw_writel(0x402, controller.reg + REG_USBD_CEP_IRQ_ENB); // suppkt int//enb sts completion int 80 return; 81 82 case CEP_DATA_TXD: 83 return; 84 85 case CEP_STS_END: 86 87 __raw_writel(0x4A, controller.reg + REG_USBD_CEP_IRQ_ENB); 88 udc_isr_update_dev(dev); 89 dev->ep0state=EP0_IDLE; 90 dev->setup_ret = 0; 91 92 break; 93 94 default: 95 break; 96 97 } 98 99 return ; 100 101 }
很简单的switch语句,device控制器硬件会根据host发来的包类型设置相应寄存器. 中断处理函数再从该寄存器中获得类型,进入不同的switch分支.
host请求设备描述符是usb控制传输,并通过device的控制端口进行,接下去会进入哪个case分支跟控制传输的流程有关
大体上是 :
1,host发送 setup 到device .device收到后准备相关data
2,host发送 in 到device device收到后发送data到host
3,host 发送 out 到device host 把状态数据发到device
详细流程可参考网上文章.
case setup中
18行 udc_isr_ctrl_pkt(dev);
1 static void udc_isr_ctrl_pkt(struct nuc900_udc *dev) 2 { 3 u32 temp; 4 u32 ReqErr=0; 5 struct nuc900_ep *ep = &dev->ep[0]; 6 struct usb_ctrlrequest crq; 7 struct nuc900_request *req; 8 int ret; 9 10 if (list_empty(&ep->queue)) { 11 //printk("ctrl ep->queue is empty "); 12 req = 0; 13 } else { 14 req = list_entry(ep->queue.next, struct nuc900_request, queue); 15 //printk("req = %x ", req); 16 } 17 18 temp = __raw_readl(controller.reg + REG_USBD_SETUP1_0); 19 20 Get_SetupPacket(&crq,temp); 21 22 dev->crq = crq; 23 24 switch (dev->ep0state) { 25 case EP0_IDLE: 26 switch (crq.bRequest) { 27 28 case USBR_SET_ADDRESS: 29 ReqErr = ((crq.bRequestType == 0) && ((crq.wValue & 0xff00) == 0) 30 && (crq.wIndex == 0) && (crq.wLength == 0)) ? 0 : 1; 31 32 if ((crq.wValue & 0xffff) > 0x7f) { //within 7f 33 ReqErr=1; //Devaddr > 127 34 } 35 36 if (dev->usb_devstate == 3) { 37 ReqErr=1; //Dev is configured 38 } 39 40 if (ReqErr==1) { 41 break; //break this switch loop 42 } 43 44 if (dev->usb_devstate == 2) { 45 if (crq.wValue == 0) 46 dev->usb_devstate = 1; //enter default state 47 dev->usb_address = crq.wValue; //if wval !=0,use new address 48 } 49 50 if (dev->usb_devstate == 1) { 51 if (crq.wValue != 0) { 52 dev->usb_address = crq.wValue; 53 dev->usb_devstate = 2; 54 } 55 } 56 57 break; 58 59 case USBR_SET_CONFIGURATION: 60 ReqErr = ((crq.bRequestType == 0) && ((crq.wValue & 0xff00) == 0) && 61 ((crq.wValue & 0x80) == 0) && (crq.wIndex == 0) && 62 (crq.wLength == 0)) ? 0 : 1; 63 64 if (dev->usb_devstate == 1) { 65 ReqErr=1; 66 } 67 68 if (ReqErr==1) { 69 break; //break this switch loop 70 } 71 72 if (crq.wValue == 0) 73 dev->usb_devstate = 2; 74 else 75 dev->usb_devstate = 3; 76 break; 77 78 case USBR_SET_INTERFACE: 79 ReqErr = ((crq.bRequestType == 0x1) && ((crq.wValue & 0xff80) == 0) 80 && ((crq.wIndex & 0xfff0) == 0) && (crq.wLength == 0)) ? 0 : 1; 81 82 if (!((dev->usb_devstate == 0x3) && (crq.wIndex == 0x0) && (crq.wValue == 0x0))) 83 ReqErr=1; 84 85 if (ReqErr == 1) { 86 break; //break this switch loop 87 } 88 89 break; 90 91 default: 92 break; 93 }//switch end 94 95 if (crq.bRequestType & USB_DIR_IN) { 96 dev->ep0state = EP0_IN_DATA_PHASE; 97 __raw_writel(0x08, controller.reg + REG_USBD_CEP_IRQ_ENB); 98 } else { 99 dev->ep0state = EP0_OUT_DATA_PHASE; 100 __raw_writel(0x40, controller.reg + REG_USBD_CEP_IRQ_ENB); 101 } 102 103 ret = dev->driver->setup(&dev->gadget, &crq); 104 dev->setup_ret = ret; 105 if (ret < 0) { 106 107 __raw_writel(0x400, controller.reg + REG_USBD_CEP_IRQ_STAT); 108 __raw_writel(0x448, controller.reg + REG_USBD_CEP_IRQ_ENB); // enable in/RxED/status complete interrupt 109 __raw_writel(CEP_NAK_CLEAR, controller.reg + REG_USBD_CEP_CTRL_STAT); //clear nak so that sts stage is complete 110 111 112 if (ret == -EOPNOTSUPP) 113 printk("Operation %x not supported ", crq.bRequest); 114 else { 115 printk("dev->driver->setup failed. (%d) ",ret); 116 } 117 } else if (ret > 1000) { //DELAYED_STATUS 118 printk("DELAYED_STATUS:%p ", req); 119 dev->ep0state = EP0_END_XFER; 120 __raw_writel(0, controller.reg + REG_USBD_CEP_IRQ_ENB); 121 } 122 123 break; 124 125 case EP0_STALL: 126 break; 127 default: 128 break; 129 } 130 131 if (ReqErr == 1) { 132 __raw_writel(CEP_SEND_STALL, controller.reg + REG_USBD_CEP_CTRL_STAT); 133 dev->ep0state = EP0_STALL; 134 } 135 136 }
18 20行就是从寄存器拿出来setup 包的数据,放到 struct usb_ctrlrequest crq;
struct usb_ctrlrequest {
__u8 bRequestType;
__u8 bRequest;
__le16 wValue;
__le16 wIndex;
__le16 wLength;
} __attribute__ ((packed));
这个数据结构与usb协议里的定义相一致.
下面的操作全是围绕这个结构进行的.
如果请bRequest是USBR_SET_ADDRESS, USBR_SET_CONFIGURATION,USBR_SET_INTERFACE.就地处理.
如果不是,进入103行的 调用gadget驱动的setup函数.
########################nuc900_udc##########################
这个setup就是上一篇
static struct usb_gadget_driver composite_driver = {
.speed = USB_SPEED_HIGH,
.bind = composite_bind,
.unbind = composite_unbind,
.setup = composite_setup,
.disconnect = composite_disconnect,
.suspend = composite_suspend,
.resume = composite_resume,
.driver = {
.owner = THIS_MODULE,
},
};
中的setup,就是composite_setup
1 /* 2 * The setup() callback implements all the ep0 functionality that's 3 * not handled lower down, in hardware or the hardware driver(like 4 * device and endpoint feature flags, and their status). It's all 5 * housekeeping for the gadget function we're implementing. Most of 6 * the work is in config and function specific setup. 7 */ 8 static int 9 composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) 10 { 11 struct usb_composite_dev *cdev = get_gadget_data(gadget); 12 struct usb_request *req = cdev->req; 13 int value = -EOPNOTSUPP; 14 u16 w_index = le16_to_cpu(ctrl->wIndex); 15 u8 intf = w_index & 0xFF; 16 u16 w_value = le16_to_cpu(ctrl->wValue); 17 u16 w_length = le16_to_cpu(ctrl->wLength); 18 struct usb_function *f = NULL; 19 u8 endp; 20 21 /* partial re-init of the response message; the function or the 22 * gadget might need to intercept e.g. a control-OUT completion 23 * when we delegate to it. 24 */ 25 req->zero = 0; 26 req->complete = composite_setup_complete; 27 req->length = USB_BUFSIZ; 28 gadget->ep0->driver_data = cdev; 29 30 switch (ctrl->bRequest) { 31 32 /* we handle all standard USB descriptors */ 33 case USB_REQ_GET_DESCRIPTOR: 34 if (ctrl->bRequestType != USB_DIR_IN) 35 goto unknown; 36 switch (w_value >> 8) { 37 38 case USB_DT_DEVICE: // 1 39 cdev->desc.bNumConfigurations = 40 count_configs(cdev, USB_DT_DEVICE); 41 value = min(w_length, (u16) sizeof cdev->desc); 42 memcpy(req->buf, &cdev->desc, value); 43 break; 44 case USB_DT_DEVICE_QUALIFIER: 45 if (!gadget_is_dualspeed(gadget)) 46 break; 47 device_qual(cdev); 48 value = min_t(int, w_length, 49 sizeof(struct usb_qualifier_descriptor)); 50 break; 51 case USB_DT_OTHER_SPEED_CONFIG: 52 if (!gadget_is_dualspeed(gadget)) 53 break; 54 /* FALLTHROUGH */ 55 case USB_DT_CONFIG: // 2 若干次跟config个数有关 56 value = config_desc(cdev, w_value); 57 if (value >= 0) 58 value = min(w_length, (u16) value); 59 break; 60 case USB_DT_STRING: // 3 若干次跟function个数有关 61 value = get_string(cdev, req->buf, 62 w_index, w_value & 0xff); 63 if (value >= 0) 64 value = min(w_length, (u16) value); 65 break; 66 } 67 break; 68 69 /* any number of configs can work */ 70 case USB_REQ_SET_CONFIGURATION: // 4 71 if (ctrl->bRequestType != 0) 72 goto unknown; 73 if (gadget_is_otg(gadget)) { 74 if (gadget->a_hnp_support) 75 DBG(cdev, "HNP available "); 76 else if (gadget->a_alt_hnp_support) 77 DBG(cdev, "HNP on another port "); 78 else 79 VDBG(cdev, "HNP inactive "); 80 } 81 spin_lock(&cdev->lock); 82 value = set_config(cdev, ctrl, w_value); 83 spin_unlock(&cdev->lock); 84 break; 85 case USB_REQ_GET_CONFIGURATION: 86 if (ctrl->bRequestType != USB_DIR_IN) 87 goto unknown; 88 if (cdev->config) 89 *(u8 *)req->buf = cdev->config->bConfigurationValue; 90 else 91 *(u8 *)req->buf = 0; 92 value = min(w_length, (u16) 1); 93 break; 94 95 /* function drivers must handle get/set altsetting; if there's 96 * no get() method, we know only altsetting zero works. 97 */ 98 case USB_REQ_SET_INTERFACE: 99 if (ctrl->bRequestType != USB_RECIP_INTERFACE) 100 goto unknown; 101 if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES) 102 break; 103 f = cdev->config->interface[intf]; 104 if (!f) 105 break; 106 if (w_value && !f->set_alt) 107 break; 108 value = f->set_alt(f, w_index, w_value); 109 break; 110 case USB_REQ_GET_INTERFACE: 111 if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)) 112 goto unknown; 113 if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES) 114 break; 115 f = cdev->config->interface[intf]; 116 if (!f) 117 break; 118 /* lots of interfaces only need altsetting zero... */ 119 value = f->get_alt ? f->get_alt(f, w_index) : 0; 120 if (value < 0) 121 break; 122 *((u8 *)req->buf) = value; 123 value = min(w_length, (u16) 1); 124 break; 125 default: 126 unknown: 127 VDBG(cdev, 128 "non-core control req%02x.%02x v%04x i%04x l%d ", 129 ctrl->bRequestType, ctrl->bRequest, 130 w_value, w_index, w_length); 131 132 /* functions always handle their interfaces and endpoints... 133 * punt other recipients (other, WUSB, ...) to the current 134 * configuration code. 135 * 136 * REVISIT it could make sense to let the composite device 137 * take such requests too, if that's ever needed: to work 138 * in config 0, etc. 139 */ 140 switch (ctrl->bRequestType & USB_RECIP_MASK) { 141 case USB_RECIP_INTERFACE: 142 f = cdev->config->interface[intf]; 143 break; 144 145 case USB_RECIP_ENDPOINT: 146 endp = ((w_index & 0x80) >> 3) | (w_index & 0x0f); 147 list_for_each_entry(f, &cdev->config->functions, list) { 148 if (test_bit(endp, f->endpoints)) 149 break; 150 } 151 if (&f->list == &cdev->config->functions) 152 f = NULL; 153 break; 154 } 155 156 if (f && f->setup) 157 value = f->setup(f, ctrl); 158 else { 159 struct usb_configuration *c; 160 161 c = cdev->config; 162 if (c && c->setup) 163 value = c->setup(c, ctrl); 164 } 165 166 goto done; 167 } 168 169 /* respond with data transfer before status phase? */ 170 if (value >= 0) { 171 req->length = value; 172 req->zero = value < w_length; 173 value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); 174 if (value < 0) { 175 DBG(cdev, "ep_queue --> %d ", value); 176 req->status = 0; 177 composite_setup_complete(gadget->ep0, req); 178 } 179 } 180 181 done: 182 /* device either stalls (value < 0) or reports success */ 183 return value; 184 }
这个函数做的就是根据host发来的请求,填充相应的req->buf,然后在最后173行,把req挂到req list上.
按照usb控制传输,setup阶段之后,是datain阶段. host会发送intoken包, device接到该包,会进到上面贴的paser_irq_cep函数的42行的case中调用 write_fifo.
write_fifo把数据写到缓冲区,并把req从req list上拿掉.
这个函数157行调用function的setup,处理特殊的setup请求.
之前的内核没有composite这一层,每一种gadget设备,都要有一个setup函数,后来的内核把通用的内容都放到了composite.c. 写gadget 驱动就简化了些.
设备识别时device这边是跟着host的请求做相应的动作,函数大体流程就是这样,细节部分以后再慢慢研究