📄 usbdev.c
字号:
list = &ep->inlist; if (!async && list->count) { halt_dma(ep->indma); flush_pkt_list(list); } link_tail(ep, list, pkt); vdbg("%s: ep%d, pkt=%p, size=%d, list count=%d", __FUNCTION__, ep->address, pkt, pkt->size, list->count); if (list->count == 1) { /* * if the packet count is one, it means the list was empty, * and no more data will go out this ep until we kick-start * it again. */ kickstart_send_packet(ep); } return pkt->size;}/* * This routine is called to restart reception of a packet. * EP spinlock must be held when calling. */static voidkickstart_receive_packet(endpoint_t * ep){ usbdev_pkt_t *pkt; // get and link a new packet for next reception if (!(pkt = add_packet(ep, &ep->outlist, ep->max_pkt_size))) { err("%s: could not alloc new packet", __FUNCTION__); return; } if (get_dma_active_buffer(ep->outdma) == 1) { clear_dma_done1(ep->outdma); set_dma_count1(ep->outdma, ep->max_pkt_size); set_dma_count0(ep->outdma, 0); set_dma_addr1(ep->outdma, virt_to_phys(pkt->payload)); enable_dma_buffer1(ep->outdma); // reenable } else { clear_dma_done0(ep->outdma); set_dma_count0(ep->outdma, ep->max_pkt_size); set_dma_count1(ep->outdma, 0); set_dma_addr0(ep->outdma, virt_to_phys(pkt->payload)); enable_dma_buffer0(ep->outdma); // reenable } if (dma_halted(ep->outdma)) start_dma(ep->outdma);}/* * This routine is called when a packet in the outlist has been * completed (received) and we need to prepare for a new packet * to be received. Halts DMA and computes the packet size from the * remaining DMA counter. Then prepares a new packet for reception * and restarts DMA. FIXME: what if another packet comes in * on top of the completed packet? Counter would be wrong. * EP spinlock must be held when calling. */static usbdev_pkt_t *receive_packet_complete(endpoint_t * ep){ usbdev_pkt_t *pkt = ep->outlist.tail; u32 cs; halt_dma(ep->outdma); cs = au_readl(ep->reg->ctrl_stat); if (!pkt) return NULL; pkt->size = ep->max_pkt_size - get_dma_residue(ep->outdma); if (pkt->size) dma_cache_inv((unsigned long)pkt->payload, pkt->size); /* * need to pull out any remaining bytes in the FIFO. */ endpoint_fifo_read(ep); /* * should be drained now, but flush anyway just in case. */ flush_read_fifo(ep); pkt->status = (cs & USBDEV_CS_NAK) ? PKT_STATUS_NAK : PKT_STATUS_ACK; if (ep->address == 0 && (cs & USBDEV_CS_SU)) pkt->status |= PKT_STATUS_SU; vdbg("%s: ep%d, %s pkt=%p, size=%d", __FUNCTION__, ep->address, (pkt->status & PKT_STATUS_NAK) ? "NAK" : "ACK", pkt, pkt->size); kickstart_receive_packet(ep); return pkt;}/* **************************************************************************** * Here starts the standard device request handlers. They are * all called by do_setup() via a table of function pointers. **************************************************************************** */static ep0_stage_tdo_get_status(struct usb_dev* dev, struct usb_ctrlrequest* setup){ switch (setup->bRequestType) { case 0x80: // Device // FIXME: send device status break; case 0x81: // Interface // FIXME: send interface status break; case 0x82: // End Point // FIXME: send endpoint status break; default: // Invalid Command endpoint_stall(&dev->ep[0]); // Stall End Point 0 break; } return STATUS_STAGE;}static ep0_stage_tdo_clear_feature(struct usb_dev* dev, struct usb_ctrlrequest* setup){ switch (setup->bRequestType) { case 0x00: // Device if ((le16_to_cpu(setup->wValue) & 0xff) == 1) dev->remote_wakeup_en = 0; else endpoint_stall(&dev->ep[0]); break; case 0x02: // End Point if ((le16_to_cpu(setup->wValue) & 0xff) == 0) { endpoint_t *ep = epaddr_to_ep(dev, le16_to_cpu(setup->wIndex) & 0xff); endpoint_unstall(ep); endpoint_reset_datatoggle(ep); } else endpoint_stall(&dev->ep[0]); break; } return SETUP_STAGE;}static ep0_stage_tdo_reserved(struct usb_dev* dev, struct usb_ctrlrequest* setup){ // Invalid request, stall End Point 0 endpoint_stall(&dev->ep[0]); return SETUP_STAGE;}static ep0_stage_tdo_set_feature(struct usb_dev* dev, struct usb_ctrlrequest* setup){ switch (setup->bRequestType) { case 0x00: // Device if ((le16_to_cpu(setup->wValue) & 0xff) == 1) dev->remote_wakeup_en = 1; else endpoint_stall(&dev->ep[0]); break; case 0x02: // End Point if ((le16_to_cpu(setup->wValue) & 0xff) == 0) { endpoint_t *ep = epaddr_to_ep(dev, le16_to_cpu(setup->wIndex) & 0xff); endpoint_stall(ep); } else endpoint_stall(&dev->ep[0]); break; } return SETUP_STAGE;}static ep0_stage_tdo_set_address(struct usb_dev* dev, struct usb_ctrlrequest* setup){ int new_state = dev->state; int new_addr = le16_to_cpu(setup->wValue); dbg("%s: our address=%d", __FUNCTION__, new_addr); if (new_addr > 127) { // usb spec doesn't tell us what to do, so just go to // default state new_state = DEFAULT; dev->address = 0; } else if (dev->address != new_addr) { dev->address = new_addr; new_state = ADDRESS; } if (dev->state != new_state) { dev->state = new_state; /* inform function layer of usbdev state change */ dev->func_cb(CB_NEW_STATE, dev->state, dev->cb_data); } return SETUP_STAGE;}static ep0_stage_tdo_get_descriptor(struct usb_dev* dev, struct usb_ctrlrequest* setup){ int strnum, desc_len = le16_to_cpu(setup->wLength); switch (le16_to_cpu(setup->wValue) >> 8) { case USB_DT_DEVICE: // send device descriptor! desc_len = desc_len > dev->dev_desc->bLength ? dev->dev_desc->bLength : desc_len; dbg("sending device desc, size=%d", desc_len); send_packet(dev, alloc_packet(&dev->ep[0], desc_len, dev->dev_desc), 0); break; case USB_DT_CONFIG: // If the config descr index in low-byte of // setup->wValue is valid, send config descr, // otherwise stall ep0. if ((le16_to_cpu(setup->wValue) & 0xff) == 0) { // send config descriptor! if (desc_len <= USB_DT_CONFIG_SIZE) { dbg("sending partial config desc, size=%d", desc_len); send_packet(dev, alloc_packet(&dev->ep[0], desc_len, dev->conf_desc), 0); } else { int len = le16_to_cpu(dev->conf_desc->wTotalLength); dbg("sending whole config desc," " size=%d, our size=%d", desc_len, len); desc_len = desc_len > len ? len : desc_len; send_packet(dev, alloc_packet(&dev->ep[0], desc_len, dev->full_conf_desc), 0); } } else endpoint_stall(&dev->ep[0]); break; case USB_DT_STRING: // If the string descr index in low-byte of setup->wValue // is valid, send string descr, otherwise stall ep0. strnum = le16_to_cpu(setup->wValue) & 0xff; if (strnum >= 0 && strnum < 6) { struct usb_string_descriptor *desc = dev->str_desc[strnum]; desc_len = desc_len > desc->bLength ? desc->bLength : desc_len; dbg("sending string desc %d", strnum); send_packet(dev, alloc_packet(&dev->ep[0], desc_len, desc), 0); } else endpoint_stall(&dev->ep[0]); break; default: // Invalid request err("invalid get desc=%d, stalled", le16_to_cpu(setup->wValue) >> 8); endpoint_stall(&dev->ep[0]); // Stall endpoint 0 break; } return STATUS_STAGE;}static ep0_stage_tdo_set_descriptor(struct usb_dev* dev, struct usb_ctrlrequest* setup){ // TODO: implement // there will be an OUT data stage (the descriptor to set) return DATA_STAGE;}static ep0_stage_tdo_get_configuration(struct usb_dev* dev, struct usb_ctrlrequest* setup){ // send dev->configuration dbg("sending config"); send_packet(dev, alloc_packet(&dev->ep[0], 1, &dev->configuration), 0); return STATUS_STAGE;}static ep0_stage_tdo_set_configuration(struct usb_dev* dev, struct usb_ctrlrequest* setup){ // set active config to low-byte of setup->wValue dev->configuration = le16_to_cpu(setup->wValue) & 0xff; dbg("set config, config=%d", dev->configuration); if (!dev->configuration && dev->state > DEFAULT) { dev->state = ADDRESS; /* inform function layer of usbdev state change */ dev->func_cb(CB_NEW_STATE, dev->state, dev->cb_data); } else if (dev->configuration == 1) { dev->state = CONFIGURED; /* inform function layer of usbdev state change */ dev->func_cb(CB_NEW_STATE, dev->state, dev->cb_data); } else { // FIXME: "respond with request error" - how? } return SETUP_STAGE;}static ep0_stage_tdo_get_interface(struct usb_dev* dev, struct usb_ctrlrequest* setup){ // interface must be zero. if ((le16_to_cpu(setup->wIndex) & 0xff) || dev->state == ADDRESS) { // FIXME: respond with "request error". how? } else if (dev->state == CONFIGURED) { // send dev->alternate_setting dbg("sending alt setting"); send_packet(dev, alloc_packet(&dev->ep[0], 1, &dev->alternate_setting), 0); } return STATUS_STAGE;}static ep0_stage_tdo_set_interface(struct usb_dev* dev, struct usb_ctrlrequest* setup){ if (dev->state == ADDRESS) { // FIXME: respond with "request error". how? } else if (dev->state == CONFIGURED) { dev->interface = le16_to_cpu(setup->wIndex) & 0xff; dev->alternate_setting = le16_to_cpu(setup->wValue) & 0xff; // interface and alternate_setting must be zero if (dev->interface || dev->alternate_setting) { // FIXME: respond with "request error". how? } } return SETUP_STAGE;}static ep0_stage_tdo_synch_frame(struct usb_dev* dev, struct usb_ctrlrequest* setup){ // TODO return SETUP_STAGE;}typedef ep0_stage_t (*req_method_t)(struct usb_dev* dev, struct usb_ctrlrequest* setup);/* Table of the standard device request handlers */static const req_method_t req_method[] = { do_get_status, do_clear_feature, do_reserved, do_set_feature, do_reserved, do_set_address, do_get_descriptor, do_set_descriptor, do_get_configuration, do_set_configuration, do_get_interface, do_set_interface, do_synch_frame};// SETUP packet request dispatcherstatic voiddo_setup (struct usb_dev* dev, struct usb_ctrlrequest* setup){ req_method_t m; dbg("%s: req %d %s", __FUNCTION__, setup->bRequestType, get_std_req_name(setup->bRequestType)); if ((setup->bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD || (setup->bRequestType & USB_RECIP_MASK) != USB_RECIP_DEVICE) { err("%s: invalid requesttype 0x%02x", __FUNCTION__, setup->bRequestType); return; } if ((setup->bRequestType & 0x80) == USB_DIR_OUT && setup->wLength) dbg("%s: OUT phase! length=%d", __FUNCTION__, setup->wLength); if (setup->bRequestType < sizeof(req_method)/sizeof(req_method_t)) m = req_method[setup->bRequestType]; else m = do_reserved; dev->ep0_stage = (*m)(dev, setup);}/* * A SETUP, DATA0, or DATA1 packet has been received * on the default control endpoint's fifo. */static voidprocess_ep0_receive (struct usb_dev* dev){ endpoint_t *ep0 = &dev->ep[0]; usbdev_pkt_t *pkt; spin_lock(&ep0->lock); // complete packet and prepare a new packet pkt = receive_packet_complete(ep0); if (!pkt) { // FIXME: should put a warn/err here. spin_unlock(&ep0->lock); return; } // unlink immediately from endpoint. unlink_head(&ep0->outlist); // override current stage if h/w says it's a setup packet if (pkt->status & PKT_STATUS_SU) dev->ep0_stage = SETUP_STAGE; switch (dev->ep0_stage) { case SETUP_STAGE: vdbg("SU bit is %s in setup stage", (pkt->status & PKT_STATUS_SU) ? "set" : "not set"); if (pkt->size == sizeof(struct usb_ctrlrequest)) {#ifdef VDEBUG if (pkt->status & PKT_STATUS_ACK) vdbg("received SETUP"); else vdbg("received NAK SETUP");#endif do_setup(dev, (struct usb_ctrlrequest*)pkt->payload); } else err("%s: wrong size SETUP received", __FUNCTION__); break; case DATA_STAGE: /* * this setup has an OUT data stage. Of the standard * device requests, only set_descriptor has this stage, * so this packet is that descriptor. TODO: drop it for * now, set_descriptor not implemented. * * Need to place a byte in the write FIFO here, to prepare * to send a zero-length DATA ack packet to the host in the * STATUS stage. */ au_writel(0, ep0->reg->write_fifo); dbg("received OUT stage DATAx on EP0, size=%d", pkt->size); dev->ep0_stage = SETUP_STAGE; break; case STATUS_STAGE: // this setup had an IN data stage, and host is ACK'ing // the packet we sent during that stage. if (pkt->size != 0) warn("received non-zero ACK on EP0??");#ifdef VDEBUG else vdbg("received ACK on EP0");#endif dev->ep0_stage = SETUP_STAGE; break; } spin_unlock(&ep0->lock); // we're done processing the packet, free it kfree(pkt);}/* * A DATA0/1 packet has been received on one of the OUT endpoints (4 or 5) */static voidprocess_ep_receive (struct usb_dev* dev, endpoint_t *ep){ usbdev_pkt_t *pkt; spin_lock(&ep->lock); pkt = receive_packet_complete(ep); spin_unlock(&ep->lock); dev->func_cb(CB_PKT_COMPLETE, (unsigned long)pkt, dev->cb_data);}/* This ISR handles the receive complete and suspend events */static voidreq_sus_intr (int irq, void *dev_id, struct pt_regs *regs){ struct usb_dev *dev = (struct usb_dev *) dev_id; u32 status;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -