Skip to content

USB device transfer #5983

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Mar 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions drivers/usb/device/usb_dc_dw.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <stdio.h>
#include <misc/byteorder.h>
#include <usb/usb_dc.h>
#include <usb/usb_device.h>
#include "usb_dw_registers.h"
#include "clk.h"

Expand Down Expand Up @@ -420,6 +421,12 @@ static int usb_dw_tx(u8_t ep, const u8_t *const data,
return -EAGAIN;
}

/* For now tx-fifo sizes are not configured (cf usb_dw_set_fifo). Here
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@finikorg maybe relevant to #5678

* we force available fifo size to be a multiple of ep mps in order to
* prevent splitting data incorrectly.
*/
avail_space -= avail_space % ep_mps;

if (data_len > avail_space) {
data_len = avail_space;
}
Expand Down Expand Up @@ -931,8 +938,9 @@ int usb_dc_ep_enable(const u8_t ep)
usb_dw_ctrl.in_ep_ctrl[ep_idx].ep_ena = 1;
}

if (USB_DW_EP_ADDR2DIR(ep) == USB_EP_DIR_OUT) {
/* Prepare EP for rx */
if (USB_DW_EP_ADDR2DIR(ep) == USB_EP_DIR_OUT &&
usb_dw_ctrl.out_ep_ctrl[ep_idx].cb != usb_transfer_ep_callback) {
/* Start reading now, except for transfer managed eps */
usb_dw_prep_rx(ep, 0);
}

Expand Down Expand Up @@ -1174,3 +1182,8 @@ int usb_dc_set_status_callback(const usb_dc_status_callback cb)

return 0;
}

int usb_dc_ep_mps(const u8_t ep)
{
return usb_dw_ctrl.out_ep_ctrl[USB_DW_EP_ADDR2IDX(ep)].mps;
}
196 changes: 55 additions & 141 deletions drivers/usb/device/usb_dc_stm32.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,6 @@
#define EP_IS_IN(ep) (((ep) & USB_EP_DIR_MASK) == USB_EP_DIR_IN)
#define EP_IS_OUT(ep) (((ep) & USB_EP_DIR_MASK) == USB_EP_DIR_OUT)

/* Transfer completion callback */
typedef void (*usb_dc_transfer_callback)(u8_t ep, int status, size_t tsize);

