Skip to content

Commit cff23d4

Browse files
committed
applications: nrf_desktop: Add USB HID next APIs
Change adds USB HID next APIs to the application. Jira: NCSDK-27014 Signed-off-by: Marek Pieta <Marek.Pieta@nordicsemi.no>
1 parent 31ccd03 commit cff23d4

File tree

2 files changed

+166
-17
lines changed

2 files changed

+166
-17
lines changed

applications/nrf_desktop/src/modules/Kconfig.usb_state

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,7 @@ config DESKTOP_USB_STACK_NEXT
5656
select EXPERIMENTAL
5757
select USB_DEVICE_STACK_NEXT
5858
help
59-
Use experimental integration of USB next stack. The USB next API is
60-
not yet integrated by the module's implementation. The option only
61-
disables the legacy USB stack and builds with the USB next stack.
59+
Use experimental integration of USB next stack.
6260

6361
config DESKTOP_USB_STACK_LEGACY
6462
bool "USB legacy stack"
@@ -143,6 +141,12 @@ endif # DESKTOP_USB_STACK_LEGACY
143141

144142
if DESKTOP_USB_STACK_NEXT
145143

144+
config USBD_HID_IN_BUF_COUNT
145+
default 1
146+
help
147+
nRF Desktop queues HID reports at the source. There is no need to use
148+
multiple buffers in the IN pool per HID instance.
149+
146150
choice USBD_LOG_LEVEL_CHOICE
147151
default USBD_LOG_LEVEL_WRN
148152
help

applications/nrf_desktop/src/modules/usb_state.c

Lines changed: 159 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <zephyr/usb/usb_device.h>
1919
#include <zephyr/usb/usb_ch9.h>
2020
#include <zephyr/usb/class/usb_hid.h>
21+
#include <zephyr/usb/class/usbd_hid.h>
2122

2223
#define MODULE usb_state
2324
#include <caf/events/module_state_event.h>
@@ -58,6 +59,7 @@ struct usb_hid_device {
5859
uint32_t report_bm;
5960
uint8_t hid_protocol;
6061
uint8_t sent_report_id;
62+
uint32_t idle_duration[REPORT_ID_COUNT];
6163
bool report_enabled[REPORT_ID_COUNT];
6264
bool enabled;
6365
};
@@ -70,7 +72,16 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_DESKTOP_USB_STACK_NEXT) ||
7072
"Unsupported USB stack");
7173

7274
#if CONFIG_DESKTOP_USB_STACK_NEXT
73-
static struct usb_hid_device usb_hid_device[0];
75+
#define USB_NEXT_USB_HID_DEVICE_INIT(node_id) \
76+
{ \
77+
.dev = DEVICE_DT_GET(node_id), \
78+
.hid_protocol = HID_PROTOCOL_REPORT, \
79+
.sent_report_id = REPORT_ID_COUNT, \
80+
},
81+
82+
static struct usb_hid_device usb_hid_device[] = {
83+
DT_FOREACH_STATUS_OKAY(zephyr_hid_device, USB_NEXT_USB_HID_DEVICE_INIT)
84+
};
7485
#else
7586
static struct usb_hid_device usb_hid_device[CONFIG_USB_HID_DEVICE_COUNT];
7687
#endif
@@ -220,11 +231,6 @@ static void report_sent(const struct device *dev, bool error)
220231
usb_hid->sent_report_id = REPORT_ID_COUNT;
221232
}
222233

