7575#define EP_IS_IN (ep ) (((ep) & USB_EP_DIR_MASK) == USB_EP_DIR_IN)
7676#define EP_IS_OUT (ep ) (((ep) & USB_EP_DIR_MASK) == USB_EP_DIR_OUT)
7777
78+ /* Transfer completion callback */
79+ typedef void (* usb_dc_transfer_callback )(u8_t ep , int status , size_t tsize );
80+
7881/* Endpoint state */
7982struct usb_dc_stm32_ep_state {
8083 u16_t ep_mps ; /** Endpoint max packet size */
@@ -83,7 +86,11 @@ struct usb_dc_stm32_ep_state {
8386 u8_t ep_stalled ; /** Endpoint stall flag */
8487 u32_t read_count ; /** Number of bytes in read buffer */
8588 u32_t read_offset ; /** Current offset in read buffer */
86- struct k_sem write_sem ; /** Write boolean semaphore */
89+ u8_t * transfer_buf ; /** IN/OUT transfer buffer */
90+ u32_t transfer_size ; /** number of bytes processed by the tranfer */
91+ int transfer_result ; /** Transfer result */
92+ usb_dc_transfer_callback transfer_cb ; /** Transfer callback */
93+ struct k_sem transfer_sem ; /** transfer boolean semaphore */
8794};
8895
8996/* Driver state */
@@ -172,7 +179,10 @@ static int usb_dc_stm32_init(void)
172179 for (i = 0 ; i < CONFIG_USB_DC_STM32_EP_NUM ; i ++ ) {
173180 HAL_PCDEx_SetTxFiFo (& usb_dc_stm32_state .pcd , i ,
174181 FIFO_EP_WORDS );
175- k_sem_init (& usb_dc_stm32_state .in_ep_state [i ].write_sem , 1 , 1 );
182+ k_sem_init (& usb_dc_stm32_state .in_ep_state [i ].transfer_sem , 1 ,
183+ 1 );
184+ k_sem_init (& usb_dc_stm32_state .out_ep_state [i ].transfer_sem , 1 ,
185+ 1 );
176186 }
177187
178188 IRQ_CONNECT (STM32F4_IRQ_OTG_FS , CONFIG_USB_DC_STM32_IRQ_PRI ,
@@ -243,10 +253,105 @@ int usb_dc_set_address(const u8_t addr)
243253 return 0 ;
244254}
245255
246- int usb_dc_ep_start_read (u8_t ep , u8_t * data , u32_t max_data_len )
256+ static int usb_dc_ep_transfer (const u8_t ep , u8_t * buf , size_t dlen , bool is_in ,
257+ usb_dc_transfer_callback cb )
247258{
259+ struct usb_dc_stm32_ep_state * ep_state = usb_dc_stm32_get_ep_state (ep );
248260 HAL_StatusTypeDef status ;
261+ int ret = 0 ;
262+
263+ SYS_LOG_DBG ("ep 0x%02x, len=%d, in=%d, sync=%s" , ep , dlen , is_in ,
264+ cb ? "no" : "yes" );
265+
266+ if (!dlen && !is_in ) {
267+ HAL_PCD_EP_Receive (& usb_dc_stm32_state .pcd , ep , NULL , 0 );
268+ return 0 ;
269+ }
270+
271+ /* Transfer Already Ongoing ? */
272+ if (k_sem_take (& ep_state -> transfer_sem , K_NO_WAIT )) {
273+ return - EBUSY ;
274+ }
275+
276+ ep_state -> transfer_buf = buf ;
277+ ep_state -> transfer_result = - EBUSY ;
278+ ep_state -> transfer_size = dlen ;
279+ ep_state -> transfer_cb = cb ;
280+
281+ if (!k_is_in_isr ()) {
282+ irq_disable (STM32F4_IRQ_OTG_FS );
283+ }
284+
285+ /* Configure and start transfer */
286+ if (is_in ) { /* DEV to HOST */
287+ status = HAL_PCD_EP_Transmit (& usb_dc_stm32_state .pcd , ep ,
288+ ep_state -> transfer_buf , dlen );
289+ } else { /* HOST TO DEV */
290+ status = HAL_PCD_EP_Receive (& usb_dc_stm32_state .pcd , ep ,
291+ ep_state -> transfer_buf , dlen );
292+ }
293+
294+ if (status != HAL_OK ) {
295+ SYS_LOG_ERR ("ep 0x%02x, transfer error %d" , ep , ret );
296+ ep_state -> transfer_buf = NULL ;
297+ ret = - EIO ;
298+ }
299+
300+ if (!k_is_in_isr ()) {
301+ irq_enable (STM32F4_IRQ_OTG_FS );
302+ }
303+
304+ if (ep_state -> transfer_cb || ret ) { /* asynchronous transfer or error */
305+ return ret ;
306+ }
307+
308+ /* Synchronous transfer */
309+ if (k_sem_take (& ep_state -> transfer_sem , K_FOREVER )) {
310+ SYS_LOG_ERR ("ep 0x%02x, transfer error" , ep );
311+ ep_state -> transfer_buf = NULL ;
312+ return - ETIMEDOUT ;
313+ }
314+
315+ if (ep_state -> transfer_result ) { /* error < 0 */
316+ ret = ep_state -> transfer_result ;
317+ } else { /* synchronous transfer success, return processed bytes */
318+ ret = ep_state -> transfer_size ;
319+ }
320+
321+ k_sem_give (& ep_state -> transfer_sem );
322+
323+ return ret ;
324+ }
325+
326+ static void __legacy_out_cb (u8_t ep , int status , size_t tsize )
327+ {
328+ struct usb_dc_stm32_ep_state * ep_state = usb_dc_stm32_get_ep_state (ep );
329+
330+ ARG_UNUSED (status );
331+
332+ /* Transfer completed, data is stored in our legacy endpoint buffer */
333+ ep_state -> read_count = tsize ;
334+ ep_state -> read_offset = 0 ;
335+
336+ if (ep_state -> cb ) {
337+ ep_state -> cb (ep , USB_DC_EP_DATA_OUT );
338+ }
339+ }
249340
341+ static void __legacy_in_cb (u8_t ep , int status , size_t tsize )
342+ {
343+ struct usb_dc_stm32_ep_state * ep_state = usb_dc_stm32_get_ep_state (ep );
344+
345+ ARG_UNUSED (status );
346+ ARG_UNUSED (tsize );
347+
348+ if (ep_state -> cb ) {
349+ ep_state -> cb (ep , USB_DC_EP_DATA_IN );
350+ }
351+ }
352+
353+ int usb_dc_ep_start_read (u8_t ep , u8_t * data , u32_t max_data_len )
354+ {
250355 SYS_LOG_DBG ("ep 0x%02x, len %u" , ep , max_data_len );
251356
252357 /* we flush EP0_IN by doing a 0 length receive on it */
@@ -259,16 +364,9 @@ int usb_dc_ep_start_read(u8_t ep, u8_t *data, u32_t max_data_len)
259364 max_data_len = USB_OTG_FS_MAX_PACKET_SIZE ;
260365 }
261366
262- status = HAL_PCD_EP_Receive (& usb_dc_stm32_state .pcd , ep ,
263- usb_dc_stm32_state .ep_buf [EP_IDX (ep )],
264- max_data_len );
265- if (status != HAL_OK ) {
266- SYS_LOG_ERR ("HAL_PCD_EP_Receive failed(0x%02x), %d" ,
267- ep , (int )status );
268- return - EIO ;
269- }
270-
271- return 0 ;
367+ /* asynchronous out transfer to keep legacy behaviour */
368+ return usb_dc_ep_transfer (ep , data , max_data_len , false,
369+ __legacy_out_cb );
272370}
273371
274372int usb_dc_ep_get_read_count (u8_t ep , u32_t * read_bytes )
@@ -440,8 +538,6 @@ int usb_dc_ep_disable(const u8_t ep)
440538int usb_dc_ep_write (const u8_t ep , const u8_t * const data ,
441539 const u32_t data_len , u32_t * const ret_bytes )
442540{
443- struct usb_dc_stm32_ep_state * ep_state = usb_dc_stm32_get_ep_state (ep );
444- HAL_StatusTypeDef status ;
445541 int ret = 0 ;
446542
447543 SYS_LOG_DBG ("ep 0x%02x, len %u" , ep , data_len );
@@ -451,24 +547,14 @@ int usb_dc_ep_write(const u8_t ep, const u8_t *const data,
451547 return - EINVAL ;
452548 }
453549
454- ret = k_sem_take (& ep_state -> write_sem , 1000 );
455- if (ret ) {
456- SYS_LOG_ERR ("Unable to write ep 0x%02x (%d)" , ep , ret );
457- return ret ;
458- }
459-
460- if (!k_is_in_isr ()) {
461- irq_disable (STM32F4_IRQ_OTG_FS );
462- }
463-
464- status = HAL_PCD_EP_Transmit (& usb_dc_stm32_state .pcd , ep ,
465- (void * )data , data_len );
466- if (status != HAL_OK ) {
467- SYS_LOG_ERR ("HAL_PCD_EP_Transmit failed(0x%02x), %d" ,
468- ep , (int )status );
469- k_sem_give (& ep_state -> write_sem );
470- ret = - EIO ;
471- }
550+ do {
551+ /* For now we want to preserve legacy ep_write behavior.
552+ * If ep transfer fails due to ongoing transfer, try again.
553+ */
554+ ret = usb_dc_ep_transfer (ep , (u8_t * )data , data_len , true,
555+ __legacy_in_cb );
556+ k_yield ();
557+ } while (ret == - EBUSY );
472558
473559 if (!ret && ep == EP0_IN ) {
474560 /* Wait for an empty package as from the host.
@@ -477,10 +563,6 @@ int usb_dc_ep_write(const u8_t ep, const u8_t *const data,
477563 usb_dc_ep_start_read (ep , NULL , 0 );
478564 }
479565
480- if (!k_is_in_isr ()) {
481- irq_enable (STM32F4_IRQ_OTG_FS );
482- }
483-
484566 if (ret_bytes ) {
485567 * ret_bytes = data_len ;
486568 }
@@ -639,14 +721,17 @@ void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, u8_t epnum)
639721 SYS_LOG_DBG ("epnum 0x%02x, rx_count %u" , epnum ,
640722 HAL_PCD_EP_GetRxCount (& usb_dc_stm32_state .pcd , epnum ));
641723
642- /* Transaction complete, data is now stored in the buffer and ready
643- * for the upper stack (usb_dc_ep_read to retrieve).
644- */
645- usb_dc_ep_get_read_count (ep , & ep_state -> read_count );
646- ep_state -> read_offset = 0 ;
724+ if (!ep_state -> transfer_buf ) { /* ignore if no transfer buffer */
725+ return ;
726+ }
647727
648- if (ep_state -> cb ) {
649- ep_state -> cb (ep , USB_DC_EP_DATA_OUT );
728+ ep_state -> transfer_buf = NULL ;
729+ ep_state -> transfer_result = 0 ;
730+ usb_dc_ep_get_read_count (ep , & ep_state -> transfer_size );
731+ k_sem_give (& ep_state -> transfer_sem );
732+
733+ if (ep_state -> transfer_cb ) {
734+ ep_state -> transfer_cb (ep , 0 , ep_state -> transfer_size );
650735 }
651736}
652737
@@ -658,9 +743,15 @@ void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, u8_t epnum)
658743
659744 SYS_LOG_DBG ("epnum 0x%02x" , epnum );
660745
661- k_sem_give (& ep_state -> write_sem );
746+ if (!ep_state -> transfer_buf ) { /* ignore if no transfer buffer */
747+ return ;
748+ }
662749
663- if (ep_state -> cb ) {
664- ep_state -> cb (ep , USB_DC_EP_DATA_IN );
750+ ep_state -> transfer_buf = NULL ;
751+ ep_state -> transfer_result = 0 ;
752+ k_sem_give (& ep_state -> transfer_sem );
753+
754+ if (ep_state -> transfer_cb ) {
755+ ep_state -> transfer_cb (ep , 0 , ep_state -> transfer_size );
665756 }
666757}
0 commit comments