Skip to content

Commit

Permalink
usb: device: gs_usb: convert dummy endpoint to fully functional OUT ep
Browse files Browse the repository at this point in the history
Convert the dummy endpoint to a fully functional bulk OUT endpoint in order
to be compatible with gs_usb drivers selecting the first available IN/OUT
endpoints for use.

Signed-off-by: Henrik Brix Andersen <[email protected]>
  • Loading branch information
henrikbrixandersen committed Dec 29, 2024
1 parent d7434f0 commit 0cc807e
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 58 deletions.
11 changes: 4 additions & 7 deletions include/cannectivity/usb/class/gs_usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -458,18 +458,15 @@ struct gs_usb_host_frame_hdr {
/**
* @name USB endpoint addresses
*
* Existing drivers expect endpoints 0x81 and 0x02. Include a dummy endpoint 0x01 to work-around the
* endpoint address fixup of the Zephyr USB device stack.
*
* @{
*/

/** USB bulk IN endpoint address */
#define GS_USB_IN_EP_ADDR 0x81
/** USB (dummy) bulk OUT endpoint address */
#define GS_USB_DUMMY_EP_ADDR 0x01
/** USB bulk OUT endpoint address */
#define GS_USB_OUT_EP_ADDR 0x02
/** USB bulk OUT1 endpoint address */
#define GS_USB_OUT1_EP_ADDR 0x01
/** USB bulk OUT2 endpoint address */
#define GS_USB_OUT2_EP_ADDR 0x02

/** @} */

Expand Down
55 changes: 35 additions & 20 deletions subsys/usb/device/class/gs_usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ LOG_MODULE_REGISTER(gs_usb, CONFIG_USB_DEVICE_GS_USB_LOG_LEVEL);

/* USB endpoint indexes */
#define GS_USB_IN_EP_IDX 0U
#define GS_USB_DUMMY_EP_IDX 1U
#define GS_USB_OUT_EP_IDX 2U
#define GS_USB_OUT1_EP_IDX 1U
#define GS_USB_OUT2_EP_IDX 2U

struct gs_usb_config {
struct usb_association_descriptor iad;
struct usb_if_descriptor if0;
struct usb_ep_descriptor if0_in_ep;
struct usb_ep_descriptor if0_dummy_ep;
struct usb_ep_descriptor if0_out_ep;
struct usb_ep_descriptor if0_out1_ep;
struct usb_ep_descriptor if0_out2_ep;
} __packed;

struct gs_usb_channel_data {
Expand Down Expand Up @@ -61,7 +61,8 @@ struct gs_usb_data {
struct k_fifo rx_fifo;
struct k_thread rx_thread;

uint8_t tx_buffer[GS_USB_HOST_FRAME_MAX_SIZE];
uint8_t tx_buffer1[GS_USB_HOST_FRAME_MAX_SIZE];
uint8_t tx_buffer2[GS_USB_HOST_FRAME_MAX_SIZE];
struct k_fifo tx_fifo;
struct k_thread tx_thread;

Expand All @@ -72,7 +73,7 @@ struct gs_usb_data {
static sys_slist_t gs_usb_data_devlist;
static gs_usb_vendorcode_callback_t vendorcode_callback;

static void gs_usb_transfer_tx_prepare(const struct device *dev);
static void gs_usb_transfer_tx_prepare(const struct device *dev, uint8_t ep);
static int gs_usb_reset_channel(const struct device *dev, uint16_t ch);

static int gs_usb_request_host_format(int32_t tlen, const uint8_t *tdata)
Expand Down Expand Up @@ -1046,6 +1047,7 @@ static void gs_usb_can_tx_callback(const struct device *can_dev, int error, void
static void gs_usb_transfer_tx_callback(uint8_t ep, int tsize, void *priv)
{
const struct device *dev = priv;
struct usb_cfg_data *cfg = (void *)dev->config;
struct gs_usb_data *data = dev->data;
struct net_buf *buf;

Expand All @@ -1056,21 +1058,32 @@ static void gs_usb_transfer_tx_callback(uint8_t ep, int tsize, void *priv)
return;
}

net_buf_add_mem(buf, data->tx_buffer, tsize);
if (ep == cfg->endpoint[GS_USB_OUT1_EP_IDX].ep_addr) {
net_buf_add_mem(buf, data->tx_buffer1, tsize);
} else {
net_buf_add_mem(buf, data->tx_buffer2, tsize);
}

k_fifo_put(&data->tx_fifo, buf);
}

gs_usb_transfer_tx_prepare(dev);
gs_usb_transfer_tx_prepare(dev, ep);
}

static void gs_usb_transfer_tx_prepare(const struct device *dev)
static void gs_usb_transfer_tx_prepare(const struct device *dev, uint8_t ep)
{
struct usb_cfg_data *cfg = (void *)dev->config;
struct gs_usb_data *data = dev->data;

usb_transfer(cfg->endpoint[GS_USB_OUT_EP_IDX].ep_addr, data->tx_buffer,
sizeof(data->tx_buffer), USB_TRANS_READ, gs_usb_transfer_tx_callback,
(void *)dev);
if (ep == cfg->endpoint[GS_USB_OUT1_EP_IDX].ep_addr) {
usb_transfer(cfg->endpoint[GS_USB_OUT1_EP_IDX].ep_addr, data->tx_buffer1,
sizeof(data->tx_buffer1), USB_TRANS_READ, gs_usb_transfer_tx_callback,
(void *)dev);
} else {
usb_transfer(cfg->endpoint[GS_USB_OUT2_EP_IDX].ep_addr, data->tx_buffer2,
sizeof(data->tx_buffer2), USB_TRANS_READ, gs_usb_transfer_tx_callback,
(void *)dev);
}
}

static void gs_usb_tx_thread(void *p1, void *p2, void *p3)
Expand Down Expand Up @@ -1354,9 +1367,10 @@ static void gs_usb_status_callback(struct usb_cfg_data *cfg, enum usb_dc_status_
case USB_DC_CONFIGURED:
LOG_DBG("USB device configured");
LOG_DBG("EP IN addr = 0x%02x", cfg->endpoint[GS_USB_IN_EP_IDX].ep_addr);
LOG_DBG("EP DUMMY addr = 0x%02x", cfg->endpoint[GS_USB_DUMMY_EP_IDX].ep_addr);
LOG_DBG("EP OUT addr = 0x%02x", cfg->endpoint[GS_USB_OUT_EP_IDX].ep_addr);
gs_usb_transfer_tx_prepare(common->dev);
LOG_DBG("EP OUT1 addr = 0x%02x", cfg->endpoint[GS_USB_OUT1_EP_IDX].ep_addr);
LOG_DBG("EP OUT2 addr = 0x%02x", cfg->endpoint[GS_USB_OUT2_EP_IDX].ep_addr);
gs_usb_transfer_tx_prepare(common->dev, cfg->endpoint[GS_USB_OUT1_EP_IDX].ep_addr);
gs_usb_transfer_tx_prepare(common->dev, cfg->endpoint[GS_USB_OUT2_EP_IDX].ep_addr);
break;
case USB_DC_DISCONNECTED:
LOG_DBG("USB device disconnected");
Expand All @@ -1365,7 +1379,8 @@ static void gs_usb_status_callback(struct usb_cfg_data *cfg, enum usb_dc_status_
}

usb_cancel_transfer(cfg->endpoint[GS_USB_IN_EP_IDX].ep_addr);
usb_cancel_transfer(cfg->endpoint[GS_USB_OUT_EP_IDX].ep_addr);
usb_cancel_transfer(cfg->endpoint[GS_USB_OUT1_EP_IDX].ep_addr);
usb_cancel_transfer(cfg->endpoint[GS_USB_OUT2_EP_IDX].ep_addr);
break;
case USB_DC_SUSPEND:
LOG_DBG("USB device suspend");
Expand Down Expand Up @@ -1486,8 +1501,8 @@ static int gs_usb_init(const struct device *dev)
.iad = INITIALIZER_IAD, \
.if0 = INITIALIZER_IF, \
.if0_in_ep = INITIALIZER_IF_EP(GS_USB_IN_EP_ADDR), \
.if0_dummy_ep = INITIALIZER_IF_EP(GS_USB_DUMMY_EP_ADDR), \
.if0_out_ep = INITIALIZER_IF_EP(GS_USB_OUT_EP_ADDR), \
.if0_out1_ep = INITIALIZER_IF_EP(GS_USB_OUT1_EP_ADDR), \
.if0_out2_ep = INITIALIZER_IF_EP(GS_USB_OUT2_EP_ADDR), \
}; \
\
static struct usb_ep_cfg_data gs_usb_ep_cfg_data_##inst[] = { \
Expand All @@ -1497,11 +1512,11 @@ static int gs_usb_init(const struct device *dev)
}, \
{ \
.ep_cb = usb_transfer_ep_callback, \
.ep_addr = GS_USB_DUMMY_EP_ADDR, \
.ep_addr = GS_USB_OUT1_EP_ADDR, \
}, \
{ \
.ep_cb = usb_transfer_ep_callback, \
.ep_addr = GS_USB_OUT_EP_ADDR, \
.ep_addr = GS_USB_OUT2_EP_ADDR, \
}, \
}; \
\
Expand Down
90 changes: 59 additions & 31 deletions subsys/usb/device_next/class/gs_usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ struct gs_usb_desc {
struct usb_association_descriptor iad;
struct usb_if_descriptor if0;
struct usb_ep_descriptor if0_in_ep;
struct usb_ep_descriptor if0_dummy_ep;
struct usb_ep_descriptor if0_out_ep;
struct usb_ep_descriptor if0_out1_ep;
struct usb_ep_descriptor if0_out2_ep;
struct usb_ep_descriptor if0_hs_in_ep;
struct usb_ep_descriptor if0_hs_dummy_ep;
struct usb_ep_descriptor if0_hs_out_ep;
struct usb_ep_descriptor if0_hs_out1_ep;
struct usb_ep_descriptor if0_hs_out2_ep;
struct usb_desc_header nil_desc;
};

Expand Down Expand Up @@ -809,18 +809,32 @@ static uint8_t gs_usb_get_bulk_in_ep_addr(struct usbd_class_data *const c_data)
return desc->if0_in_ep.bEndpointAddress;
}

