X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=bertos%2Fcpu%2Fcortex-m3%2Fdrv%2Fusb_stm32.c;h=46069ff0bec281321b7d951d50f731648c4ea4d5;hb=183859226be37f23232f080b9e7457113a0faeb7;hp=0aa4c188ee8a74a171b6e7aa2d63e9cd9fb73c9e;hpb=46a1dfc5b039beb4495945e534c746bcce91edae;p=bertos.git diff --git a/bertos/cpu/cortex-m3/drv/usb_stm32.c b/bertos/cpu/cortex-m3/drv/usb_stm32.c index 0aa4c188..46069ff0 100644 --- a/bertos/cpu/cortex-m3/drv/usb_stm32.c +++ b/bertos/cpu/cortex-m3/drv/usb_stm32.c @@ -54,17 +54,13 @@ #include #include +#include + #include /* memcpy() */ #include "usb_stm32.h" -/* XXX: consider to move this to cfg/compiler.h */ -#define ALIGNED(x) __attribute__ ((__aligned__(x))) - /* XXX: consider to move this to cfg/macros.h */ -#define ALIGN_UP(value, align) (((value) & ((align) - 1)) ? \ - (((value) + ((align) - 1)) & ~((align) - 1)) : \ - (value)) /* XXX: redefine this to make it usable within C expression */ #define _MIN(a,b) (((a) < (b)) ? (a) : (b)) @@ -92,7 +88,8 @@ struct stm32_usb static struct stm32_usb *usb = (struct stm32_usb *)USB_BASE_ADDR; /* Endpoint descriptors: used for handling requests to use with endpoints */ -static stm32_UsbEp ep_cnfg[ENP_MAX_NUMB]; +static stm32_UsbEp ep_cnfg[EP_MAX_NUM]; +STATIC_ASSERT(EP_MAX_NUM <= EP_MAX_HW_NUM); /* USB EP0 control descriptor */ static const UsbEndpointDesc USB_CtrlEpDescr0 = @@ -120,7 +117,7 @@ static const UsbEndpointDesc USB_CtrlEpDescr1 = static UsbCtrlRequest setup_packet; /* USB device controller: max supported interfaces */ -#define USB_MAX_INTERFACE 1 +#define USB_MAX_INTERFACE CONFIG_USB_INTERFACE_MAX /* USB device controller features */ #define STM32_UDC_FEATURE_SELFPOWERED BV(0) @@ -148,16 +145,20 @@ static UsbDevice *usb_dev; static stm32_UsbMemSlot *mem_use; /* USB packet memory management: memory buffer metadata */ -#define EP_MAX_SLOTS 16 -static stm32_UsbMemSlot memory_buffer[EP_MAX_SLOTS]; +static stm32_UsbMemSlot memory_buffer[EP_MAX_NUM]; /* Endpoint TX and RX buffers */ -/// \cond -/* XXX: use the empty cond section to silent a buggy doxygen warning */ -static bool rx_done, tx_done; static size_t rx_size, tx_size; -static uint8_t ep_buffer[_MIN(CONFIG_USB_BUFSIZE, USB_XFER_MAX_SIZE)] ALIGNED(4); -/// \endcond + +#define EP_BUFFER_SIZE _MIN(CONFIG_USB_BUFSIZE, USB_XFER_MAX_SIZE) +STATIC_ASSERT(!(EP_BUFFER_SIZE & 0x03)); + +static uint8_t ep_buffer[EP_MAX_NUM][EP_BUFFER_SIZE] ALIGNED(4); + +static Event usb_event_done[EP_MAX_SLOTS]; + +/* Check if we're running in atomic (non-sleepable) context or not */ +static volatile bool in_atomic = false; /* Allocate a free block of the packet memory */ static stm32_UsbMemSlot *usb_malloc(void) @@ -210,13 +211,13 @@ static bool usb_alloc_buffer(uint16_t *pOffset, uint32_t *size, mem = mem->next; } /* Check for out-of-memory condition */ - if ((*pOffset + max_size) >= USB_BDT_OFFSET) + if (UNLIKELY((*pOffset + max_size) >= USB_BDT_OFFSET)) return false; /* * Allocate a new memory block, next to the last allocated block. */ mem_useNew = usb_malloc(); - if (mem_useNew == NULL) + if (UNLIKELY(mem_useNew == NULL)) return false; /* Insert the block to the list of allocated blocks */ if (mem_use == NULL) @@ -687,7 +688,7 @@ out: \ static stm32_UsbIoStatus __usb_ep_read(int ep, void *buffer, ssize_t size, void (*complete)(int)) { - if (UNLIKELY((ep >= ENP_MAX_NUMB) || (ep & 0x01))) + if (UNLIKELY((ep >= EP_MAX_NUM) || (ep & 0x01))) { LOG_ERR("%s: invalid EP number %d\n", __func__, ep); ASSERT(0); @@ -706,7 +707,7 @@ __usb_ep_read(int ep, void *buffer, ssize_t size, void (*complete)(int)) static stm32_UsbIoStatus __usb_ep_write(int ep, const void *buffer, ssize_t size, void (*complete)(int)) { - if (UNLIKELY((ep >= ENP_MAX_NUMB) || !(ep & 0x01))) + if (UNLIKELY((ep >= EP_MAX_NUM) || !(ep & 0x01))) { LOG_ERR("%s: invalid EP number %d\n", __func__, ep); ASSERT(0); @@ -813,22 +814,27 @@ static int usb_ep_configure(const UsbEndpointDesc *epd, bool enable) switch (ep_hw->type) { case USB_ENDPOINT_XFER_CONTROL: - LOG_INFO("EP%d: CONTROL IN\n", EP >> 1); + LOG_INFO("EP%d: CONTROL %s\n", EP >> 1, + EP & 1 ? "IN" : "OUT"); ep_ctrl_set_ep_type(hw, EP_CTRL); ep_ctrl_set_ep_kind(hw, 0); break; case USB_ENDPOINT_XFER_INT: - LOG_INFO("EP%d: INTERRUPT IN\n", EP >> 1); + LOG_INFO("EP%d: INTERRUPT %s\n", EP >> 1, + EP & 1 ? "IN" : "OUT"); ep_ctrl_set_ep_type(hw, EP_INTERRUPT); ep_ctrl_set_ep_kind(hw, 0); break; case USB_ENDPOINT_XFER_BULK: - LOG_INFO("EP%d: BULK IN\n", EP >> 1); + LOG_INFO("EP%d: BULK %s\n", EP >> 1, + EP & 1 ? "IN" : "OUT"); ep_ctrl_set_ep_type(hw, EP_BULK); ep_ctrl_set_ep_kind(hw, 0); break; case USB_ENDPOINT_XFER_ISOC: - LOG_ERR("EP%d: ISOCHRONOUS IN: not supported\n", EP >> 1); + LOG_ERR("EP%d: ISOCHRONOUS %s: not supported\n", + EP >> 1, + EP & 1 ? "IN" : "OUT"); /* Fallback to default */ default: ASSERT(0); @@ -1106,24 +1112,24 @@ static void usb_status_handler(UNUSED_ARG(int, EP)) static void usb_endpointRead_complete(int ep) { - if (UNLIKELY(ep >= ENP_MAX_NUMB)) + if (UNLIKELY(ep >= EP_MAX_NUM)) { ASSERT(0); return; } ASSERT(!(ep & 0x01)); - rx_done = true; + event_do(&usb_event_done[ep >> 1]); rx_size = ep_cnfg[ep].size; } ssize_t usb_endpointRead(int ep, void *buffer, ssize_t size) { int ep_num = usb_ep_logical_to_hw(ep); - ssize_t max_size = sizeof(ep_buffer); + ssize_t max_size = sizeof(ep_buffer[ep_num]); /* Non-blocking read for EP0 */ - if (ep_num == CTRL_ENP_OUT) + if (in_atomic && (ep_num == CTRL_ENP_OUT)) { size = usb_size(size, usb_le16_to_cpu(setup_packet.wLength)); if (UNLIKELY(size > max_size)) @@ -1137,47 +1143,47 @@ ssize_t usb_endpointRead(int ep, void *buffer, ssize_t size) usb_status_handler(ep_num); else { - __usb_ep_read(ep_num, ep_buffer, size, + __usb_ep_read(ep_num, ep_buffer[ep_num], size, usb_status_handler); - memcpy(buffer, ep_buffer, size); + memcpy(buffer, ep_buffer[ep_num], size); } return size; } if (UNLIKELY(!size)) return 0; size = MIN(size, max_size); - rx_done = false; + event_initGeneric(&usb_event_done[ep_num >> 1]); rx_size = 0; /* Blocking read */ - __usb_ep_read(ep_num, ep_buffer, size, usb_endpointRead_complete); - while (!rx_done) - cpu_relax(); - memcpy(buffer, ep_buffer, rx_size); + __usb_ep_read(ep_num, ep_buffer[ep_num], size, + usb_endpointRead_complete); + event_wait(&usb_event_done[ep_num >> 1]); + memcpy(buffer, ep_buffer[ep_num], rx_size); return rx_size; } static void usb_endpointWrite_complete(int ep) { - if (UNLIKELY(ep >= ENP_MAX_NUMB)) + if (UNLIKELY(ep >= EP_MAX_NUM)) { ASSERT(0); return; } ASSERT(ep & 0x01); - tx_done = true; + event_do(&usb_event_done[ep >> 1]); tx_size = ep_cnfg[ep].size; } ssize_t usb_endpointWrite(int ep, const void *buffer, ssize_t size) { int ep_num = usb_ep_logical_to_hw(ep); - ssize_t max_size = sizeof(ep_buffer); + ssize_t max_size = sizeof(ep_buffer[ep_num]); /* Non-blocking write for EP0 */ - if (ep_num == CTRL_ENP_IN) + if (in_atomic && (ep_num == CTRL_ENP_IN)) { size = usb_size(size, usb_le16_to_cpu(setup_packet.wLength)); if (UNLIKELY(size > max_size)) @@ -1191,8 +1197,8 @@ ssize_t usb_endpointWrite(int ep, const void *buffer, ssize_t size) usb_status_handler(ep_num); else { - memcpy(ep_buffer, buffer, size); - __usb_ep_write(ep_num, ep_buffer, size, + memcpy(ep_buffer[ep_num], buffer, size); + __usb_ep_write(ep_num, ep_buffer[ep_num], size, usb_status_handler); } return size; @@ -1200,14 +1206,14 @@ ssize_t usb_endpointWrite(int ep, const void *buffer, ssize_t size) if (UNLIKELY(!size)) return 0; size = MIN(size, max_size); - tx_done = false; + event_initGeneric(&usb_event_done[ep_num >> 1]); tx_size = 0; /* Blocking write */ - memcpy(ep_buffer, buffer, size); - __usb_ep_write(ep_num, ep_buffer, size, usb_endpointWrite_complete); - while (!tx_done) - cpu_relax(); + memcpy(ep_buffer[ep_num], buffer, size); + __usb_ep_write(ep_num, ep_buffer[ep_num], size, + usb_endpointWrite_complete); + event_wait(&usb_event_done[ep_num >> 1]); return tx_size; } @@ -1489,11 +1495,8 @@ static void usb_get_descriptor_handler(void) if ((setup_packet.mRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) usb_get_descriptor(); - /* Getting descriptor for a device is a standard request */ - else if ((setup_packet.mRequestType & USB_DIR_MASK) == USB_DIR_IN) - usb_event_handler(usb_dev); else - ep_cnfg[CTRL_ENP_OUT].status = STALLED; + usb_event_handler(usb_dev); } /* USB setup packet: SET_ADDRESS handler */ @@ -1579,6 +1582,7 @@ static int usb_set_config_state(uint32_t conf) udc.alt[i] = 0; usb_set_device_state(USB_STATE_CONFIGURED); usb_dev->configured = true; + event_do(&usb_event_done[0]); LOG_INFO("%s: device configured\n", __func__); } else @@ -1802,6 +1806,9 @@ static void usb_isr(void) interrupt.status = usb->ISTR; interrupt.status &= usb->CNTR | 0x1f; + /* Set the context as atomic */ + in_atomic = true; + if (interrupt.PMAOVR) { LOG_WARN("%s: DMA overrun / underrun\n", __func__); @@ -1851,6 +1858,7 @@ static void usb_isr(void) { usb_isr_correct_transfer(interrupt); } + in_atomic = false; } /* USB: hardware initialization */ @@ -1915,8 +1923,11 @@ int usb_deviceRegister(UsbDevice *dev) MOD_CHECK(proc); #endif usb_dev = dev; + usb_dev->configured = false; + + event_initGeneric(&usb_event_done[0]); usb_init(); - while (!usb_dev->configured) - cpu_relax(); + event_wait(&usb_event_done[0]); + return 0; }