/** * udc_startup - allow udc code to do any additional startup */ void udc_startup_events (struct usb_device_instance *device) { /* The DEVICE_INIT event puts the USB device in the state STATE_INIT. */ usbd_device_event_irq (device, DEVICE_INIT, 0); /* The DEVICE_CREATE event puts the USB device in the state * STATE_ATTACHED. */ usbd_device_event_irq (device, DEVICE_CREATE, 0); /* Some USB controller driver implementations signal * DEVICE_HUB_CONFIGURED and DEVICE_RESET events here. * DEVICE_HUB_CONFIGURED causes a transition to the state STATE_POWERED, * and DEVICE_RESET causes a transition to the state STATE_DEFAULT. * The OMAP USB client controller has the capability to detect when the * USB cable is connected to a powered USB bus via the ATT bit in the * DEVSTAT register, so we will defer the DEVICE_HUB_CONFIGURED and * DEVICE_RESET events until later. */ /* The GTA01 can detect usb device attachment, but we just assume being * attached for now (go to STATE_POWERED) */ usbd_device_event_irq (device, DEVICE_HUB_CONFIGURED, 0); udc_enable (device); }
/* Handle general USB interrupts and dispatch according to type. * This function implements TRM Figure 14-13. */ void S3C24X0_udc_irq(void) { struct usb_endpoint_instance *ep0 = udc_device->bus->endpoint_array; u_int32_t save_idx = inl(S3C24X0_UDC_INDEX_REG); /* read interrupt sources */ u_int32_t usb_status = inl(S3C24X0_UDC_USB_INT_REG); u_int32_t usbd_status = inl(S3C24X0_UDC_EP_INT_REG); debug("< IRQ usbs=0x%02x, usbds=0x%02x start > \n", usb_status, usbd_status); /* clear interrupts */ outl(usb_status, S3C24X0_UDC_USB_INT_REG); if (usb_status & S3C24X0_UDC_USBINT_RESET) { //serial_putc('R'); debug("RESET pwr=0x%x\n", inl(S3C24X0_UDC_PWR_REG)); udc_setup_ep(udc_device, 0, ep0); outl(S3C24X0_UDC_EP0_CSR_SSE|S3C24X0_UDC_EP0_CSR_SOPKTRDY, S3C24X0_UDC_EP0_CSR_REG); ep0->state = EP0_IDLE; usbd_device_event_irq (udc_device, DEVICE_RESET, 0); } if (usb_status & S3C24X0_UDC_USBINT_RESUME) { debug("RESUME\n"); usbd_device_event_irq(udc_device, DEVICE_BUS_ACTIVITY, 0); } if (usb_status & S3C24X0_UDC_USBINT_SUSPEND) { debug("SUSPEND\n"); usbd_device_event_irq(udc_device, DEVICE_BUS_INACTIVE, 0); } /* Endpoint Interrupts */ if (usbd_status) { int i; if (usbd_status & S3C24X0_UDC_INT_EP0) { outl(S3C24X0_UDC_INT_EP0, S3C24X0_UDC_EP_INT_REG); S3C24X0_udc_ep0(); } for (i = 1; i < 5; i++) { u_int32_t tmp = 1 << i; if (usbd_status & tmp) { /* FIXME: Handle EP X */ outl(tmp, S3C24X0_UDC_EP_INT_REG); S3C24X0_udc_epn(i); } } } S3C24X0_UDC_SETIX(save_idx); }
static void musb_peri_ep0_zero_data_request(int err) { musb_peri_ep0_ack_req(); if (err) { musb_peri_ep0_stall(); SET_EP0_STATE(IDLE); } else { musb_peri_ep0_last(); /* USBD state */ switch (ep0_urb->device_request.bRequest) { case USB_REQ_SET_ADDRESS: if ((debug_setup) && (debug_level > 1)) serial_printf("INFO : %s received set " "address\n", __PRETTY_FUNCTION__); break; case USB_REQ_SET_CONFIGURATION: if ((debug_setup) && (debug_level > 1)) serial_printf("INFO : %s Configured\n", __PRETTY_FUNCTION__); usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0); break; } /* EP0 state */ if (USB_REQ_SET_ADDRESS == ep0_urb->device_request.bRequest) { SET_EP0_STATE(SET_ADDRESS); } else { SET_EP0_STATE(IDLE); } } }
void udc_startup_events(struct usb_device_instance *device) { /* The DEVICE_INIT event puts the USB device in the state STATE_INIT. */ usbd_device_event_irq(device, DEVICE_INIT, 0); /* * The DEVICE_CREATE event puts the USB device in the state * STATE_ATTACHED. */ usbd_device_event_irq(device, DEVICE_CREATE, 0); /* Resets the address to 0 */ usbd_device_event_irq(device, DEVICE_RESET, 0); udc_enable(device); }
void usbd_device_event (struct usb_device_instance *device, usb_device_event_t event, int data) { unsigned long flags; local_irq_save (flags); usbd_device_event_irq (device, event, data); local_irq_restore (flags); }
/* udc_startup_events * * Enable the specified device */ void udc_startup_events (struct usb_device_instance *device) { udc_enable (device); if (udc_state == STATE_READY) { usbd_device_event_irq (device, DEVICE_CREATE, 0); } }
/* Allow udc code to do any additional startup */ void udc_startup_events(struct usb_device_instance *device) { /* The DEVICE_INIT event puts the USB device in the state STATE_INIT */ usbd_device_event_irq(device, DEVICE_INIT, 0); /* The DEVICE_CREATE event puts the USB device in the state * STATE_ATTACHED */ usbd_device_event_irq(device, DEVICE_CREATE, 0); /* Some USB controller driver implementations signal * DEVICE_HUB_CONFIGURED and DEVICE_RESET events here. * DEVICE_HUB_CONFIGURED causes a transition to the state * STATE_POWERED, and DEVICE_RESET causes a transition to * the state STATE_DEFAULT. */ udc_enable(device); }
static void usb_dev_hand_reset(void) { u32 temp; temp = readl(USB_DEVICEADDR); temp &= ~0xfe000000; writel(temp, USB_DEVICEADDR); writel(readl(USB_ENDPTSETUPSTAT), USB_ENDPTSETUPSTAT); writel(readl(USB_ENDPTCOMPLETE), USB_ENDPTCOMPLETE); while (readl(USB_ENDPTPRIME)) ; writel(0xffffffff, USB_ENDPTFLUSH); DBG("reset-PORTSC=%x\n", readl(USB_PORTSC1)); usbd_device_event_irq(udc_device, DEVICE_RESET, 0); }
/** * udc_cable_event - called from cradle interrupt handler */ void udc_cable_event(void) { struct usb_bus_instance *bus; struct usb_device_instance *device; struct bi_data *data; dbgENTER(dbgflg_usbdbi_init,1); // sanity check if (!(device = device_array[0]) || !(bus = device->bus) || !(data = bus->privdata)) { return; } { unsigned long flags; local_irq_save(flags); if (udc_connected()) { dbg_init(1, "state: %d connected: %d", device->device_state, 1);; if (device->device_state == STATE_ATTACHED) { dbg_init(1, "LOADING"); usbd_device_event_irq(device, DEVICE_HUB_CONFIGURED, 0); usbd_device_event_irq(device, DEVICE_RESET, 0); } } else { dbg_init(1, "state: %d connected: %d", device->device_state, 0);; if (device->device_state != STATE_ATTACHED) { dbg_init(1, "UNLOADING"); usbd_device_event_irq(device, DEVICE_RESET, 0); usbd_device_event_irq(device, DEVICE_POWER_INTERRUPTION, 0); usbd_device_event_irq(device, DEVICE_HUB_RESET, 0); } } local_irq_restore(flags); } dbgLEAVE(dbgflg_usbdbi_init,1); }
static void udc_state_changed(void) { int config, interface, alternate; writel(readl(UDCCR) | UDCCR_SMAC, UDCCR); config = (readl(UDCCR) & UDCCR_ACN) >> UDCCR_ACN_S; interface = (readl(UDCCR) & UDCCR_AIN) >> UDCCR_AIN_S; alternate = (readl(UDCCR) & UDCCR_AAISN) >> UDCCR_AAISN_S; usbdbg("New UDC settings are: conf %d - inter %d - alter %d", config, interface, alternate); usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0); writel(UDCISR1_IRCC, UDCISR1); }
static void musb_peri_ep0_set_address(void) { u8 faddr; writeb(udc_device->address, &musbr->faddr); /* Verify */ faddr = readb(&musbr->faddr); if (udc_device->address == faddr) { SET_EP0_STATE(IDLE); usbd_device_event_irq(udc_device, DEVICE_ADDRESS_ASSIGNED, 0); if ((debug_setup) && (debug_level > 1)) serial_printf("INFO : %s Address set to %d\n", __PRETTY_FUNCTION__, udc_device->address); } else { if (debug_level > 0) serial_printf("ERROR : %s Address missmatch " "sw %d vs hw %d\n", __PRETTY_FUNCTION__, udc_device->address, faddr); } }
static void S3C24X0_udc_ep0(void) { u_int8_t ep0csr; struct usb_endpoint_instance *ep0 = udc_device->bus->endpoint_array; S3C24X0_UDC_SETIX(0); ep0csr = inl(S3C24X0_UDC_IN_CSR1_REG); /* clear stall status */ if (ep0csr & S3C24X0_UDC_EP0_CSR_SENTSTL) { /* serial_printf("Clearing SENT_STALL\n"); */ clear_ep0_sst(); if (ep0csr & S3C24X0_UDC_EP0_CSR_SOPKTRDY) clear_ep0_opr(); ep0->state = EP0_IDLE; return; } /* clear setup end */ if (ep0csr & S3C24X0_UDC_EP0_CSR_SE /* && ep0->state != EP0_IDLE */) { /* serial_printf("Clearing SETUP_END\n"); */ clear_ep0_se(); #if 1 if (ep0csr & S3C24X0_UDC_EP0_CSR_SOPKTRDY) { /* Flush FIFO */ while (inl(S3C24X0_UDC_OUT_FIFO_CNT1_REG)) inl(S3C24X0_UDC_EP0_FIFO_REG); clear_ep0_opr(); } #endif ep0->state = EP0_IDLE; return; } /* Don't ever put [serial] debugging in non-error codepaths here, it * will violate the tight timing constraints of this USB Device * controller (and lead to bus enumeration failures) */ switch (ep0->state) { int i, fifo_count; unsigned char *datap; case EP0_IDLE: if (!(ep0csr & S3C24X0_UDC_EP0_CSR_OPKRDY)) break; datap = (unsigned char *) &ep0_urb->device_request; /* host->device packet has been received */ /* pull it out of the fifo */ fifo_count = fifo_count_out(); for (i = 0; i < fifo_count; i++) { *datap = (unsigned char)inl(S3C24X0_UDC_EP0_FIFO_REG); datap++; } if (fifo_count != 8) { debug("STRANGE FIFO COUNT: %u bytes\n", fifo_count); set_ep0_ss(); return; } if (ep0_urb->device_request.wLength == 0) { if (ep0_recv_setup(ep0_urb)) { /* Not a setup packet, stall next EP0 transaction */ debug("can't parse setup packet1\n"); set_ep0_ss(); set_ep0_de_out(); ep0->state = EP0_IDLE; return; } /* There are some requests with which we need to deal * manually here */ switch (ep0_urb->device_request.bRequest) { case USB_REQ_SET_CONFIGURATION: if (!ep0_urb->device_request.wValue) usbd_device_event_irq(udc_device, DEVICE_DE_CONFIGURED, 0); else usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0); break; case USB_REQ_SET_ADDRESS: udc_set_address(udc_device->address); usbd_device_event_irq(udc_device, DEVICE_ADDRESS_ASSIGNED, 0); break; default: break; } set_ep0_de_out(); ep0->state = EP0_IDLE; } else { if ((ep0_urb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) { clear_ep0_opr(); ep0->state = EP0_OUT_DATA_PHASE; ep0_urb->buffer = ep0_urb->buffer_data; ep0_urb->buffer_length = sizeof(ep0_urb->buffer_data); ep0_urb->actual_length = 0; } else { ep0->state = EP0_IN_DATA_PHASE; if (ep0_recv_setup(ep0_urb)) { /* Not a setup packet, stall next EP0 transaction */ debug("can't parse setup packet2\n"); set_ep0_ss(); //set_ep0_de_out(); ep0->state = EP0_IDLE; return; } clear_ep0_opr(); ep0->tx_urb = ep0_urb; ep0->sent = ep0->last = 0; if (S3C24X0_write_noniso_tx_fifo(ep0)) { ep0->state = EP0_IDLE; set_ep0_de_in(); } else set_ep0_ipr(); } } break; case EP0_IN_DATA_PHASE: if (!(ep0csr & S3C24X0_UDC_EP0_CSR_IPKRDY)) { ep0->sent += ep0->last; if (S3C24X0_write_noniso_tx_fifo(ep0)) { ep0->state = EP0_IDLE; set_ep0_de_in(); } else set_ep0_ipr(); } break; case EP0_OUT_DATA_PHASE: if (ep0csr & S3C24X0_UDC_EP0_CSR_OPKRDY) { u32 urb_avail = ep0_urb->buffer_length - ep0_urb->actual_length; u_int8_t *cp = ep0_urb->buffer + ep0_urb->actual_length; int i, fifo_count; fifo_count = fifo_count_out(); if (fifo_count < urb_avail) urb_avail = fifo_count; for (i = 0; i < urb_avail; i++) *cp++ = inl(S3C24X0_UDC_EP0_FIFO_REG); ep0_urb->actual_length += urb_avail; if (fifo_count < ep0->rcv_packetSize || ep0_urb->actual_length >= ep0_urb->device_request.wLength) { ep0->state = EP0_IDLE; if (ep0_recv_setup(ep0_urb)) { /* Not a setup packet, stall next EP0 transaction */ debug("can't parse setup packet3\n"); set_ep0_ss(); //set_ep0_de_out(); return; } set_ep0_de_out(); } else clear_ep0_opr(); } break; case EP0_END_XFER: ep0->state = EP0_IDLE; break; case EP0_STALL: //set_ep0_ss; ep0->state = EP0_IDLE; break; } }
static void mxc_udc_recv_setup(void) { setup_packet *s = &ep0_urb->device_request; mxc_udc_read_setup_pkt(s); if (s->wLength) { mxc_udc.ep0_dir = (s->bmRequestType & USB_DIR_IN) ? USB_DIR_OUT : USB_DIR_IN; mxc_udc_queue_update(0, NULL, 0, 0xffffffff); } if (ep0_recv_setup(ep0_urb)) { mxc_ep0_stall(); return; } switch (s->bRequest) { case USB_REQ_GET_STATUS: if ((s->bmRequestType & (USB_DIR_IN | USB_TYPE_MASK)) != (USB_DIR_IN | USB_TYPE_STANDARD)) break; ch9getstatus(s->bmRequestType, s->wValue, s->wIndex, s->wLength); return; case USB_REQ_SET_ADDRESS: if (s->bmRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE)) break; mxc_udc.setaddr = 1; mxc_udc.ep0_dir = USB_DIR_IN; mxc_udc_queue_update(0, NULL, 0, 0xffffffff); usbd_device_event_irq(udc_device, DEVICE_ADDRESS_ASSIGNED, 0); return; case USB_REQ_SET_CONFIGURATION: usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0); case USB_REQ_CLEAR_FEATURE: case USB_REQ_SET_FEATURE: { int rc = -1; if ((s->bmRequestType & (USB_RECIP_MASK | USB_TYPE_MASK)) == (USB_RECIP_ENDPOINT | USB_TYPE_STANDARD)) rc = 0; else if ((s->bmRequestType & (USB_RECIP_MASK | USB_TYPE_MASK)) == (USB_RECIP_DEVICE | USB_TYPE_STANDARD)) rc = 0; else break; if (rc == 0) { mxc_udc.ep0_dir = USB_DIR_IN; mxc_udc_queue_update(0, NULL, 0, 0xffffffff); } return; } default: break; } if (s->wLength) { mxc_udc.ep0_dir = (s->bmRequestType & USB_DIR_IN) ? USB_DIR_IN : USB_DIR_OUT; mxc_udc_queue_update(0, ep0_urb->buffer, ep0_urb->actual_length, 0xffffffff); ep0_urb->actual_length = 0; } else { mxc_udc.ep0_dir = USB_DIR_IN; mxc_udc_queue_update(0, NULL, 0, 0xffffffff); } }
static void mxc_udc_recv_setup(void) { struct usb_device_request *s = &ep0_urb->device_request; mxc_udc_read_setup_pkt(s); if (s->wLength) { /* If has a data phase, * then prime a dtd for status stage which has zero length DATA0. * The direction of status stage should oppsite to direction of data phase. */ mxc_udc.ep0_dir = (s->bmRequestType & USB_DIR_IN) ? USB_DIR_OUT : USB_DIR_IN; mxc_udc_queue_update(0, NULL, 0, 0xffffffff); } if (ep0_recv_setup(ep0_urb)) { mxc_ep0_stall(); return; } switch (s->bRequest) { case USB_REQ_GET_STATUS: if ((s->bmRequestType & (USB_DIR_IN | USB_TYPE_MASK)) != (USB_DIR_IN | USB_TYPE_STANDARD)) break; ch9getstatus(s->bmRequestType, s->wValue, s->wIndex, s->wLength); DBG("[SETUP] REQ_GET_STATUS\n"); return; case USB_REQ_SET_ADDRESS: if (s->bmRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE)) break; mxc_udc.setaddr = 1; mxc_udc.ep0_dir = USB_DIR_IN; mxc_udc_queue_update(0, NULL, 0, 0xffffffff); usbd_device_event_irq(udc_device, DEVICE_ADDRESS_ASSIGNED, 0); DBG("[SETUP] REQ_SET_ADDRESS\n"); return; case USB_REQ_SET_CONFIGURATION: usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0); DBG("[SETUP] REQ_SET_CONFIGURATION\n"); case USB_REQ_CLEAR_FEATURE: case USB_REQ_SET_FEATURE: { int rc = -1; if ((s->bmRequestType & (USB_RECIP_MASK | USB_TYPE_MASK)) == (USB_RECIP_ENDPOINT | USB_TYPE_STANDARD)) rc = 0; else if ((s->bmRequestType & (USB_RECIP_MASK | USB_TYPE_MASK)) == (USB_RECIP_DEVICE | USB_TYPE_STANDARD)) rc = 0; else break; if (rc == 0) { mxc_udc.ep0_dir = USB_DIR_IN; mxc_udc_queue_update(0, NULL, 0, 0xffffffff); } return; } default: break; } if (s->wLength) { mxc_udc.ep0_dir = (s->bmRequestType & USB_DIR_IN) ? USB_DIR_IN : USB_DIR_OUT; mxc_udc_queue_update(0, ep0_urb->buffer, ep0_urb->actual_length, 0xffffffff); ep0_urb->actual_length = 0; } else { mxc_udc.ep0_dir = USB_DIR_IN; mxc_udc_queue_update(0, NULL, 0, 0xffffffff); } }
/* Handle general USB interrupts and dispatch according to type. * This function implements TRM Figure 14-13. */ void s3c2410_udc_irq(void) { struct usb_endpoint_instance *ep0 = udc_device->bus->endpoint_array; u_int32_t save_idx = inl(S3C2410_UDC_INDEX_REG), idx2; /* read interrupt sources */ u_int32_t usb_status = inl(S3C2410_UDC_USB_INT_REG); u_int32_t usbd_status = inl(S3C2410_UDC_EP_INT_REG); u_int32_t pwr_reg = inl(S3C2410_UDC_PWR_REG); u_int32_t ep0csr = inl(S3C2410_UDC_IN_CSR1_REG); //debug("< IRQ usbs=0x%02x, usbds=0x%02x start >", usb_status, usbd_status); /* clear interrupts */ outl(usb_status, S3C2410_UDC_USB_INT_REG); if (usb_status & S3C2410_UDC_USBINT_RESET) { //serial_putc('R'); debug("RESET pwr=0x%x\n", inl(S3C2410_UDC_PWR_REG)); udc_setup_ep(udc_device, 0, ep0); outl(S3C2410_UDC_EP0_CSR_SSE|S3C2410_UDC_EP0_CSR_SOPKTRDY, S3C2410_UDC_EP0_CSR_REG); ep0->state = EP0_IDLE; usbd_device_event_irq (udc_device, DEVICE_RESET, 0); } if (usb_status & S3C2410_UDC_USBINT_RESUME) { debug("RESUME\n"); usbd_device_event_irq(udc_device, DEVICE_BUS_ACTIVITY, 0); } if (usb_status & S3C2410_UDC_USBINT_SUSPEND) { debug("SUSPEND\n"); usbd_device_event_irq(udc_device, DEVICE_BUS_INACTIVE, 0); } /* Endpoint Interrupts */ if (usbd_status) { int i; if (usbd_status & S3C2410_UDC_INT_EP0) { outl(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_REG); s3c2410_udc_ep0(); } for (i = 1; i < 5; i++) { u_int32_t tmp = 1 << i; if (usbd_status & tmp) { /* FIXME: Handle EP X */ outl(tmp, S3C2410_UDC_EP_INT_REG); s3c2410_udc_epn(i); } } usbd_status = inl(S3C2410_UDC_EP_INT_REG); /* what else causes this interrupt? a receive! who is it? */ if (!usb_status && !usbd_status && !pwr_reg && !ep0csr) { debug("dual packet issue\n"); for (i = 1; i < 5; i++) { idx2 = inl(S3C2410_UDC_INDEX_REG); outl(i, S3C2410_UDC_INDEX_REG); if (inl(S3C2410_UDC_OUT_CSR1_REG) & 0x1) s3c2410_udc_epn(i); /* restore index */ outl(idx2, S3C2410_UDC_INDEX_REG); } } } S3C2410_UDC_SETIX(save_idx); }
/** * bi_device_event - handle generic bus event * @device: device pointer * @event: interrupt event * * Called by usb core layer to inform bus of an event. */ int bi_device_event(struct usb_device_instance *device, usb_device_event_t event, int data) { sie_info * sie_data; cy_priv_t * cy_priv; otg_t * otg; sie_data = (sie_info *) device->bus->privdata; cy_priv = (cy_priv_t *) sie_data->cy_priv; otg = (otg_t *) cy_priv->otg; //printk(KERN_DEBUG "bi_device_event: event: %d\n", event); if (!device) { return 0; } switch (event) { case DEVICE_UNKNOWN: break; case DEVICE_INIT: break; case DEVICE_CREATE: // XXX should this stuff be in DEVICE_INIT? bi_config(device); // enable udc, enable interrupts, enable connect udc_enable(device); udc_all_interrupts(device); udc_connect(); break; case DEVICE_HUB_CONFIGURED: break; case DEVICE_RESET: device->address = 0; udc_set_address(device->address, device); udc_reset_ep(0, device); udc_all_interrupts(device); // XXX break; case DEVICE_ADDRESS_ASSIGNED: udc_set_address(device->address, device); device->status = USBD_OK; break; case DEVICE_CONFIGURED: bi_config(device); break; case DEVICE_DE_CONFIGURED: udc_reset_ep(1, device); udc_reset_ep(2, device); udc_reset_ep(3, device); break; case DEVICE_SET_INTERFACE: bi_config(device); break; case DEVICE_SET_FEATURE: break; case DEVICE_CLEAR_FEATURE: break; case DEVICE_BUS_INACTIVE: // disable suspend interrupt udc_suspended_interrupts(device); // XXX check on linkup and sl11 // if we are no longer connected then force a reset if (!udc_connected()) { usbd_device_event_irq(device, DEVICE_RESET, 0); } break; case DEVICE_BUS_ACTIVITY: // enable suspend interrupt udc_all_interrupts(device); break; case DEVICE_POWER_INTERRUPTION: break; case DEVICE_HUB_RESET: break; case DEVICE_DESTROY: udc_disconnect(); bi_disable_endpoints(device); udc_disable_interrupts(device); udc_disable(); break; case DEVICE_BUS_REQUEST: otg->b_bus_req = TRUE; update_otg_state(otg); break; case DEVICE_BUS_RELEASE: otg->b_bus_req = FALSE; update_otg_state(otg); break; case DEVICE_RCV_URB_RECYCLED: udc_rcv_urb_recycled(); break; case DEVICE_ACCEPT_HNP: otg->b_hnp_en = TRUE; update_otg_state(otg); break; case DEVICE_REQUEST_SRP: //otg->srp_start_flag = TRUE; otg->b_bus_req = TRUE; otg->b_se0_srp = TRUE; update_otg_state(otg); break; case DEVICE_FUNCTION_PRIVATE: break; } return 0; }
/** * bi_device_event - handle generic bus event * @device: device pointer * @event: interrupt event * * Called by usb core layer to inform bus of an event. */ int bi_device_event (struct usb_device_instance *device, usb_device_event_t event, int data) { //printk(KERN_DEBUG "bi_device_event: event: %d\n", event); if (!device) { return 0; } dbg_usbe (1,"%s", USBD_DEVICE_EVENTS(event)); switch (event) { case DEVICE_UNKNOWN: break; case DEVICE_INIT: break; case DEVICE_CREATE: // XXX should this stuff be in DEVICE_INIT? // enable upstream port //ep0_enable(device); // for net_create bi_config (device); // enable udc, enable interrupts, enable connect printk(KERN_INFO"bi_device_event: call udc_enable\n"); udc_enable (device); printk(KERN_INFO"bi_device_event: call udc_all_interrupts\n"); // XXX verify udc_suspended_interrupts (device); //udc_all_interrupts (device); dbg_usbe (1, "CREATE done"); break; case DEVICE_HUB_CONFIGURED: udc_connect (); break; case DEVICE_RESET: device->address = 0; udc_set_address (device->address); udc_reset_ep (0); // XXX verify udc_suspended_interrupts (device); dbg_usbe (1, "DEVICE RESET done: %d", device->address); break; case DEVICE_ADDRESS_ASSIGNED: udc_set_address (device->address); device->status = USBD_OK; // XXX verify udc_all_interrupts (device); // XXX break; case DEVICE_CONFIGURED: device->status = USBD_OK; bi_config (device); break; case DEVICE_DE_CONFIGURED: { int ep; for (ep = 1; ep < udc_max_endpoints (); ep++) udc_reset_ep (ep); } break; case DEVICE_SET_INTERFACE: bi_config (device); break; case DEVICE_SET_FEATURE: break; case DEVICE_CLEAR_FEATURE: break; case DEVICE_BUS_INACTIVE: // disable suspend interrupt udc_suspended_interrupts (device); // XXX check on linkup and sl11 // if we are no longer connected then force a reset if (!udc_connected ()) { usbd_device_event_irq (device, DEVICE_RESET, 0); } break; case DEVICE_BUS_ACTIVITY: // enable suspend interrupt udc_all_interrupts (device); break; case DEVICE_POWER_INTERRUPTION: break; case DEVICE_HUB_RESET: break; case DEVICE_DESTROY: udc_disconnect (); bi_disable_endpoints (device); udc_disable_interrupts (device); udc_disable (); break; case DEVICE_FUNCTION_PRIVATE: break; } return 0; }
void udc_irq(void) { /* This is a high freq called function */ if (enabled) { u8 intrusb; intrusb = readb(&musbr->intrusb); /* * See drivers/usb/gadget/mpc8xx_udc.c for * state diagram going from detached through * configuration. */ if (MUSB_INTR_RESUME & intrusb) { usbd_device_event_irq(udc_device, DEVICE_BUS_ACTIVITY, 0); musb_peri_resume(); } musb_peri_ep0(); if (MUSB_INTR_RESET & intrusb) { usbd_device_event_irq(udc_device, DEVICE_RESET, 0); musb_peri_reset(); } if (MUSB_INTR_DISCONNECT & intrusb) { /* cable unplugged from hub/host */ usbd_device_event_irq(udc_device, DEVICE_RESET, 0); musb_peri_reset(); usbd_device_event_irq(udc_device, DEVICE_HUB_RESET, 0); } if (MUSB_INTR_SOF & intrusb) { usbd_device_event_irq(udc_device, DEVICE_BUS_ACTIVITY, 0); musb_peri_resume(); } if (MUSB_INTR_SUSPEND & intrusb) { usbd_device_event_irq(udc_device, DEVICE_BUS_INACTIVE, 0); } if (ep0_state != SET_ADDRESS) { u16 intrrx, intrtx; intrrx = readw(&musbr->intrrx); intrtx = readw(&musbr->intrtx); if (intrrx) musb_peri_rx(intrrx); if (intrtx) musb_peri_tx(intrtx); } else { if (MUSB_INTR_SOF & intrusb) { u8 faddr; faddr = readb(&musbr->faddr); /* * Setting of the address can fail. * Normally it succeeds the second time. */ if (udc_device->address != faddr) musb_peri_ep0_set_address(); } } } }
static void s3c2410_udc_epn(int ep) { struct usb_endpoint_instance *endpoint; struct urb *urb; u32 ep_csr1; if (ep >= S3C2410_UDC_NUM_ENDPOINTS) return; endpoint = &udc_device->bus->endpoint_array[ep]; S3C2410_UDC_SETIX(ep); if (endpoint->endpoint_address & USB_DIR_IN) { /* IN transfer (device to host) */ ep_csr1 = inl(S3C2410_UDC_IN_CSR1_REG); debug("for ep=%u, IN_CSR1=0x%x ", ep, ep_csr1); urb = endpoint->tx_urb; if (ep_csr1 & S3C2410_UDC_ICSR1_SENTSTL) { /* Stall handshake */ debug("stall\n"); outl(0x00, S3C2410_UDC_IN_CSR1_REG); return; } if (!(ep_csr1 & S3C2410_UDC_ICSR1_PKTRDY) && urb && urb->actual_length) { debug("completing previously send data "); usbd_tx_complete(endpoint); /* push pending data into FIFO */ if ((endpoint->last == endpoint->tx_packetSize) && (urb->actual_length - endpoint->sent - endpoint->last == 0)) { endpoint->sent += endpoint->last; /* Write 0 bytes of data (ZLP) */ debug("ZLP "); outl(ep_csr1|S3C2410_UDC_ICSR1_PKTRDY, S3C2410_UDC_IN_CSR1_REG); } else { /* write actual data to fifo */ debug_urb_buffer("TX_DATA", endpoint); s3c2410_write_noniso_tx_fifo(endpoint); outl(ep_csr1|S3C2410_UDC_ICSR1_PKTRDY, S3C2410_UDC_IN_CSR1_REG); } } debug("\n"); } else { /* OUT transfer (host to device) */ ep_csr1 = inl(S3C2410_UDC_OUT_CSR1_REG); debug("for ep=%u, OUT_CSR1=0x%x ", ep, ep_csr1); urb = endpoint->rcv_urb; if (ep_csr1 & S3C2410_UDC_OCSR1_SENTSTL) { /* Stall handshake */ debugX("SENT STALL\n"); outl(0x00, S3C2410_UDC_IN_CSR1_REG); return; } if ((ep_csr1 & S3C2410_UDC_OCSR1_PKTRDY) && urb) { /* Read pending data from fifo */ u32 fifo_count = fifo_count_out(); int is_last = 0; u32 i, urb_avail = urb->buffer_length - urb->actual_length; u8 *cp = urb->buffer + urb->actual_length; if (fifo_count < endpoint->rcv_packetSize) is_last = 1; debug("fifo_count=%u is_last=%d, urb_avail=%u\n", fifo_count, is_last, urb_avail); if (fifo_count < urb_avail) urb_avail = fifo_count; for (i = 0; i < urb_avail; i++) *cp++ = inb(ep_fifo_reg[ep]); /* if (is_last) */ /* * Once the MCU reads the packet from FIFO, * this bit should be cleared */ #ifndef AUTO_CLEAR outl(ep_csr1 & ~S3C2410_UDC_OCSR1_PKTRDY, S3C2410_UDC_OUT_CSR1_REG); #endif usbd_rcv_complete(endpoint, urb_avail, 0); /* FIXME is there a better way to notify that, * we have got data */ usbd_device_event_irq(udc_device, DEVICE_FUNCTION_PRIVATE, 0); } } urb = endpoint->rcv_urb; }
void udc_irq(void) { int handled; struct usb_endpoint_instance *endpoint; int ep_num, i; u32 udcisr0; do { handled = 0; /* Suspend Interrupt Request */ if (readl(USIR1) & UDCCR_SUSIR) { usbdbg("Suspend\n"); udc_ack_int_UDCCR(UDCCR_SUSIR); handled = 1; ep0state = EP0_IDLE; } /* Resume Interrupt Request */ if (readl(USIR1) & UDCCR_RESIR) { udc_ack_int_UDCCR(UDCCR_RESIR); handled = 1; usbdbg("USB resume\n"); } if (readl(USIR1) & (1<<31)) { handled = 1; udc_state_changed(); } /* Reset Interrupt Request */ if (readl(USIR1) & UDCCR_RSTIR) { udc_ack_int_UDCCR(UDCCR_RSTIR); handled = 1; usbdbg("Reset\n"); usbd_device_event_irq(udc_device, DEVICE_RESET, 0); } else { if (readl(USIR0)) usbdbg("UISR0: %x \n", readl(USIR0)); if (readl(USIR0) & 0x2) writel(0x2, USIR0); /* Control traffic */ if (readl(USIR0) & USIR0_IR0) { handled = 1; writel(USIR0_IR0, USIR0); udc_handle_ep0(udc_device->bus->endpoint_array); } endpoint = udc_device->bus->endpoint_array; for (i = 0; i < udc_device->bus->max_endpoints; i++) { ep_num = (endpoint[i].endpoint_address) & USB_ENDPOINT_NUMBER_MASK; if (!ep_num) continue; udcisr0 = readl(UDCISR0); if (udcisr0 & UDCISR_INT(ep_num, UDC_INT_PACKETCMP)) { writel(UDCISR_INT(ep_num, UDC_INT_PACKETCMP), UDCISR0); udc_handle_ep(&endpoint[i]); } } } } while (handled); }