static uint8_t gs_usb_get_bulk_out_ep_addr(struct usbd_class_data *const c_data)
static uint8_t gs_usb_get_bulk_out1_ep_addr(struct usbd_class_data *const c_data)
{
const struct device *dev = usbd_class_get_private(c_data);
const struct gs_usb_config *config = dev->config;
struct usbd_context *uds_ctx = usbd_class_get_ctx(c_data);
struct gs_usb_desc *desc = config->desc;

if (usbd_bus_speed(uds_ctx) == USBD_SPEED_HS) {
return desc->if0_hs_out_ep.bEndpointAddress;
return desc->if0_hs_out1_ep.bEndpointAddress;
}

return desc->if0_out_ep.bEndpointAddress;
return desc->if0_out1_ep.bEndpointAddress;
}

static uint8_t gs_usb_get_bulk_out2_ep_addr(struct usbd_class_data *const c_data)
{
const struct device *dev = usbd_class_get_private(c_data);
const struct gs_usb_config *config = dev->config;
struct usbd_context *uds_ctx = usbd_class_get_ctx(c_data);
struct gs_usb_desc *desc = config->desc;

if (usbd_bus_speed(uds_ctx) == USBD_SPEED_HS) {
return desc->if0_hs_out2_ep.bEndpointAddress;
}

return desc->if0_out2_ep.bEndpointAddress;
}

