Linux gadget驱动分析2------设备识别过程

设备连上主机之后,设备驱动做了的事.

设备连上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的请求做相应的动作,函数大体流程就是这样,细节部分以后再慢慢研究

原文地址:https://www.cnblogs.com/fengeryi/p/3374590.html