# HG changeset patch # User jld # Date 1289564071 0 # Node ID 1a427c29fd0fccca717e6929bfdc328a44dc5b19 # Parent 8536a2fc60a4b84fd16e65a3b963f3c68b9d2dc0 * src/usbs_at91.c : Complete support for halting endpoints * cdl/usbs_at91.cdl : Add option CYGSEM_DEVS_USB_AT91_ZERO_LENGTH_PACKET_TERMINATION. When data transfer length is known from both side, sending an empty packet at the end of the transfer is not required. Add devtab entry for endpoints 4 to 7. diff --git a/packages/devs/usb/at91/current/ChangeLog b/packages/devs/usb/at91/current/ChangeLog --- a/packages/devs/usb/at91/current/ChangeLog +++ b/packages/devs/usb/at91/current/ChangeLog @@ -1,3 +1,12 @@ +2010-11-12 Christophe Coutand + + * src/usbs_at91.c : Complete support for halting endpoints + * cdl/usbs_at91.cdl : Add option + CYGSEM_DEVS_USB_AT91_ZERO_LENGTH_PACKET_TERMINATION. When data + transfer length is known from both side, sending an empty packet + at the end of the transfer is not required. + Add devtab entry for endpoints 4 to 7. + 2008-11-17 Gabor Toeroek * src/usbs_at91.c (usbs_at91_set_pullup): Fix typo introduced by @@ -101,7 +110,7 @@ 2006-03-06 Oliver Munz // ####GPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. -// Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. +// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2010 Free Software Foundation, Inc. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/packages/devs/usb/at91/current/cdl/usbs_at91.cdl b/packages/devs/usb/at91/current/cdl/usbs_at91.cdl --- a/packages/devs/usb/at91/current/cdl/usbs_at91.cdl +++ b/packages/devs/usb/at91/current/cdl/usbs_at91.cdl @@ -8,7 +8,7 @@ ## ####ECOSGPLCOPYRIGHTBEGIN#### ## ------------------------------------------- ## This file is part of eCos, the Embedded Configurable Operating System. -## Copyright (C) 2006 Free Software Foundation, Inc. +## Copyright (C) 2006, 2010 Free Software Foundation, Inc. ## ## eCos is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free @@ -41,7 +41,7 @@ # # Author(s): Oliver Munz, Andrew Lunn # Original data: bartv -# Contributors: +# Contributors: ccoutand # Date: 2006-02-25 # #####DESCRIPTIONEND#### @@ -143,6 +143,17 @@ cdl_package CYGPKG_DEVS_USB_AT91 { This option indicates that the power detect pin should be inverted. ie VDD is active, VCC is inactive." } + + cdl_option CYGSEM_DEVS_USB_AT91_ZERO_LENGTH_PACKET_TERMINATION { + display "Allow USB driver to end data transfer with an empty data packet." + flavor bool + default_value 1 + description " + This option allows the USB driver to automatically signal the + end of a data transmission with an empty packet, if the last packet + fragment is equal to the endpoint buffer size." + } + } cdl_component CYGPKG_DEVS_USB_AT91_DEVTAB_ENTRIES { @@ -203,21 +214,73 @@ cdl_package CYGPKG_DEVS_USB_AT91 { application intends to access the endpoint by means of open and read calls then a devtab entry is needed." } - - cdl_option CYGDAT_DEVS_USB_AT91_DEVTAB_BASENAME { - display "Base name for devtab entries" - flavor data - default_value { "\"/dev/usbs\"" } - description " - If the uAT91 USB device driver package provides devtab - entries for any of the endpoints then this option gives - control over the names of these entries. By default the - endpoints will be called \"/dev/usbs0c\", \"/dev/usbs3w\" - and \"/dev/usbs4r\" (assuming all three endpoints are - enabled. The common part \"/dev/usbs\" is determined - by this configuration option. It may be necessary to - change this if there are multiple USB slave-side - devices on the target hardware to prevent a name clash." - } + + cdl_option CYGVAR_DEVS_USB_AT91_EP4_DEVTAB_ENTRY { + display "Provide a devtab entry for endpoint 4" + flavor bool + default_value 0 + requires CYGPKG_IO + description " + If this endpoint will only be accessed via the low-level + USB-specific calls then there is no need for an entry + in the device table, saving some memory. If the + application intends to access the endpoint by means + of open and read calls then a devtab entry is needed." + } + + cdl_option CYGVAR_DEVS_USB_AT91_EP5_DEVTAB_ENTRY { + display "Provide a devtab entry for endpoint 5" + flavor bool + default_value 0 + requires CYGPKG_IO + description " + If this endpoint will only be accessed via the low-level + USB-specific calls then there is no need for an entry + in the device table, saving some memory. If the + application intends to access the endpoint by means + of open and read calls then a devtab entry is needed." + } + + cdl_option CYGVAR_DEVS_USB_AT91_EP6_DEVTAB_ENTRY { + display "Provide a devtab entry for endpoint 6" + flavor bool + default_value 0 + requires CYGPKG_IO + description " + If this endpoint will only be accessed via the low-level + USB-specific calls then there is no need for an entry + in the device table, saving some memory. If the + application intends to access the endpoint by means + of open and read calls then a devtab entry is needed." + } + + cdl_option CYGVAR_DEVS_USB_AT91_EP7_DEVTAB_ENTRY { + display "Provide a devtab entry for endpoint 7" + flavor bool + default_value 0 + requires CYGPKG_IO + description " + If this endpoint will only be accessed via the low-level + USB-specific calls then there is no need for an entry + in the device table, saving some memory. If the + application intends to access the endpoint by means + of open and read calls then a devtab entry is needed." + } + + cdl_option CYGDAT_DEVS_USB_AT91_DEVTAB_BASENAME { + display "Base name for devtab entries" + flavor data + default_value { "\"/dev/usbs\"" } + description " + If the uAT91 USB device driver package provides devtab + entries for any of the endpoints then this option gives + control over the names of these entries. By default the + endpoints will be called \"/dev/usbs0c\", \"/dev/usbs3w\" + and \"/dev/usbs4r\" (assuming all three endpoints are + enabled. The common part \"/dev/usbs\" is determined + by this configuration option. It may be necessary to + change this if there are multiple USB slave-side + devices on the target hardware to prevent a name clash." + } } } diff --git a/packages/devs/usb/at91/current/src/usbs_at91.c b/packages/devs/usb/at91/current/src/usbs_at91.c --- a/packages/devs/usb/at91/current/src/usbs_at91.c +++ b/packages/devs/usb/at91/current/src/usbs_at91.c @@ -8,7 +8,7 @@ // ####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. -// Copyright (C) 2006 Free Software Foundation, Inc. +// Copyright (C) 2006, 2010 Free Software Foundation, Inc. // // eCos is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free @@ -40,7 +40,7 @@ //#####DESCRIPTIONBEGIN#### // // Author(s): Oliver Munz, -// Contributors: Andrew Lunn, bartv +// Contributors: Andrew Lunn, bartv, ccoutand // Date: 2006-02-22 // // This code implements support for the on-chip USB port on the AT91 @@ -524,7 +524,7 @@ usbs_state_notify (usbs_control_endpoint } if (pcep->state_change_fn) { - (*pcep->state_change_fn) (pcep, 0, pcep->state, old_state); + (*pcep->state_change_fn) (pcep, pcep->state_change_data, pcep->state, old_state); } old_state = pcep->state; @@ -579,22 +579,35 @@ usbs_at91_endpoint_set_halted (usbs_rx_e { int epn = usbs_at91_pep_to_number(pep); cyg_addrword_t pCSR = pCSRn(epn); - + cyg_uint32 reg; + cyg_drv_dsr_lock (); - if (pep->halted != new_value) { + if (pep->halted != new_value) { /* There is something is to do */ pep->halted = new_value; + + if ( new_value ) { - if (new_value && BITS_ARE_SET (pIMR, 1 << epn)) { - /* Ready to transmit */ + /* Halt endpoint */ + SET_BITS (pCSR, AT91_UDP_CSR_FORCESTALL); + + } else { + /* Restart endpoint */ + CLEAR_BITS (pCSR, AT91_UDP_CSR_FORCESTALL); + + // Reset Fifo + HAL_READ_UINT32 (AT91_UDP + AT91_UDP_RST_EP, reg); + reg |= (1 << epn); + HAL_WRITE_UINT32 (AT91_UDP + AT91_UDP_RST_EP, reg); + reg &= ~(1 << epn); + HAL_WRITE_UINT32 (AT91_UDP + AT91_UDP_RST_EP, reg); + + // Ready to use if (pep->complete_fn) { - (*pep->complete_fn) (pep->complete_data, -EAGAIN); + (*pep->complete_fn) (pep->complete_data, ENOERR); } - usbs_at91_endpoint_interrupt_enable (epn, false); - SET_BITS (pCSR, AT91_UDP_CSR_FORCESTALL); - } else { - CLEAR_BITS (pCSR, AT91_UDP_CSR_FORCESTALL); + } } cyg_drv_dsr_unlock (); @@ -726,11 +739,14 @@ usbs_at91_endpoint_start (usbs_rx_endpoi return; } + // Is this endpoint currently stalled? If so then a size of 0 can + // be used to block until the stall condition is clear, anything + // else should result in an immediate callback. if (pep->halted) { /* Halted means nothing to do */ cyg_drv_dsr_unlock (); - if (pep->complete_fn) { + if (pep->complete_fn && pep->buffer_size != 0) { (*pep->complete_fn) (pep->complete_data, -EAGAIN); } return; @@ -753,9 +769,12 @@ usbs_at91_endpoint_start (usbs_rx_endpoi if (BITS_ARE_SET (pCSR, 0x400)) { /* IN: tx_endpoint */ space = (cyg_uint32) * ppend - (cyg_uint32) * ppbegin; + +#ifdef CYGSEM_DEVS_USB_AT91_ZERO_LENGTH_PACKET_TERMINATION if (space == endpoint_size) { *ppend = *ppbegin; /* Send zero-packet */ } +#endif *ppbegin = write_fifo_uint8 (pFDR, *ppbegin, @@ -786,26 +805,32 @@ usbs_at91_endpoint_isr_tx(cyg_uint8 epn) CLEAR_BITS (pCSR, AT91_UDP_CSR_TXCOMP); - if (BITS_ARE_CLEARED (pCSR, AT91_UDP_CSR_TXPKTRDY)) { + if (BITS_ARE_CLEARED (pCSR, AT91_UDP_CSR_TXPKTRDY)) { /* Ready to transmit ? */ if (*ppend > *ppbegin) { /* Something to send */ space = (cyg_uint32) * ppend - (cyg_uint32) * ppbegin; + +#ifdef CYGSEM_DEVS_USB_AT91_ZERO_LENGTH_PACKET_TERMINATION if (space == endpoint_size) { *ppend = *ppbegin; /* Send zero-packet */ } +#endif *ppbegin = write_fifo_uint8 (pFDR, *ppbegin, (cyg_uint8 *) ((cyg_uint32) * ppbegin + MIN (space, endpoint_size))); SET_BITS (pCSR, AT91_UDP_CSR_TXPKTRDY); - + if (*ppend == *ppbegin) { /* Last packet ? */ *ppend = *ppbegin - 1; /* The packet isn't sent yet */ } + } else { + +#ifdef CYGSEM_DEVS_USB_AT91_ZERO_LENGTH_PACKET_TERMINATION if (*ppend + 1 == *ppbegin) { *ppend = *ppbegin; /* Flag for DSR */ return true; @@ -813,6 +838,11 @@ usbs_at91_endpoint_isr_tx(cyg_uint8 epn) *ppend = *ppbegin - 1; /* Flag for zero-packet */ SET_BITS (pCSR, AT91_UDP_CSR_TXPKTRDY); /* Send no data */ } +#else + *ppend = *ppbegin; /* Flag for DSR */ + return true; +#endif + } } @@ -887,6 +917,11 @@ usbs_at91_endpoint_isr (cyg_uint8 epn) CYG_ASSERT (AT91_USB_ENDPOINTS > epn && epn, "Invalid end point"); + // Host has acknowledged the endpoint being stall + if (BITS_ARE_SET (pCSR, AT91_UDP_CSR_ISOERROR)) { + CLEAR_BITS (pCSR, AT91_UDP_CSR_ISOERROR); + } + if (BITS_ARE_SET (pCSR, 0x400)) { /* IN: tx_endpoint */ if (usbs_at91_endpoint_isr_tx(epn)) return true; // Call the DSR @@ -920,12 +955,15 @@ usbs_at91_endpoint_dsr (cyg_uint8 epn) if (*ppend == *ppbegin) { /* Transmitted/Received ? */ pep->buffer_size = (cyg_uint32) * ppbegin - (cyg_uint32) pep->buffer; - if (pep->buffer_size && pep->complete_fn) { - if (!pep->halted) { - (*pep->complete_fn) (pep->complete_data, pep->buffer_size); - } else { - (*pep->complete_fn) (pep->complete_data, -EAGAIN); - } + if (pep->complete_fn) + { + /* Do not check on pep->buffer_size != 0, user should + * be allowed to send empty packet */ + if (!pep->halted) { + (*pep->complete_fn) (pep->complete_data, pep->buffer_size); + } else { + (*pep->complete_fn) (pep->complete_data, -EAGAIN); + } } usbs_at91_endpoint_interrupt_enable (epn, false); } @@ -1018,6 +1056,8 @@ usbs_at91_control_setup_set_feature(void ep0_low_level_status_t status; usb_devreq *req = (usb_devreq *)usbs_at91_ep0.control_buffer; cyg_uint8 recipient = req->type & USB_DEVREQ_RECIPIENT_MASK; + usbs_rx_endpoint * pep; + cyg_uint8 ep_num = req->index_lo & 0x0F; usbs_at91_control_setup_send_ack(); status = EP0_LL_SEND_READY; @@ -1030,18 +1070,24 @@ usbs_at91_control_setup_set_feature(void // Nothing to do break; case USB_DEVREQ_RECIPIENT_ENDPOINT: - if ((usbs_at91_ep0.state == USBS_STATE_CONFIGURED) && - (req->index_lo > 0) && - (req->index_lo < AT91_USB_ENDPOINTS)) { + if ((usbs_at91_ep0.state == USBS_STATE_CONFIGURED) && + (ep_num > 0) && + (ep_num < AT91_USB_ENDPOINTS)) { cyg_uint32 CSR; - - HAL_READ_UINT32(pCSRn(req->index_lo), CSR); - if (CSR & AT91_UDP_CSR_EPEDS) { - /* TODO */ + + HAL_READ_UINT32(pCSRn(ep_num), CSR); + pep = (usbs_rx_endpoint *) usbs_at91_endpoints[ep_num]; + if ( (CSR & AT91_UDP_CSR_EPEDS) ) { + usbs_at91_endpoint_set_halted ( pep , true ); } - } else { + else + status = EP0_LL_STALL; + + } + else { status = EP0_LL_STALL; } + break; default: status = EP0_LL_STALL; } @@ -1055,6 +1101,8 @@ usbs_at91_control_setup_clear_feature(vo ep0_low_level_status_t status; usb_devreq *req = (usb_devreq *)usbs_at91_ep0.control_buffer; cyg_uint8 recipient = req->type & USB_DEVREQ_RECIPIENT_MASK; + usbs_rx_endpoint * pep; + cyg_uint8 ep_num = req->index_lo & 0x0F; usbs_at91_control_setup_send_ack(); status = EP0_LL_SEND_READY; @@ -1067,18 +1115,24 @@ usbs_at91_control_setup_clear_feature(vo // Nothing to do break; case USB_DEVREQ_RECIPIENT_ENDPOINT: - if ((usbs_at91_ep0.state == USBS_STATE_CONFIGURED) && - (req->index_lo > 0) && - (req->index_lo < AT91_USB_ENDPOINTS)) { + if ((usbs_at91_ep0.state == USBS_STATE_CONFIGURED) && + (ep_num > 0) && + (ep_num < AT91_USB_ENDPOINTS)) { cyg_uint32 CSR; - - HAL_READ_UINT32(pCSRn(req->index_lo), CSR); - if (CSR & AT91_UDP_CSR_EPEDS) { - /* TODO */ + + HAL_READ_UINT32(pCSRn(ep_num), CSR); + pep = (usbs_rx_endpoint *) usbs_at91_endpoints[ep_num]; + if ( (CSR & AT91_UDP_CSR_EPEDS) && pep->halted ) { + usbs_at91_endpoint_set_halted ( pep , false ); } - } else { + else + status = EP0_LL_STALL; + + } + else { status = EP0_LL_STALL; } + break; default: status = EP0_LL_STALL; }