/* Endpoint state */
struct usb_dc_stm32_ep_state {
u16_t ep_mps; /** Endpoint max packet size */
Expand All @@ -99,11 +96,7 @@ struct usb_dc_stm32_ep_state {
u8_t ep_stalled; /** Endpoint stall flag */
u32_t read_count; /** Number of bytes in read buffer */
u32_t read_offset; /** Current offset in read buffer */
u8_t *transfer_buf; /** IN/OUT transfer buffer */
u32_t transfer_size; /** number of bytes processed by the tranfer */
int transfer_result; /** Transfer result */
usb_dc_transfer_callback transfer_cb; /** Transfer callback */
struct k_sem transfer_sem; /** transfer boolean semaphore */
struct k_sem write_sem; /** Write boolean semaphore */
};

/* Driver state */
Expand Down Expand Up @@ -192,13 +185,7 @@ static int usb_dc_stm32_init(void)
for (i = 0; i < NUM_IN_EP; i++) {
HAL_PCDEx_SetTxFiFo(&usb_dc_stm32_state.pcd, i,
FIFO_EP_WORDS);
k_sem_init(&usb_dc_stm32_state.in_ep_state[i].transfer_sem, 1,
1);
}

for (i = 0; i < NUM_OUT_EP; i++) {
k_sem_init(&usb_dc_stm32_state.out_ep_state[i].transfer_sem, 1,
1);
k_sem_init(&usb_dc_stm32_state.in_ep_state[i].write_sem, 1, 1);
}

IRQ_CONNECT(CONFIG_USB_IRQ, CONFIG_USB_IRQ_PRI,
Expand Down Expand Up @@ -269,105 +256,10 @@ int usb_dc_set_address(const u8_t addr)
return 0;
}

static int usb_dc_ep_transfer(const u8_t ep, u8_t *buf, size_t dlen, bool is_in,
usb_dc_transfer_callback cb)
int usb_dc_ep_start_read(u8_t ep, u8_t *data, u32_t max_data_len)
{
struct usb_dc_stm32_ep_state *ep_state = usb_dc_stm32_get_ep_state(ep);
HAL_StatusTypeDef status;
int ret = 0;

SYS_LOG_DBG("ep 0x%02x, len=%d, in=%d, sync=%s", ep, dlen, is_in,
cb ? "no" : "yes");

if (!dlen && !is_in) {
HAL_PCD_EP_Receive(&usb_dc_stm32_state.pcd, ep, NULL, 0);
return 0;
}

/* Transfer Already Ongoing ? */
if (k_sem_take(&ep_state->transfer_sem, K_NO_WAIT)) {
return -EBUSY;
}

ep_state->transfer_buf = buf;
ep_state->transfer_result = -EBUSY;
ep_state->transfer_size = dlen;
ep_state->transfer_cb = cb;

if (!k_is_in_isr()) {
irq_disable(CONFIG_USB_IRQ);
}

/* Configure and start transfer */
if (is_in) { /* DEV to HOST */
status = HAL_PCD_EP_Transmit(&usb_dc_stm32_state.pcd, ep,
ep_state->transfer_buf, dlen);
} else { /* HOST TO DEV */
status = HAL_PCD_EP_Receive(&usb_dc_stm32_state.pcd, ep,
ep_state->transfer_buf, dlen);
}

if (status != HAL_OK) {
SYS_LOG_ERR("ep 0x%02x, transfer error %d", ep, ret);
ep_state->transfer_buf = NULL;
ret = -EIO;
}

if (!k_is_in_isr()) {
irq_enable(CONFIG_USB_IRQ);
}

if (ep_state->transfer_cb || ret) { /* asynchronous transfer or error */
return ret;
}

/* Synchronous transfer */
if (k_sem_take(&ep_state->transfer_sem, K_FOREVER)) {
SYS_LOG_ERR("ep 0x%02x, transfer error", ep);
ep_state->transfer_buf = NULL;
return -ETIMEDOUT;
}

if (ep_state->transfer_result) { /* error < 0 */
ret = ep_state->transfer_result;
} else { /* synchronous transfer success, return processed bytes */
ret = ep_state->transfer_size;
}

k_sem_give(&ep_state->transfer_sem);

return ret;
}

static void __legacy_out_cb(u8_t ep, int status, size_t tsize)
{
struct usb_dc_stm32_ep_state *ep_state = usb_dc_stm32_get_ep_state(ep);

ARG_UNUSED(status);

/* Transfer completed, data is stored in our legacy endpoint buffer */
ep_state->read_count = tsize;
ep_state->read_offset = 0;

if (ep_state->cb) {
ep_state->cb(ep, USB_DC_EP_DATA_OUT);
}
}

static void __legacy_in_cb(u8_t ep, int status, size_t tsize)
{
struct usb_dc_stm32_ep_state *ep_state = usb_dc_stm32_get_ep_state(ep);

ARG_UNUSED(status);
ARG_UNUSED(tsize);

if (ep_state->cb) {
ep_state->cb(ep, USB_DC_EP_DATA_IN);
}
}

int usb_dc_ep_start_read(u8_t ep, u8_t *data, u32_t max_data_len)
{
SYS_LOG_DBG("ep 0x%02x, len %u", ep, max_data_len);

/* we flush EP0_IN by doing a 0 length receive on it */
Expand All @@ -380,9 +272,16 @@ int usb_dc_ep_start_read(u8_t ep, u8_t *data, u32_t max_data_len)
max_data_len = USB_OTG_FS_MAX_PACKET_SIZE;
}

/* asynchronous out transfer to keep legacy behaviour */
return usb_dc_ep_transfer(ep, data, max_data_len, false,
__legacy_out_cb);
status = HAL_PCD_EP_Receive(&usb_dc_stm32_state.pcd, ep,
usb_dc_stm32_state.ep_buf[EP_IDX(ep)],
max_data_len);
if (status != HAL_OK) {
SYS_LOG_ERR("HAL_PCD_EP_Receive failed(0x%02x), %d",
ep, (int)status);
return -EIO;
}

return 0;
}