223-
static void report_sent_cb(const struct device *dev)
224-
{
225-
report_sent(dev, false);
226-
}
227-
228234
static void send_hid_report(const struct hid_report_event *event)
229235
{
230236
struct usb_hid_device *usb_hid = NULL;
@@ -288,7 +294,15 @@ static void send_hid_report(const struct hid_report_event *event)
288294
int err = 0;
289295

290296
if (IS_ENABLED(CONFIG_DESKTOP_USB_STACK_NEXT)) {
291-
LOG_WRN("send_hid_report not integrated for USB next");
297+
/* USB next stack expects buffer alignment. */
298+
if (IS_ALIGNED(report_buffer, sizeof(void *))) {
299+
err = hid_device_submit_report(usb_hid->dev, report_size, report_buffer);
300+
} else {
301+
uint8_t temp[report_size] __aligned(sizeof(void *));
302+
303+
memcpy(temp, report_buffer, report_size);
304+
err = hid_device_submit_report(usb_hid->dev, report_size, temp);
305+
}
292306
} else {
293307
__ASSERT_NO_MSG(IS_ENABLED(CONFIG_DESKTOP_USB_STACK_LEGACY));
294308
err = hid_int_ep_write(usb_hid->dev, report_buffer, report_size, NULL);
@@ -300,11 +314,11 @@ static void send_hid_report(const struct hid_report_event *event)
300314
}
301315
}
302316

303-
static void broadcast_usb_state(void)
317+
static void broadcast_usb_state(enum usb_state broadcast_state)
304318
{
305319
struct usb_state_event *event = new_usb_state_event();
306320

307-
event->state = state;
321+
event->state = broadcast_state;
308322

309323
APP_EVENT_SUBMIT(event);
310324
}
@@ -633,14 +647,19 @@ static int set_report_legacy(const struct device *dev, struct usb_setup_packet *
633647
return err;
634648
}
635649