static struct net_buf *gs_usb_buf_alloc(const struct gs_usb_config *config, uint8_t ep)
Expand Down Expand Up @@ -859,30 +873,28 @@ static void gs_usb_fill_echo_frame_hdr(struct net_buf *buf, uint32_t echo_id, ui
bi->ep = ep;
}

static int gs_usb_out_start(struct usbd_class_data *const c_data)
static int gs_usb_out_start(struct usbd_class_data *const c_data, uint8_t ep)
{
const struct device *dev = usbd_class_get_private(c_data);
const struct gs_usb_config *config = dev->config;
struct gs_usb_data *data = dev->data;
struct net_buf *buf;
uint8_t ep;
int ret;

if (!atomic_test_bit(&data->state, GS_USB_STATE_CLASS_ENABLED)) {
LOG_ERR("cannot start OUT transfer, class instance not enabled");
return -EPERM;
}

ep = gs_usb_get_bulk_out_ep_addr(c_data);
buf = gs_usb_buf_alloc(config, ep);
if (buf == NULL) {
LOG_ERR("failed to allocate buffer for ep 0x%02x", ep);
LOG_ERR("failed to allocate buffer for OUT ep 0x%02x", ep);
return -ENOMEM;
}

ret = usbd_ep_enqueue(c_data, buf);
if (ret != 0) {
LOG_ERR("failed to enqueue buffer for ep 0x%02x (err %d)", ep, ret);
LOG_ERR("failed to enqueue buffer for OUT ep 0x%02x (err %d)", ep, ret);
net_buf_unref(buf);
}

Expand Down Expand Up @@ -1273,7 +1285,8 @@ static int gs_usb_request(struct usbd_class_data *const c_data, struct net_buf *

LOG_DBG("request complete for ep 0x%02x (err %d)", bi->ep, err);

if (bi->ep == gs_usb_get_bulk_out_ep_addr(c_data)) {
if (bi->ep == gs_usb_get_bulk_out1_ep_addr(c_data) ||
bi->ep == gs_usb_get_bulk_out2_ep_addr(c_data)) {
if (!atomic_test_bit(&data->state, GS_USB_STATE_CLASS_ENABLED)) {
LOG_WRN("class not enabled");
net_buf_unref(buf);
Expand All @@ -1282,9 +1295,10 @@ static int gs_usb_request(struct usbd_class_data *const c_data, struct net_buf *

k_fifo_put(&data->tx_fifo, buf);

ret = gs_usb_out_start(c_data);
ret = gs_usb_out_start(c_data, bi->ep);
if (ret != 0) {
LOG_ERR("failed to restart OUT transfer (err %d)", ret);
LOG_ERR("failed to restart OUT transfer for ep 0x%02x (err %d)", bi->ep,
ret);
}

return ret;
Expand All @@ -1302,14 +1316,22 @@ static void gs_usb_enable(struct usbd_class_data *const c_data)
{
const struct device *dev = usbd_class_get_private(c_data);
struct gs_usb_data *data = dev->data;
uint8_t ep;
int err;

atomic_set_bit(&data->state, GS_USB_STATE_CLASS_ENABLED);
LOG_DBG("enabled");

err = gs_usb_out_start(c_data);
ep = gs_usb_get_bulk_out1_ep_addr(c_data);
err = gs_usb_out_start(c_data, ep);
if (err != 0) {
LOG_ERR("failed to start OUT transfer for ep 0x%02x (err %d)", ep, err);
}

ep = gs_usb_get_bulk_out2_ep_addr(c_data);
err = gs_usb_out_start(c_data, ep);
if (err != 0) {
LOG_ERR("failed to start OUT transfer (err %d)", err);
LOG_ERR("failed to start OUT transfer for ep 0x%02x (err %d)", ep, err);
}
}

Expand All @@ -1334,7 +1356,13 @@ static void gs_usb_disable(struct usbd_class_data *const c_data)
LOG_ERR("failed to dequeue IN ep 0x%02x (err %d)", ep, err);
}

ep = gs_usb_get_bulk_out_ep_addr(c_data);
ep = gs_usb_get_bulk_out1_ep_addr(c_data);
err = usbd_ep_dequeue(uds_ctx, ep);
if (err != 0) {
LOG_ERR("failed to dequeue OUT ep 0x%02x (err %d)", ep, err);
}

ep = gs_usb_get_bulk_out2_ep_addr(c_data);
err = usbd_ep_dequeue(uds_ctx, ep);
if (err != 0) {
LOG_ERR("failed to dequeue OUT ep 0x%02x (err %d)", ep, err);
Expand Down Expand Up @@ -1616,18 +1644,18 @@ struct usbd_class_api gs_usb_api = {
.wMaxPacketSize = sys_cpu_to_le16(64), \
.bInterval = 0x00, \
}, \
.if0_dummy_ep = { \
.if0_out1_ep = { \
.bLength = sizeof(struct usb_ep_descriptor), \
.bDescriptorType = USB_DESC_ENDPOINT, \
.bEndpointAddress = GS_USB_DUMMY_EP_ADDR, \
.bEndpointAddress = GS_USB_OUT1_EP_ADDR, \
.bmAttributes = USB_EP_TYPE_BULK, \
.wMaxPacketSize = sys_cpu_to_le16(64U), \
.bInterval = 0x00, \
}, \
.if0_out_ep = { \
.if0_out2_ep = { \
.bLength = sizeof(struct usb_ep_descriptor), \
.bDescriptorType = USB_DESC_ENDPOINT, \
.bEndpointAddress = GS_USB_OUT_EP_ADDR, \
.bEndpointAddress = GS_USB_OUT2_EP_ADDR, \
.bmAttributes = USB_EP_TYPE_BULK, \
.wMaxPacketSize = sys_cpu_to_le16(64U), \
.bInterval = 0x00, \
Expand All @@ -1640,18 +1668,18 @@ struct usbd_class_api gs_usb_api = {
.wMaxPacketSize = sys_cpu_to_le16(512), \
.bInterval = 0x00, \
}, \
.if0_hs_dummy_ep = { \
.if0_hs_out1_ep = { \
.bLength = sizeof(struct usb_ep_descriptor), \
.bDescriptorType = USB_DESC_ENDPOINT, \
.bEndpointAddress = GS_USB_DUMMY_EP_ADDR, \
.bEndpointAddress = GS_USB_OUT1_EP_ADDR, \
.bmAttributes = USB_EP_TYPE_BULK, \
.wMaxPacketSize = sys_cpu_to_le16(512U), \
.bInterval = 0x00, \
}, \
.if0_hs_out_ep = { \
.if0_hs_out2_ep = { \
.bLength = sizeof(struct usb_ep_descriptor), \
.bDescriptorType = USB_DESC_ENDPOINT, \
.bEndpointAddress = GS_USB_OUT_EP_ADDR, \
.bEndpointAddress = GS_USB_OUT2_EP_ADDR, \
.bmAttributes = USB_EP_TYPE_BULK, \
.wMaxPacketSize = sys_cpu_to_le16(512U), \
.bInterval = 0x00, \
Expand All @@ -1666,17 +1694,17 @@ struct usbd_class_api gs_usb_api = {
(struct usb_desc_header *)&gs_usb_desc_##n.iad, \
(struct usb_desc_header *)&gs_usb_desc_##n.if0, \
(struct usb_desc_header *)&gs_usb_desc_##n.if0_in_ep, \
(struct usb_desc_header *)&gs_usb_desc_##n.if0_dummy_ep, \
(struct usb_desc_header *)&gs_usb_desc_##n.if0_out_ep, \
(struct usb_desc_header *)&gs_usb_desc_##n.if0_out1_ep, \
(struct usb_desc_header *)&gs_usb_desc_##n.if0_out2_ep, \
(struct usb_desc_header *)&gs_usb_desc_##n.nil_desc, \
}; \
\
static const struct usb_desc_header *gs_usb_hs_desc_##n[] = { \
(struct usb_desc_header *)&gs_usb_desc_##n.iad, \
(struct usb_desc_header *)&gs_usb_desc_##n.if0, \
(struct usb_desc_header *)&gs_usb_desc_##n.if0_hs_in_ep, \
(struct usb_desc_header *)&gs_usb_desc_##n.if0_hs_dummy_ep, \
(struct usb_desc_header *)&gs_usb_desc_##n.if0_hs_out_ep, \
(struct usb_desc_header *)&gs_usb_desc_##n.if0_hs_out1_ep, \
(struct usb_desc_header *)&gs_usb_desc_##n.if0_hs_out2_ep, \
(struct usb_desc_header *)&gs_usb_desc_##n.nil_desc, \
}

Expand All @@ -1690,7 +1718,7 @@ struct usbd_class_api gs_usb_api = {
USBD_DEFINE_CLASS(gs_usb_##n, &gs_usb_api, (void *)DEVICE_DT_GET(DT_DRV_INST(n)), \
&gs_usb_vendor_requests); \
\
UDC_BUF_POOL_DEFINE(gs_usb_pool_##n, CONFIG_USBD_GS_USB_POOL_SIZE, \
UDC_BUF_POOL_DEFINE(gs_usb_pool_##n, CONFIG_USBD_GS_USB_POOL_SIZE, /* TODO: +1? */ \
GS_USB_HOST_FRAME_MAX_SIZE, sizeof(struct udc_buf_info), NULL); \
\
static const struct gs_usb_config gs_usb_config_##n = { \
Expand Down

0 comments on commit 0cc807e

Please sign in to comment.