#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // For memcpy() #include #include #define AT91_UDP_CSR0 (AT91_UDP_CSR) #define AT91_UDP_FDR0 (AT91_UDP_FDR) #define pIER (AT91C_BASE_UDP + AT91_UDP_IER) #define pIDR (AT91C_BASE_UDP + AT91_UDP_IDR) #define pISR (AT91C_BASE_UDP + AT91_UDP_ISR) #define pIMR (AT91C_BASE_UDP + AT91_UDP_IMR) #define pICR (AT91C_BASE_UDP + AT91_UDP_ICR) #define pCSR0 (AT91C_BASE_UDP + AT91_UDP_CSR0) #define pFDR0 (AT91C_BASE_UDP + AT91_UDP_FDR0) #define AT91C_UDP_ALLOWED_IRQs (AT91C_UDP_WAKEUP | AT91C_UDP_ENDBUSRES | AT91C_UDP_EXTRSM | AT91C_UDP_RXRSM | AT91C_UDP_RXSUSP | AT91C_UDP_EPINT0 | AT91C_UDP_EPINT1 | AT91C_UDP_EPINT2 | AT91C_UDP_EPINT3) #define THERE_IS_A_NEW_PACKET_IN_THE_UDP 0xffff static const cyg_uint16 usbs_sam7_endpoint_fifo_size[AT91SAM7S_USB_ENDPOINTS] = { 8, 64, 64, 8 }; static const bool usbs_sam7_endpoint_pingpong[AT91SAM7S_USB_ENDPOINTS] = { false, true, true, false }; static cyg_uint8 *usbs_sam7_endpoint_pbegin[AT91SAM7S_USB_ENDPOINTS] = {0}; static cyg_uint8 *usbs_sam7_endpoint_pend[AT91SAM7S_USB_ENDPOINTS] = {0}; static bool usbs_sam7_endpoint_bank1[AT91SAM7S_USB_ENDPOINTS] = {false}; //static bool usbs_sam7_endpoint_send_zero_packet[AT91SAM7S_USB_ENDPOINTS] = {false}; static bool usbs_sam7_endpoint_transfer[AT91SAM7S_USB_ENDPOINTS] = {false}; static cyg_uint16 usbs_sam7_endpoint_bytes_in_fifo[AT91SAM7S_USB_ENDPOINTS] = {0}; static cyg_uint16 usbs_sam7_endpoint_bytes_recived[AT91SAM7S_USB_ENDPOINTS] = {THERE_IS_A_NEW_PACKET_IN_THE_UDP}; static cyg_interrupt usbs_sam7_intr_data; static cyg_handle_t usbs_sam7_intr_handle; static void usbs_sam7_ep0_start(usbs_control_endpoint*); static void usbs_sam7_poll(usbs_control_endpoint*); static void usbs_sam7_endpoint_start(cyg_uint8 epn); static void usbs_sam7_set_halted(cyg_bool new_value, cyg_uint8 epn); static void usbs_sam7_endpoint_init(cyg_uint8 epn, cyg_uint8 endpoint_type, cyg_bool enable); void usbs_start_dummy(usbs_rx_endpoint* ep){ CYG_ASSERT(0, "usbs_start_dummy()"); } void set_halted_dummy(usbs_rx_endpoint* ep, cyg_bool b){ CYG_ASSERT(0, "set_halted_dummy()"); } void usbs_sam7_ep1_start(usbs_rx_endpoint *pep){ usbs_sam7_endpoint_start(1); } void usbs_sam7_ep2_start(usbs_rx_endpoint *pep){ usbs_sam7_endpoint_start(2); } void usbs_sam7_ep3_start(usbs_rx_endpoint *pep){ usbs_sam7_endpoint_start(3); } void usbs_sam7_ep1_set_halted(usbs_rx_endpoint *pep, cyg_bool new_value){ usbs_sam7_set_halted(new_value, 1); } void usbs_sam7_ep2_set_halted(usbs_rx_endpoint *pep, cyg_bool new_value){ usbs_sam7_set_halted(new_value, 2); } void usbs_sam7_ep3_set_halted(usbs_rx_endpoint *pep, cyg_bool new_value){ usbs_sam7_set_halted(new_value, 3); } void usbs_sam7_ep1_init(usbs_rx_endpoint *pep, cyg_uint8 endpoint_type, cyg_bool enable){ usbs_sam7_endpoint_init(1, endpoint_type, enable); } void usbs_sam7_ep2_init(usbs_rx_endpoint *pep, cyg_uint8 endpoint_type, cyg_bool enable){ usbs_sam7_endpoint_init(2, endpoint_type, enable); } void usbs_sam7_ep3_init(usbs_rx_endpoint *pep, cyg_uint8 endpoint_type, cyg_bool enable){ usbs_sam7_endpoint_init(3, endpoint_type, enable); } usbs_control_endpoint usbs_sam7_ep0 = { state: USBS_STATE_POWERED, // The hardware does not distinguish between detached, attached and powered. enumeration_data: (usbs_enumeration_data*) 0, start_fn: usbs_sam7_ep0_start, poll_fn: usbs_sam7_poll, interrupt_vector: CYGNUM_HAL_INTERRUPT_UDP, control_buffer: { 0, 0, 0, 0, 0, 0, 0, 0 }, state_change_fn: (void (*)(usbs_control_endpoint*, void*, usbs_state_change, int)) 0, state_change_data: (void*) 0, standard_control_fn: (usbs_control_return (*)(usbs_control_endpoint*, void*)) 0, standard_control_data: (void*) 0, class_control_fn: (usbs_control_return (*)(usbs_control_endpoint*, void*)) 0, class_control_data: (void*) 0, vendor_control_fn: (usbs_control_return (*)(usbs_control_endpoint*, void*)) 0, vendor_control_data: (void*) 0, reserved_control_fn: (usbs_control_return (*)(usbs_control_endpoint*, void*)) 0, reserved_control_data: (void*) 0, buffer: (unsigned char*) 0, buffer_size: 0, fill_buffer_fn: (void (*)(usbs_control_endpoint*)) 0, fill_data: (void*) 0, fill_index: 0, complete_fn: (usbs_control_return (*)(usbs_control_endpoint*, int)) 0 }; usbs_rx_endpoint usbs_sam7_ep1 = { start_rx_fn: usbs_sam7_ep1_start, set_halted_fn: usbs_sam7_ep1_set_halted, complete_fn: (void (*)(void*, int)) 0, complete_data: (void*) 0, buffer: (const unsigned char*) 0, buffer_size: 0, halted: 0, }; usbs_rx_endpoint usbs_sam7_ep2 = { start_rx_fn: usbs_sam7_ep2_start, set_halted_fn: usbs_sam7_ep2_set_halted, complete_fn: (void (*)(void*, int)) 0, complete_data: (void*) 0, buffer: (const unsigned char*) 0, buffer_size: 0, halted: 0, }; usbs_rx_endpoint usbs_sam7_ep3 = { start_rx_fn: usbs_sam7_ep3_start, set_halted_fn: usbs_sam7_ep3_set_halted, complete_fn: (void (*)(void*, int)) 0, complete_data: (void*) 0, buffer: (const unsigned char*) 0, buffer_size: 0, halted: 0, }; const void *usbs_sam7_enpoints[AT91SAM7S_USB_ENDPOINTS] = { (void *) &usbs_sam7_ep0, (void *) &usbs_sam7_ep1, (void *) &usbs_sam7_ep2, (void *) &usbs_sam7_ep3 }; typedef enum ep0_low_level_status_t { EP0_LL_IDLE = 0, EP0_LL_REQUEST, EP0_LL_SEND_READY, EP0_LL_ACK, EP0_LL_RECIVE_READY, EP0_LL_ISOERROR, EP0_LL_STALL, EP0_LL_SET_ADDRESS, } ep0_low_level_status_t; #ifndef _BV #define _BV(_bit_) (1 << _bit_) #endif #ifndef MIN #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #endif // DEBUG CHÄS #define MAXPRINTBUFSIZE 3000 cyg_uint32 printbuf_size = MAXPRINTBUFSIZE; char printbuf[MAXPRINTBUFSIZE]; cyg_uint32 printbuf_next = 0; #define debug_line_and_funcion debug_printf("%d: %s(); ", __LINE__, __FUNCTION__); void buf_printf(char *fmt, ...){ va_list argp; va_start(argp, fmt); printbuf_next = printbuf_next + vsnprintf((char *)((cyg_uint32) printbuf + printbuf_next), printbuf_size - printbuf_next, fmt, argp); // diag_vprintf(fmt, argp); va_end(argp); } #define debug_printf buf_printf void debug_dump(cyg_uint8 *pbegin, cyg_uint8 *pend){ //debug_line_and_funcion debug_printf("[%d] ", (cyg_uint32) pend - (cyg_uint32) pbegin); do { debug_printf("%02x ", *pbegin); pbegin++; } while (pbegin < pend); debug_printf("\n"); } //#define diag_ // #if 1 #define dbg debug_line_and_funcion #else #define dbg // #endif #if 1 #define dbgdsr debug_line_and_funcion #else #define dbgdsr #endif #define dbgf void diag_status(usbs_control_endpoint cep, ep0_low_level_status_t s){ cyg_uint32 isr; cyg_uint32 csr0; HAL_READ_UINT32(pISR, isr); HAL_READ_UINT32(pCSR0, csr0); debug_printf("i%08x; c%08x; state: ", isr, csr0); switch(cep.state){ case USBS_STATE_DETACHED: debug_printf("USBS_STATE_DETACHED"); break; case USBS_STATE_ATTACHED: debug_printf("USBS_STATE_ATTACHED"); break; case USBS_STATE_POWERED: debug_printf("USBS_STATE_POWERED"); break; case USBS_STATE_DEFAULT: debug_printf("USBS_STATE_DEFAULT"); break; case USBS_STATE_ADDRESSED: debug_printf("USBS_STATE_ADDRESSED"); break; case USBS_STATE_CONFIGURED:debug_printf("USBS_STATE_CONFIGURED"); break; case USBS_STATE_MASK: debug_printf("USBS_STATE_MASK"); break; case USBS_STATE_SUSPENDED: debug_printf("USBS_STATE_SUSPENDED"); break; default: debug_printf("USBS_STATE_ERROR"); break; } debug_printf("; ll: "); switch(s){ case EP0_LL_IDLE: debug_printf("EP0_LL_IDLE"); break; case EP0_LL_REQUEST: debug_printf("EP0_LL_REQUEST"); break; case EP0_LL_SEND_READY: debug_printf("EP0_LL_SEND_READY"); break; case EP0_LL_ACK: debug_printf("EP0_LL_ACK"); break; case EP0_LL_RECIVE_READY: debug_printf("EP0_LL_RECIVE_READY"); break; case EP0_LL_ISOERROR: debug_printf("EP0_LL_ISOERROR"); break; case EP0_LL_STALL: debug_printf("EP0_LL_STALL"); break; case EP0_LL_SET_ADDRESS: debug_printf("EP0_LL_SET_ADDRESS"); break; default: debug_printf("EP0_LL_ERROR"); break; } debug_printf(";\n"); } void usbs_sam7_endpoint_interrupt_enable(cyg_uint8 epn, bool enable){ CYG_ASSERT(epn < 4, ""); if (enable){ HAL_WRITE_UINT32(pIER, 1 << epn); }else{ HAL_WRITE_UINT32(pIDR, 1 << epn); } } inline cyg_uint32 hal_get_2_bytes(cyg_addrword_t addr){ cyg_uint32 temp1, temp2; HAL_READ_UINT8(addr, temp1); HAL_READ_UINT8(addr, temp2); return temp1 | (temp2 << 8); } inline cyg_uint8 hal_get_byte(cyg_addrword_t addr){ cyg_uint8 temp1; HAL_READ_UINT32(addr, temp1); return temp1; } inline cyg_uint32 hal_get_uint32(cyg_addrword_t addr){ cyg_uint32 temp1; HAL_READ_UINT32(addr, temp1); return temp1; } cyg_uint8 *hal_read_fifo_uint8(cyg_uint8 *pdest, cyg_uint8 *psource, cyg_uint32 size){ cyg_uint8 *preqbyte = pdest; cyg_uint8 reqbyte; while (preqbyte < (cyg_uint8 *)((cyg_uint32) size + pdest)){ HAL_READ_UINT8(psource, reqbyte); *preqbyte = reqbyte; preqbyte++; } return preqbyte; } cyg_uint8 *hal_write_fifo_uint8(cyg_uint8 *pdest, cyg_uint8 *psource, cyg_uint8 *psource_end){ cyg_uint8 *preqbyte; for (preqbyte = psource; preqbyte < psource_end; preqbyte++){ HAL_WRITE_UINT8(pdest, (*preqbyte)); } return preqbyte; } void set_bits(cyg_addrword_t addr, cyg_uint32 set){ cyg_uint32 read; HAL_READ_UINT32(addr, read); HAL_WRITE_UINT32(addr, read | set); } void clear_bits(cyg_addrword_t addr, cyg_uint32 clear){ cyg_uint32 read; HAL_READ_UINT32(addr, read); HAL_WRITE_UINT32(addr, read & ~clear); } cyg_uint32 bits_are_set(cyg_addrword_t addr, cyg_uint32 set){ cyg_uint32 read; HAL_READ_UINT32(addr, read); return (read & set) == set; } cyg_uint32 bits_are_cleared(cyg_addrword_t addr, cyg_uint32 clear){ cyg_uint32 read; HAL_READ_UINT32(addr, read); return (read | ~clear) == ~clear; } void usbs_change_state(usbs_control_endpoint *pcep, usbs_state_change new_state){ int old_state = pcep->state; pcep->state = new_state; if (pcep->state_change_fn){ (*pcep->state_change_fn)(pcep, 0, new_state, old_state); } } void usbs_end_all_transfers(usbs_control_return returncode){ cyg_uint32 epn; usbs_rx_endpoint *pep; for (epn = 1; epn < AT91SAM7S_USB_ENDPOINTS; epn++){ if (usbs_sam7_endpoint_transfer[epn]){ /* Ready to transmit ? */ pep = (usbs_rx_endpoint *) usbs_sam7_enpoints[epn]; if (pep->complete_fn){ (*pep->complete_fn)(pep->complete_data, returncode); } usbs_sam7_endpoint_interrupt_enable(epn, false); usbs_sam7_endpoint_transfer[epn] = false; } } } void usbs_state_notify(usbs_control_endpoint *pcep){ static int old_state = USBS_STATE_CHANGE_POWERED; int state = pcep->state & USBS_STATE_MASK; if (pcep->state != old_state){ diag_printf(" ", pcep->state); usbs_end_all_transfers(-EPIPE); if (pcep->state & USBS_STATE_MASK == USBS_STATE_DETACHED){ } else if (state == USBS_STATE_DETACHED){ } else if (state == USBS_STATE_ATTACHED){ } else if (state == USBS_STATE_POWERED){ } else if (state == USBS_STATE_DEFAULT){ HAL_WRITE_UINT32(AT91C_BASE_UDP + AT91_UDP_GLBSTATE, 0); } else if (state == USBS_STATE_ADDRESSED){ HAL_WRITE_UINT32(AT91C_BASE_UDP + AT91_UDP_GLBSTATE, AT91C_UDP_FADDEN); } else if (state == USBS_STATE_CONFIGURED){ HAL_WRITE_UINT32(AT91C_BASE_UDP + AT91_UDP_GLBSTATE, AT91C_UDP_CONFG); } else { /* ERROR */ } if (pcep->state & USBS_STATE_SUSPENDED){ } else { } if (pcep->state_change_fn){ (*pcep->state_change_fn)(pcep, 0, pcep->state, old_state); } old_state = pcep->state; } } usbs_control_return usbs_parse_host_get_command(usbs_control_endpoint *pcep){ usbs_control_return retcode; cyg_uint8 dev_req_type = (((usb_devreq *) pcep->control_buffer)->type) & USB_DEVREQ_TYPE_MASK; pcep->buffer_size = 0; pcep->fill_buffer_fn = 0; if (dev_req_type == USB_DEVREQ_TYPE_STANDARD){ if (!pcep->standard_control_fn){ return usbs_handle_standard_control(pcep); } retcode = (*pcep->standard_control_fn)(pcep, pcep->standard_control_data); if (retcode == USBS_CONTROL_RETURN_UNKNOWN){ return usbs_handle_standard_control(pcep); } return retcode; } else if (dev_req_type == USB_DEVREQ_TYPE_CLASS){ if (!pcep->class_control_fn){ return USBS_CONTROL_RETURN_STALL; } return (*pcep->class_control_fn)(pcep, pcep->class_control_data); } else if (dev_req_type == USB_DEVREQ_TYPE_VENDOR){ if (!pcep->class_control_fn){ return USBS_CONTROL_RETURN_STALL; } return (*pcep->class_control_fn)(pcep, pcep->vendor_control_data); } else if (dev_req_type == USB_DEVREQ_TYPE_RESERVED){ if (!pcep->reserved_control_fn){ return USBS_CONTROL_RETURN_STALL; } return (*pcep->reserved_control_fn)(pcep, pcep->reserved_control_data); } return USBS_CONTROL_RETURN_STALL; } static void usbs_sam7_set_halted(cyg_bool new_value, cyg_uint8 epn){ usbs_rx_endpoint *pep = (usbs_rx_endpoint *) usbs_sam7_enpoints[epn]; cyg_uint32 *pbegin = usbs_sam7_endpoint_pbegin[epn]; cyg_uint32 *pend = usbs_sam7_endpoint_pend[epn]; if (pep->halted != new_value){ /* If somting is to do */ // cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_UDP); pep->halted = new_value; pbegin = pep->buffer; pend = pbegin; if (new_value && usbs_sam7_endpoint_transfer[epn]){ if (pep->complete_fn && usbs_sam7_endpoint_transfer[epn]){ (*pep->complete_fn)(pep->complete_data, -EAGAIN); } usbs_sam7_endpoint_transfer[epn] = false; } // cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_UDP); } } static void usbs_sam7_endpoint_init(cyg_uint8 epn, cyg_uint8 endpoint_type, cyg_bool enable){ usbs_rx_endpoint *pep = (usbs_rx_endpoint *) usbs_sam7_enpoints[epn]; cyg_uint32 *pCSR = (cyg_uint32 *)((cyg_uint32) pCSR0 + 4 * epn); // cyg_uint32 *pFDR = (cyg_uint32 *)((cyg_uint32) pFDR0 + 4 * epn); // cyg_uint32 endpoint_size = usbs_sam7_endpoint_fifo_size[epn]; // cyg_uint32 *pbegin = usbs_sam7_endpoint_pbegin[epn]; // cyg_uint32 *pend = usbs_sam7_endpoint_pend[epn]; CYG_ASSERT(AT91SAM7S_USB_ENDPOINTS > epn && epn, "Wrong epn"); usbs_sam7_endpoint_interrupt_enable(epn, false); HAL_WRITE_UINT32(pCSR, ((((cyg_uint32) endpoint_type) & 0x03) << 8) | ((((cyg_uint32) endpoint_type) & 0x80) << 3)); /* Type | In */ // CYG_ASSERT(bits_are_set(pCSR, 1 << 9), "Wrong enpoint type"); HAL_WRITE_UINT32(AT91C_BASE_UDP + AT91_UDP_RSTEP, 1 << epn); /* Reset endpoint */ HAL_WRITE_UINT32(AT91C_BASE_UDP + AT91_UDP_RSTEP, 0); pep->halted = false; usbs_sam7_endpoint_transfer[epn] = false; usbs_sam7_endpoint_bytes_in_fifo[epn] = 0; usbs_sam7_endpoint_bytes_recived[epn] = THERE_IS_A_NEW_PACKET_IN_THE_UDP; usbs_sam7_endpoint_bank1[epn] = false; usbs_sam7_endpoint_transfer[epn] = false; if (enable){ set_bits(pCSR, AT91C_UDP_EPEDS); } } static void usbs_sam7_handle_reset(void){ dbg debug_printf("\n"); usbs_end_all_transfers(-EPIPE); HAL_WRITE_UINT32(AT91C_BASE_UDP + AT91_UDP_IDR, 0xffffffff); HAL_WRITE_UINT32(AT91C_BASE_UDP + AT91_UDP_ICR, 0xffffffff); HAL_WRITE_UINT32(AT91C_BASE_UDP + AT91_UDP_RSTEP, 0xffffffff); HAL_WRITE_UINT32(AT91C_BASE_UDP + AT91_UDP_RSTEP, 0x00000000); HAL_WRITE_UINT32(AT91C_BASE_UDP + AT91_UDP_FADDR, AT91C_UDP_FEN); HAL_WRITE_UINT32(AT91C_BASE_UDP + AT91_UDP_CSR0, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL); HAL_WRITE_UINT32(AT91C_BASE_UDP + AT91_UDP_IER, AT91C_UDP_ALLOWED_IRQs); #if 1 usbs_sam7_endpoint_init(1, USB_ENDPOINT_DESCRIPTOR_ATTR_BULK, true); usbs_sam7_endpoint_init(2, USB_ENDPOINT_DESCRIPTOR_ATTR_BULK | USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN, true); usbs_sam7_endpoint_init(3, USB_ENDPOINT_DESCRIPTOR_ATTR_INTERRUPT | USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN, true); #else usbs_sam7_endpoint_init(1, 0, false); usbs_sam7_endpoint_init(2, 0, false); usbs_sam7_endpoint_init(3, 0, false); #endif } static void usbs_sam7_ep0_start(usbs_control_endpoint* endpoint){ dbg debug_printf("\n"); usbs_sam7_handle_reset(); // If there is additional platform-specific initialization to // perform, do it now. This macro can come from the platform HAL, // but may not be available on all platforms. #ifdef AT91SAM7S_USB_PLATFORM_INIT AT91SAM7S_USB_PLATFORM_INIT(); #else HAL_WRITE_UINT32(AT91C_BASE_PIOA + AT91_PIO_CODR, AT91C_PIO_PA4); #endif } static void usbs_sam7_endpoint_start(cyg_uint8 epn){ usbs_rx_endpoint *pep = (usbs_rx_endpoint *) usbs_sam7_enpoints[epn]; cyg_uint32 *pCSR = (cyg_uint32 *)((cyg_uint32) pCSR0 + 4 * epn); cyg_uint32 *pFDR = (cyg_uint32 *)((cyg_uint32) pFDR0 + 4 * epn); cyg_uint16 space = 0; cyg_uint16 endpoint_size = usbs_sam7_endpoint_fifo_size[epn]; cyg_uint16 *pinfifo = &usbs_sam7_endpoint_bytes_in_fifo[epn]; cyg_uint8 **ppbegin = &usbs_sam7_endpoint_pbegin[epn]; cyg_uint8 **ppend = &usbs_sam7_endpoint_pend[epn]; CYG_ASSERT(AT91SAM7S_USB_ENDPOINTS > epn && epn, "Wrong epn"); CYG_ASSERT(bits_are_set(pCSR, 1 << 9), "Wrong enpoint type"); // CYG_ASSERT(pep->complete_fn, "No complete_fn()"); if (usbs_sam7_ep0.state != USBS_STATE_CONFIGURED){ /* Halted means nothing to do */ diag_printf("*1"); if (pep->complete_fn){ (*pep->complete_fn)(pep->complete_data, -EPIPE); } return; } if (pep->halted){ /* Halted means nothing to do */ diag_printf("*2"); if (pep->complete_fn){ (*pep->complete_fn)(pep->complete_data, -EAGAIN); } return; } if (usbs_sam7_endpoint_transfer[epn]){ /* Transfer in progress */ diag_printf("*3"); if (pep->complete_fn){ (*pep->complete_fn)(pep->complete_data, -EIO); } return; } *ppbegin = pep->buffer; /* Set the working pointers */ *ppend = (cyg_uint32 *)((cyg_uint32) pep->buffer + pep->buffer_size); if (bits_are_set(pCSR, 0x400)){ /* IN: tx_endpoint */ space = (cyg_uint32) *ppend - (cyg_uint32) *ppbegin; if (space == endpoint_size){ *ppend = *ppbegin; /* Send zero-packet */ } *ppbegin = hal_write_fifo_uint8(pFDR, *ppbegin, (cyg_uint32 *)((cyg_uint32) *ppbegin + MIN(space, endpoint_size))); set_bits(pCSR, AT91C_UDP_TXPKTRDY); if (*ppend == *ppbegin){ /* Last packet ? */ *ppend = *ppbegin - 1; /* The packet isn't sent yet */ } } usbs_sam7_endpoint_transfer[epn] = true; usbs_sam7_endpoint_interrupt_enable(epn, true); } static bool usbs_sam7_endpoint_isr(cyg_uint8 epn){ /* Move the datas in ISR for high bandwidth */ cyg_uint32 *pCSR = (cyg_uint32 *)((cyg_uint32) pCSR0 + 4 * epn); cyg_uint32 *pFDR = (cyg_uint32 *)((cyg_uint32) pFDR0 + 4 * epn); cyg_uint16 endpoint_size = usbs_sam7_endpoint_fifo_size[epn]; cyg_uint32 space = 0; cyg_uint8 **ppbegin = &usbs_sam7_endpoint_pbegin[epn]; cyg_uint8 **ppend = &usbs_sam7_endpoint_pend[epn]; cyg_uint16 *pinfifo = &usbs_sam7_endpoint_bytes_in_fifo[epn]; cyg_uint16 *precived = &usbs_sam7_endpoint_bytes_recived[epn]; CYG_ASSERT(AT91SAM7S_USB_ENDPOINTS > epn && epn, "Wrong epn"); //diag_printf(" i%d ", epn); if (bits_are_set(pCSR, 0x400)){ /* IN: tx_endpoint */ clear_bits(pCSR, AT91C_UDP_TXCOMP); if (bits_are_cleared(pCSR, AT91C_UDP_TXPKTRDY)){ /* Ready to transmit ? */ if (*ppend > *ppbegin){ /* Somthing to send ? */ space = (cyg_uint32) *ppend - (cyg_uint32) *ppbegin; if (space == endpoint_size){ *ppend = *ppbegin; /* Send zero-packet */ } *ppbegin = hal_write_fifo_uint8(pFDR, *ppbegin, (cyg_uint32 *)((cyg_uint32) *ppbegin + MIN(space, endpoint_size))); set_bits(pCSR, AT91C_UDP_TXPKTRDY); if (*ppend == *ppbegin){ /* Last packet ? */ *ppend = *ppbegin - 1; /* The packet isn't sent yet */ } } else { if (*ppend + 1 == *ppbegin){ *ppend = *ppbegin; /* Flag for DSR */ return true; } else { *ppend = *ppbegin - 1; /* Flag for zero-packet */ set_bits(pCSR, AT91C_UDP_TXPKTRDY); /* Send no data */ } } } clear_bits(pCSR, AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1 | AT91C_UDP_RXSETUP | AT91C_UDP_ISOERROR); } else { /* OUT: rx_endpoint */ if (!bits_are_cleared(pCSR, AT91C_UDP_RX_DATA_BK0) || AT91C_UDP_RX_DATA_BK1){ /* Sometime something recived ? */ if (*precived == THERE_IS_A_NEW_PACKET_IN_THE_UDP){ /* If there is a new... */ *precived = ((*pCSR) >> 16) & 0x7ff; /* How many bytes ? */ *pinfifo = *precived; /* FIFO hold datas */ } while ((*ppbegin < *ppend) && *pinfifo){ /* If we have buffer-space AND datas in the FIFO */ **ppbegin = *pFDR; (*ppbegin)++; (*pinfifo)--; } if (*ppbegin == *ppend){ /* The buffer is full... call the DSR */ return true; /* We can call the complet-function in the DSR */ } if (*pinfifo == 0){ /* If the FIFO is empty, then we can release it */ if (usbs_sam7_endpoint_pingpong[epn]){ /* Time to clear the interrupt flag */ if (usbs_sam7_endpoint_bank1[epn]){ clear_bits(pCSR, AT91C_UDP_RX_DATA_BK1); } else { clear_bits(pCSR, AT91C_UDP_RX_DATA_BK0); } usbs_sam7_endpoint_bank1[epn] = !usbs_sam7_endpoint_bank1[epn]; } else { clear_bits(pCSR, AT91C_UDP_RX_DATA_BK0); } if (*precived < endpoint_size){ /* If the last packet was smaller then the endpoint-size... */ *ppend = *ppbegin; *precived = THERE_IS_A_NEW_PACKET_IN_THE_UDP; /* Set flag */ return true; /* We can call the complet-function in the DSR */ } *precived = THERE_IS_A_NEW_PACKET_IN_THE_UDP; /* Set flag */ } } clear_bits(pCSR, AT91C_UDP_TXCOMP | AT91C_UDP_RXSETUP | AT91C_UDP_ISOERROR); } return false; } static void usbs_sam7_endpoint_dsr(cyg_uint8 epn){ usbs_rx_endpoint *pep = (usbs_rx_endpoint *) usbs_sam7_enpoints[epn]; cyg_uint32 *pCSR = (cyg_uint32 *)((cyg_uint32) pCSR0 + 4 * epn); cyg_uint8 **ppbegin = &usbs_sam7_endpoint_pbegin[epn]; cyg_uint8 **ppend = &usbs_sam7_endpoint_pend[epn]; CYG_ASSERT(AT91SAM7S_USB_ENDPOINTS > epn && epn, "Wrong epn"); CYG_ASSERT(bits_are_set(pCSR, 1 << 9), "Wrong enpoint type"); CYG_ASSERT(pep->complete_fn, "No complete_fn()"); //diag_printf(" d%d ", epn); if (usbs_sam7_endpoint_transfer[epn]){ /* Transmiting ? */ if (*ppend == *ppbegin){ /* Transmitted ? */ pep->buffer_size = (cyg_uint32) *ppbegin - (cyg_uint32) pep->buffer; if (pep->complete_fn){ if (!pep->halted){ (*pep->complete_fn)(pep->complete_data, pep->buffer_size); } else { (*pep->complete_fn)(pep->complete_data, -EAGAIN); } } usbs_sam7_endpoint_interrupt_enable(epn, false); usbs_sam7_endpoint_transfer[epn] = false; } } } static void usbs_sam7_control_dsr(){ usb_devreq *req = usbs_sam7_ep0.control_buffer; /* */ static ep0_low_level_status_t status = EP0_LL_IDLE; bool dev_to_host; /* IN */ usbs_control_return usbcode; static cyg_uint16 length; static cyg_uint8 *pbuffer = 0; static cyg_uint8 *pbuffer_end = 0; static cyg_uint32 bytes_to_write = 0; static cyg_uint32 address; static cyg_uint8 configaddress ; //dbgdsr debug_printf("BEGIN: "); diag_status(usbs_sam7_ep0, status); //diag_printf("o"); while (!bits_are_cleared(pCSR0, AT91C_UDP_TXCOMP | AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RXSETUP | AT91C_UDP_ISOERROR | AT91C_UDP_RX_DATA_BK1)){ /* ERROR-HANDLING */ /******************/ if (bits_are_set(pCSR0, AT91C_UDP_ISOERROR)){ /* ERROR? */ // clear_bits(pCSR0, AT91C_UDP_FORCESTALL); /* We recived the host-request */ clear_bits(pCSR0, AT91C_UDP_ISOERROR | AT91C_UDP_FORCESTALL); /* We recived the host-request */ pbuffer = usbs_sam7_ep0.buffer; pbuffer_end = pbuffer; if (status == EP0_LL_IDLE){ if (usbs_sam7_ep0.complete_fn){ (*usbs_sam7_ep0.complete_fn)(&usbs_sam7_ep0, USBS_CONTROL_RETURN_STALL); } } status = EP0_LL_IDLE; //dbgdsr debug_printf("AT91C_UDP_ISOERROR "); diag_status(usbs_sam7_ep0, status); } /* HOSTREQUEST-PARSING */ /***********************/ if (bits_are_set(pCSR0, AT91C_UDP_RXSETUP)){ /* wenn wir auf ein request warten */ /* host request */ hal_read_fifo_uint8(req, pFDR0, sizeof(usb_devreq)); length = (req->length_hi << 8) | req->length_lo; //value = req->value_hi; //value = (req->value_hi << 8) | req->value_lo; usbs_sam7_ep0.buffer_size = 0; status = EP0_LL_REQUEST; dev_to_host = req->type & USB_DEVREQ_DIRECTION_IN; if (dev_to_host){ /* if next transfer is IN: "host <- dev" ? */ set_bits(pCSR0, AT91C_UDP_DIR); /* Set IN direction */ } else { clear_bits(pCSR0, AT91C_UDP_DIR); /* Set OUT direction */ } if (req->request == USB_DEVREQ_GET_STATUS && dev_to_host){ //diag_printf("s"); pbuffer = &usbs_sam7_ep0.state; pbuffer_end = pbuffer + sizeof(usbs_sam7_ep0.state); status = EP0_LL_SEND_READY; } else if (req->request == USB_DEVREQ_SET_ADDRESS && !dev_to_host){ /* Special-processing */ //diag_printf("a"); pbuffer = usbs_sam7_ep0.buffer;/* Send ACK */ pbuffer_end = pbuffer; status = EP0_LL_SEND_READY; } else { usbcode = usbs_parse_host_get_command(&usbs_sam7_ep0); usbs_sam7_ep0.buffer_size = MIN(usbs_sam7_ep0.buffer_size, length); length = length - usbs_sam7_ep0.buffer_size; pbuffer = usbs_sam7_ep0.buffer; pbuffer_end = pbuffer + usbs_sam7_ep0.buffer_size; /* Ready to send... */ if (usbcode == USBS_CONTROL_RETURN_HANDLED){ /* OK */ if (dev_to_host){ /* if next transfer is IN: "host <- dev" ? */ status = EP0_LL_SEND_READY; } else { status = EP0_LL_RECIVE_READY; } } else { //diag_printf(" "); clear_bits(pCSR0, 0x7f); set_bits(pCSR0, AT91C_UDP_FORCESTALL); status = EP0_LL_STALL; } } clear_bits(pCSR0, AT91C_UDP_RXSETUP); /* We recived the host-request */ // while(!bits_are_cleared(pCSR0, AT91C_UDP_RXSETUP)){ /* Test like Atmel USB AN */ // } } /* INTERRUPT-HANDLING clear flags and do the work and update the state-machine */ /*******************************************************************************/ if (bits_are_set(pCSR0, AT91C_UDP_TXCOMP)){ //received an ACK packet clear_bits(pCSR0, AT91C_UDP_TXCOMP); // Clear corresponding interrupt // while(!bits_are_cleared(pCSR0, AT91C_UDP_TXCOMP)){ // Test like Atmel USB AN // } } if (bits_are_cleared(pCSR0, AT91C_UDP_TXPKTRDY)){ if (status == EP0_LL_SEND_READY){ if (pbuffer == pbuffer_end){ // All bytes are sent, send ACK status = EP0_LL_ACK; set_bits(pCSR0, AT91C_UDP_TXPKTRDY); // Signal FIFO loaded } else { bytes_to_write = MIN(pbuffer_end - pbuffer, usbs_sam7_endpoint_fifo_size[0]); pbuffer = hal_write_fifo_uint8(pFDR0, pbuffer, (cyg_uint8 *)((cyg_uint32) pbuffer + bytes_to_write)); // Send next few bytes if (pbuffer == pbuffer_end){ /* Control-Endoints don't need ACK's */ if (usbs_sam7_ep0.fill_buffer_fn){ /* More Records ? */ //diag_printf(" f "); (*usbs_sam7_ep0.fill_buffer_fn)(&usbs_sam7_ep0); pbuffer = usbs_sam7_ep0.buffer; pbuffer_end = pbuffer + usbs_sam7_ep0.buffer_size; /* Ready to send... */ bytes_to_write = MIN(pbuffer_end - pbuffer, usbs_sam7_endpoint_fifo_size[0] - bytes_to_write); pbuffer = hal_write_fifo_uint8(pFDR0, pbuffer, (cyg_uint8 *)((cyg_uint32) pbuffer + bytes_to_write)); // Send next few bytes } else { status = EP0_LL_IDLE; } } set_bits(pCSR0, AT91C_UDP_TXPKTRDY); // Signal FIFO loaded } } else if (status == EP0_LL_RECIVE_READY){ /* Maybe we have to send an ACK */ if (pbuffer == pbuffer_end){ // All bytes are recived, send ACK status = EP0_LL_ACK; set_bits(pCSR0, AT91C_UDP_TXPKTRDY); // Signal FIFO loaded } } else if (status == EP0_LL_ACK){ dbgdsr debug_printf("confirmed ACK "); diag_status(usbs_sam7_ep0, status); if (req->request == USB_DEVREQ_SET_ADDRESS){ /* Special-processing */ //diag_printf("b"); HAL_WRITE_UINT32(AT91C_BASE_UDP + AT91_UDP_FADDR, req->value_lo | AT91C_UDP_FEN); // HAL_WRITE_UINT32(AT91C_BASE_UDP + AT91_UDP_GLBSTATE, 0x00000001); usbs_sam7_ep0.state = USBS_STATE_ADDRESSED; } if (usbs_sam7_ep0.complete_fn){ (*usbs_sam7_ep0.complete_fn)(&usbs_sam7_ep0, USBS_CONTROL_RETURN_HANDLED); } status = EP0_LL_IDLE; usbs_state_notify(&usbs_sam7_ep0); } } if (bits_are_set(pCSR0, AT91C_UDP_RX_DATA_BK0)){ /* TODO READ FIFO OR SEND ACK */ pbuffer = usbs_sam7_ep0.buffer; pbuffer_end = pbuffer; /* Ready to send... */ status = EP0_LL_SEND_READY; clear_bits(pCSR0, AT91C_UDP_RX_DATA_BK0); } } } static void usbs_sam7_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data){ cyg_uint8 n; CYG_ASSERT(CYGNUM_HAL_INTERRUPT_UDP == vector, "Wrong interrupts"); CYG_ASSERT(0 == data, "DSR needs no data"); //diag_printf("."); clear_bits(AT91C_BASE_UDP + AT91_UDP_GLBSTATE, 0x10); if (bits_are_set(pISR, AT91C_UDP_WAKEUP)){ usbs_sam7_ep0.state = USBS_STATE_DEFAULT; usbs_state_notify(&usbs_sam7_ep0); HAL_WRITE_UINT32(pICR, AT91C_UDP_WAKEUP); } if (bits_are_set(pISR, AT91C_UDP_ENDBUSRES)){ // RESET UDP //diag_printf("R"); usbs_sam7_ep0.state = USBS_STATE_POWERED; usbs_state_notify(&usbs_sam7_ep0); usbs_sam7_handle_reset(); HAL_WRITE_UINT32(pCSR0, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL); HAL_WRITE_UINT32(pIER, AT91C_UDP_EPINT0); usbs_sam7_ep0.state = USBS_STATE_DEFAULT; usbs_state_notify(&usbs_sam7_ep0); HAL_WRITE_UINT32(pICR, AT91C_UDP_ENDBUSRES); } if (bits_are_set(pISR, AT91C_UDP_SOFINT)){ HAL_WRITE_UINT32(pICR, AT91C_UDP_SOFINT); } if (bits_are_set(pISR, AT91C_UDP_EXTRSM)){ usbs_sam7_ep0.state = usbs_sam7_ep0.state & ~USBS_STATE_SUSPENDED; usbs_state_notify(&usbs_sam7_ep0); HAL_WRITE_UINT32(pICR, AT91C_UDP_EXTRSM); } if (bits_are_set(pISR, AT91C_UDP_RXRSM)){ usbs_sam7_ep0.state = usbs_sam7_ep0.state & ~USBS_STATE_SUSPENDED; usbs_state_notify(&usbs_sam7_ep0); HAL_WRITE_UINT32(pICR, AT91C_UDP_RXRSM); } if (bits_are_set(pISR, AT91C_UDP_RXSUSP)){ usbs_sam7_ep0.state = usbs_sam7_ep0.state | USBS_STATE_SUSPENDED; usbs_state_notify(&usbs_sam7_ep0); HAL_WRITE_UINT32(pICR, AT91C_UDP_RXSUSP); } if (bits_are_set(pISR, AT91C_UDP_EPINT0)){ usbs_sam7_control_dsr(); } for (n = 1; n < AT91SAM7S_USB_ENDPOINTS; n++){ if (usbs_sam7_endpoint_transfer[n]){ usbs_sam7_endpoint_dsr(n); } } cyg_drv_interrupt_unmask(vector); } static cyg_uint32 usbs_sam7_isr(cyg_vector_t vector, cyg_addrword_t data){ cyg_uint8 n; bool need_dsr = false; CYG_ASSERT(CYGNUM_HAL_INTERRUPT_UDP == vector, "Wrong interrupts"); CYG_ASSERT(0 == data, "ISR needs no data"); //diag_printf("<>\n", *(cyg_uint32 *) pISR & AT91C_UDP_ALLOWED_IRQs); for (n = 1; n < AT91SAM7S_USB_ENDPOINTS; n++){ /* Need any data endpoint a data transfer ? */ if (bits_are_set(pISR, 1 << n)){ need_dsr = need_dsr || usbs_sam7_endpoint_isr(n); /* Move the datas */ } } if (bits_are_cleared(pISR, AT91C_UDP_ALLOWED_IRQs & 0xffffff01) && !need_dsr){ /* If we don't need any DSR */ diag_printf("-"); cyg_drv_interrupt_acknowledge(vector); return CYG_ISR_HANDLED; } cyg_drv_interrupt_mask(vector); /* Call the DSR */ cyg_drv_interrupt_acknowledge(vector); diag_printf("+"); return CYG_ISR_HANDLED | CYG_ISR_CALL_DSR; } // ---------------------------------------------------------------------------- // Polling support. It is not clear that this is going to work particularly // well since according to the documentation the hardware does not generate // NAKs automatically - instead the ISR has to set the appropriate bits // sufficiently quickly to avoid confusing the host. // // Calling the isr directly avoids duplicating code, but means that // cyg_drv_interrupt_acknowledge() will get called when not inside a // real interrupt handler. This should be harmless. static void usbs_sam7_poll(usbs_control_endpoint* endpoint){ dbg debug_printf("\n"); CYG_ASSERT(endpoint == &usbs_sam7_ep0, "Wrong endpoint"); if (CYG_ISR_CALL_DSR == usbs_sam7_isr(CYGNUM_HAL_INTERRUPT_UDP, 0)) { usbs_sam7_dsr(CYGNUM_HAL_INTERRUPT_UDP, 0, 0); } } // ---------------------------------------------------------------------------- // Initialization // // This routine gets called from a prioritized static constructor during // eCos startup. void usbs_sam7_init(void){ // return; HAL_WRITE_UINT32(AT91C_BASE_PIOA + AT91_PIO_SODR, AT91C_PIO_PA4); HAL_WRITE_UINT32(AT91C_BASE_PIOA + AT91_PIO_PER, AT91C_PIO_PA3 | AT91C_PIO_PA3); HAL_WRITE_UINT32(AT91C_BASE_PIOA + AT91_PIO_OER, AT91C_PIO_PA4); usbs_sam7_handle_reset(); cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_UDP, 6, // priority 0, // data &usbs_sam7_isr, &usbs_sam7_dsr, &usbs_sam7_intr_handle, &usbs_sam7_intr_data); cyg_drv_interrupt_attach(usbs_sam7_intr_handle); cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_UDP); HAL_WRITE_UINT32(AT91C_BASE_UDP + AT91_UDP_TXVC, 0); usbs_sam7_ep0.state = USBS_STATE_POWERED; usbs_state_notify(&usbs_sam7_ep0); }