650+
static void report_sent_cb_legacy(const struct device *dev)
651+
{
652+
report_sent(dev, false);
653+
}
654+
636655
static int usb_init_legacy_hid_device_init(struct usb_hid_device *usb_hid_dev,
637656
const struct device *dev,
638657
uint32_t report_bm)
639658
{
640659
static const struct hid_ops hid_ops = {
641660
.get_report = get_report_legacy,
642661
.set_report = set_report_legacy,
643-
.int_in_ready = report_sent_cb,
662+
.int_in_ready = report_sent_cb_legacy,
644663
.protocol_change = protocol_change,
645664
};
646665

@@ -754,7 +773,7 @@ static void usb_init_legacy_status_cb(enum usb_dc_status_code cb_status, const u
754773

755774
/* Update state. */
756775
state = new_state;
757-
broadcast_usb_state();
776+
broadcast_usb_state(state);
758777

759778
/* HID subscribe when entering active state. */
760779
if (state == USB_STATE_ACTIVE) {
@@ -811,6 +830,122 @@ static int usb_init_legacy(void)
811830
return 0;
812831
}
813832

833+
static bool is_usb_active_next(void)
834+
{
835+
bool usb_active = false;
836+
837+
for (size_t i = 0; i < ARRAY_SIZE(usb_hid_device); i++) {
838+
if (usb_hid_device[i].enabled) {
839+
usb_active = true;
840+
break;
841+
}
842+
}
843+
844+
return usb_active;
845+
}
846+
847+
static void iface_ready_next(const struct device *dev, const bool ready)
848+
{
849+
struct usb_hid_device *usb_hid = dev_to_hid(dev);
850+
bool was_usb_active = is_usb_active_next();
851+
852+
update_usb_hid(usb_hid, ready);
853+
854+
bool is_usb_active = is_usb_active_next();
855+
856+
if (state == USB_STATE_SUSPENDED) {
857+
/* USB state update is delayed if USB is suspended. */
858+
return;
859+
}
860+
861+
if (!was_usb_active && is_usb_active) {
862+
broadcast_usb_state(USB_STATE_ACTIVE);
863+
} else if (was_usb_active && !is_usb_active) {
864+
broadcast_usb_state(state);
865+
}
866+
}
867+
868+
static int get_report_next(const struct device *dev, const uint8_t type, const uint8_t id,
869+
const uint16_t len, uint8_t *const buf)
870+
{
871+
/* Omit the first byte - HID report ID. */
872+
buf[0] = id;
873+
return get_report(dev, type, id, buf + 1, len - 1);
874+
}
875+
876+
static int set_report_next(const struct device *dev, const uint8_t type, const uint8_t id,
877+
const uint16_t len, const uint8_t *const buf)
878+
{
879+
/* Omit the first byte - HID report ID. */
880+
return set_report(dev, type, id, buf + 1, len - 1);
881+
}
882+
883+
static void set_idle_next(const struct device *dev, const uint8_t id, const uint32_t duration)
884+
{
885+
struct usb_hid_device *usb_hid = dev_to_hid(dev);
886+
887+
usb_hid->idle_duration[id] = duration;
888+
}
889+
890+
static uint32_t get_idle_next(const struct device *dev, const uint8_t id)
891+
{
892+
struct usb_hid_device *usb_hid = dev_to_hid(dev);
893+
894+
return usb_hid->idle_duration[id];
895+
}
896+
897+
static void report_sent_cb_next(const struct device *dev)
898+
{
899+
struct usb_hid_device *usb_hid = dev_to_hid(dev);
900+
901+
/* USB next stack does not explicitly indicate failed transfers. */
902+
if (usb_hid->enabled) {
903+
report_sent(dev, false);
904+
} else {
905+
report_sent(dev, true);
906+
}
907+
}
908+
909+
static int usb_init_next_hid_device_init(struct usb_hid_device *usb_hid_dev, uint32_t report_bm)
910+
{
911+
static const struct hid_device_ops hid_ops = {
912+
.iface_ready = iface_ready_next,
913+
.get_report = get_report_next,
914+
.set_report = set_report_next,
915+
.set_idle = set_idle_next,
916+
.get_idle = get_idle_next,
917+
.set_protocol = protocol_change,
918+
.input_report_done = report_sent_cb_next,
919+
};
920+
921+
usb_hid_dev->report_bm = report_bm;
922+
923+
int err = hid_device_register(usb_hid_dev->dev, hid_report_desc, hid_report_desc_size,
924+
&hid_ops);
925+
926+
if (err) {
927+
LOG_ERR("hid_device_register failed for %p (err: %d)",
928+
(void *)usb_hid_dev->dev, err);
929+
}
930+
931+
return err;
932+
}
933+
934+
static int usb_init_next_hids_init(void)
935+
{
936+
int err = 0;
937+
938+
for (size_t i = 0; i < ARRAY_SIZE(usb_hid_device); i++) {
939+
err = usb_init_next_hid_device_init(&usb_hid_device[i], get_report_bm(i));
940+
if (err) {
941+
LOG_ERR("usb_init_next_hid_device_init failed (err: %d)", err);
942+
break;
943+
}
944+
}
945+
946+
return err;
947+
}
948+
814949
static void usb_init_next_status_cb(struct usbd_contex *const contex,
815950
const struct usbd_msg *const msg)
816951
{
@@ -871,7 +1006,11 @@ static void usb_init_next_status_cb(struct usbd_contex *const contex,
8711006
}
8721007

8731008
if (new_state != state) {
874-
broadcast_usb_state(new_state);
1009+
if ((state == USB_STATE_SUSPENDED) && is_usb_active_next()) {
1010+
broadcast_usb_state(USB_STATE_ACTIVE);
1011+
} else {
1012+
broadcast_usb_state(new_state);
1013+
}
8751014
state = new_state;
8761015
}
8771016
}
@@ -1016,15 +1155,21 @@ static struct usbd_contex *usb_init_next_usbd_init(void)
10161155

10171156
static int usb_init_next(void)
10181157
{
1158+
int err = usb_init_next_hids_init();
1159+
1160+
if (err) {
1161+
LOG_ERR("usb_init_next_hids_init failed (err: %d)", err);
1162+
return err;
1163+
}
1164+
10191165
struct usbd_contex *usbd = usb_init_next_usbd_init();
10201166

10211167
if (!usbd) {
10221168
LOG_ERR("usb_init_next_usbd_init failed");
10231169
return -ENXIO;
10241170
}
10251171

1026-
int err = usbd_msg_register_cb(usbd, usb_init_next_status_cb);
1027-
1172+
err = usbd_msg_register_cb(usbd, usb_init_next_status_cb);
10281173
if (err) {
10291174
LOG_ERR("usbd_msg_register_cb failed (err: %d)", err);
10301175
return err;

0 commit comments

Comments
 (0)