int usb_dc_ep_get_read_count(u8_t ep, u32_t *read_bytes)
Expand Down Expand Up @@ -554,6 +453,8 @@ int usb_dc_ep_disable(const u8_t ep)
int usb_dc_ep_write(const u8_t ep, const u8_t *const data,
const u32_t data_len, u32_t * const ret_bytes)
{
struct usb_dc_stm32_ep_state *ep_state = usb_dc_stm32_get_ep_state(ep);
HAL_StatusTypeDef status;
int ret = 0;

SYS_LOG_DBG("ep 0x%02x, len %u", ep, data_len);
Expand All @@ -563,14 +464,24 @@ int usb_dc_ep_write(const u8_t ep, const u8_t *const data,
return -EINVAL;
}

do {
/* For now we want to preserve legacy ep_write behavior.
* If ep transfer fails due to ongoing transfer, try again.
*/
ret = usb_dc_ep_transfer(ep, (u8_t *)data, data_len, true,
__legacy_in_cb);
k_yield();
} while (ret == -EBUSY);
ret = k_sem_take(&ep_state->write_sem, 1000);
if (ret) {
SYS_LOG_ERR("Unable to write ep 0x%02x (%d)", ep, ret);
return ret;
}

if (!k_is_in_isr()) {
irq_disable(STM32F4_IRQ_OTG_FS);
}

status = HAL_PCD_EP_Transmit(&usb_dc_stm32_state.pcd, ep,
(void *)data, data_len);
if (status != HAL_OK) {
SYS_LOG_ERR("HAL_PCD_EP_Transmit failed(0x%02x), %d",
ep, (int)status);
k_sem_give(&ep_state->write_sem);
ret = -EIO;
}

if (!ret && ep == EP0_IN) {
/* Wait for an empty package as from the host.
Expand All @@ -579,6 +490,10 @@ int usb_dc_ep_write(const u8_t ep, const u8_t *const data,
usb_dc_ep_start_read(ep, NULL, 0);
}

if (!k_is_in_isr()) {
irq_enable(STM32F4_IRQ_OTG_FS);
}

if (ret_bytes) {
*ret_bytes = data_len;
}
Expand Down Expand Up @@ -655,6 +570,14 @@ int usb_dc_ep_read(const u8_t ep, u8_t *const data, const u32_t max_data_len,
return 0;
}


int usb_dc_ep_mps(const u8_t ep)
{
struct usb_dc_stm32_ep_state *ep_state = usb_dc_stm32_get_ep_state(ep);

return ep_state->ep_mps;
}

/* Callbacks from the STM32 Cube HAL code */

void HAL_PCD_ResetCallback(PCD_HandleTypeDef *hpcd)
Expand Down Expand Up @@ -737,17 +660,14 @@ void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, u8_t epnum)
SYS_LOG_DBG("epnum 0x%02x, rx_count %u", epnum,
HAL_PCD_EP_GetRxCount(&usb_dc_stm32_state.pcd, epnum));

if (!ep_state->transfer_buf) { /* ignore if no transfer buffer */
return;
}

ep_state->transfer_buf = NULL;
ep_state->transfer_result = 0;
usb_dc_ep_get_read_count(ep, &ep_state->transfer_size);
k_sem_give(&ep_state->transfer_sem);
/* Transaction complete, data is now stored in the buffer and ready
* for the upper stack (usb_dc_ep_read to retrieve).
*/
usb_dc_ep_get_read_count(ep, &ep_state->read_count);
ep_state->read_offset = 0;

if (ep_state->transfer_cb) {
ep_state->transfer_cb(ep, 0, ep_state->transfer_size);
if (ep_state->cb) {
ep_state->cb(ep, USB_DC_EP_DATA_OUT);
}
}

Expand All @@ -759,15 +679,9 @@ void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, u8_t epnum)

SYS_LOG_DBG("epnum 0x%02x", epnum);

if (!ep_state->transfer_buf) { /* ignore if no transfer buffer */
return;
}

ep_state->transfer_buf = NULL;
ep_state->transfer_result = 0;
k_sem_give(&ep_state->transfer_sem);
k_sem_give(&ep_state->write_sem);

if (ep_state->transfer_cb) {
ep_state->transfer_cb(ep, 0, ep_state->transfer_size);
if (ep_state->cb) {
ep_state->cb(ep, USB_DC_EP_DATA_IN);
}
}
11 changes: 11 additions & 0 deletions include/drivers/usb/usb_dc.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ enum usb_dc_status_code {
USB_DC_DISCONNECTED, /* USB connection lost */
USB_DC_SUSPEND, /* USB connection suspended by the HOST */
USB_DC_RESUME, /* USB connection resumed by the HOST */
USB_DC_INTERFACE, /* USB interface selected */
USB_DC_UNKNOWN /* Initial USB connection status */
};

Expand Down Expand Up @@ -326,4 +327,14 @@ int usb_dc_ep_read_wait(u8_t ep, u8_t *data, u32_t max_data_len,
*/
int usb_dc_ep_read_continue(u8_t ep);

/**
* @brief Get endpoint max packet size
*
* @param[in] ep Endpoint address corresponding to the one
* listed in the device configuration table
*
* @return enpoint max packet size (mps)
*/
int usb_dc_ep_mps(u8_t ep);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is misleading since wMaxPacketSize is not always equal to buffer or fifo size of a endpoint. Can we rename it to max buffer size, usb_dc_ep_mbs?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really need the Max Packet Size here, in order to know how the transfer will be split, what is the size of a short packet, is Zero lenght Packet requested, etc...


#endif /* __USB_DC_H__ */
Loading