STM32: USB: correctly detect when read/write must be called without blocking
authorarighi <arighi@38d2e660-2303-0410-9eaa-f027e97ec537>
Fri, 18 Feb 2011 23:55:18 +0000 (23:55 +0000)
committerarighi <arighi@38d2e660-2303-0410-9eaa-f027e97ec537>
Fri, 18 Feb 2011 23:55:18 +0000 (23:55 +0000)
Read or write operations with the EP0 may happen within the USB
interrupt.

Make the driver able to understand when the usb_endpointRead() or
usb_endpointWrite() is called from the interrupt context or not.

Basically, only the even callbacks concerning the EP0 should be called
in a interrupt context. For all the other cases the user must take care
of using usb_endpointRead() and usb_endointWrite() from a non-atomic
(sleepable) context.

git-svn-id: https://src.develer.com/svnoss/bertos/trunk@4717 38d2e660-2303-0410-9eaa-f027e97ec537

bertos/cpu/cortex-m3/drv/usb_stm32.c

index 794aa8916f2e050461d5858b2972ca36964170e0..ac3f55fa40bc2af8ffb05a10130a43adf464647e 100644 (file)
@@ -160,6 +160,9 @@ 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)
 {
@@ -1129,7 +1132,7 @@ ssize_t usb_endpointRead(int ep, void *buffer, ssize_t size)
        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))
@@ -1183,7 +1186,7 @@ ssize_t usb_endpointWrite(int ep, const void *buffer, ssize_t size)
        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))
@@ -1806,6 +1809,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__);
@@ -1855,6 +1861,7 @@ static void usb_isr(void)
        {
                usb_isr_correct_transfer(interrupt);
        }
+       in_atomic = false;
 }
 
 /* USB: hardware initialization */