-
Notifications
You must be signed in to change notification settings - Fork 6.9k
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
usb: device_next: support BOS descriptor with vendor request code #76326
usb: device_next: support BOS descriptor with vendor request code #76326
Conversation
Add a function similar to sample_usbd_init_device(), but one that does not initialize the device. It allows the application to set additional features, such as additional descriptors. Signed-off-by: Johann Fischer <johann.fischer@nordicsemi.no>
subsys/usb/device_next/usbd_ch9.c
Outdated
{ | ||
struct usbd_desc_node *desc_nd; | ||
|
||
SYS_DLIST_FOR_EACH_CONTAINER(&uds_ctx->descriptors, desc_nd, node) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why abuse the descriptors list? I think it would be better to just have a separate list for the vendor requests. The vendor requests should not be limited to BOS-only, but generally any vendor (here: application developer) should be able to provide their own vendor commands in application.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why abuse the descriptors list?
It is a descriptor and it does not abusing anything.
I think it would be better to just have a separate list for the vendor requests. The vendor requests should not be limited to BOS-only, but generally any vendor (here: application developer) should be able to provide their own vendor commands in application.
There are no requirements in the specification to allow arbitrary vendor request with recipient device. Using the BOS platform capability is the most portable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How is this a descriptor? This is not descriptor in any way, just a way for application to register vendor commands. USB specification doesn't require the devices to implement any optional functionality (vendor commands are optional functionality). In this context the specification states "A device vendor may also define requests supported by the device.".
What do you mean by "most portable"? What does portability have to do with a stack functionality to allow application developer to support vendor commands?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please familiarize yourself with how MSOS2 and WebUSB use the BOS descriptor, I am pretty sure you will understand it.
struct bos_msosv2_descriptor bos_msosv2_desc = { | ||
/* | ||
* Microsoft OS 2.0 Platform Capability Descriptor, | ||
* see Microsoft OS 2.0 Descriptors Specification | ||
*/ | ||
.platform = { | ||
.bLength = sizeof(struct usb_bos_platform_descriptor) | ||
+ sizeof(struct usb_bos_capability_msos), | ||
.bDescriptorType = USB_DESC_DEVICE_CAPABILITY, | ||
.bDevCapabilityType = USB_BOS_CAPABILITY_PLATFORM, | ||
.bReserved = 0, | ||
/* Microsoft OS 2.0 descriptor platform capability UUID | ||
* D8DD60DF-4589-4CC7-9CD2-659D9E648A9F | ||
*/ | ||
.PlatformCapabilityUUID = { | ||
0xDF, 0x60, 0xDD, 0xD8, | ||
0x89, 0x45, | ||
0xC7, 0x4C, | ||
0x9C, 0xD2, | ||
0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F, | ||
}, | ||
}, | ||
.cap = { | ||
.dwWindowsVersion = sys_cpu_to_le32(SAMPLE_MSOS2_OS_VERSION), | ||
.wMSOSDescriptorSetTotalLength = sys_cpu_to_le16(sizeof(msosv2_desc)), | ||
.bMS_VendorCode = SAMPLE_MSOS2_VENDOR_CODE, | ||
.bAltEnumCode = 0x00 | ||
}, | ||
}; | ||
|
||
static int msosv2_to_host_cb(const struct usbd_context *const ctx, | ||
const struct usb_setup_packet *const setup, | ||
struct net_buf *const buf) | ||
{ | ||
LOG_INF("Vendor callback to host"); | ||
|
||
if (setup->bRequest == SAMPLE_MSOS2_VENDOR_CODE && | ||
setup->wIndex == MS_OS_20_DESCRIPTOR_INDEX) { | ||
LOG_INF("Get MS OS 2.0 Descriptor Set"); | ||
|
||
net_buf_add_mem(buf, &msosv2_desc, | ||
MIN(net_buf_tailroom(buf), sizeof(msosv2_desc))); | ||
|
||
return 0; | ||
} | ||
|
||
return -ENOTSUP; | ||
} | ||
|
||
USBD_DESC_BOS_VREQ_DEFINE(bos_vreq_msosv2, sizeof(bos_msosv2_desc), &bos_msosv2_desc, | ||
SAMPLE_MSOS2_VENDOR_CODE, msosv2_to_host_cb, NULL); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this is defined in a header?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not? Or what is the problem? This is limited to a specific part and can be used as a template.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Everything compilation unit that includes this header will have the variables in the corresponding object file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is only that include it. So where is the problem?
static const struct usb_bos_webusb_desc bos_cap_webusb = { | ||
/* WebUSB Platform Capability Descriptor: | ||
* https://wicg.github.io/webusb/#webusb-platform-capability-descriptor | ||
*/ | ||
.platform = { | ||
.bLength = sizeof(struct usb_bos_platform_descriptor) | ||
+ sizeof(struct usb_bos_capability_webusb), | ||
.bDescriptorType = USB_DESC_DEVICE_CAPABILITY, | ||
.bDevCapabilityType = USB_BOS_CAPABILITY_PLATFORM, | ||
.bReserved = 0, | ||
/* WebUSB Platform Capability UUID | ||
* 3408b638-09a9-47a0-8bfd-a0768815b665 | ||
*/ | ||
.PlatformCapabilityUUID = { | ||
0x38, 0xB6, 0x08, 0x34, | ||
0xA9, 0x09, | ||
0xA0, 0x47, | ||
0x8B, 0xFD, | ||
0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65, | ||
}, | ||
}, | ||
.cap = { | ||
.bcdVersion = sys_cpu_to_le16(0x0100), | ||
.bVendorCode = SAMPLE_WEBUSB_VENDOR_CODE, | ||
.iLandingPage = SAMPLE_WEBUSB_LANDING_PAGE | ||
} | ||
}; | ||
|
||
/* WebUSB URL Descriptor, see https://wicg.github.io/webusb/#webusb-descriptors */ | ||
static const uint8_t webusb_origin_url[] = { | ||
/* bLength, bDescriptorType, bScheme, UTF-8 encoded URL */ | ||
0x11, WEBUSB_DESC_TYPE_URL, WEBUSB_URL_PREFIX_HTTP, | ||
'l', 'o', 'c', 'a', 'l', 'h', 'o', 's', 't', ':', '8', '0', '0', '0' | ||
}; | ||
|
||
static int webusb_to_host_cb(const struct usbd_context *const ctx, | ||
const struct usb_setup_packet *const setup, | ||
struct net_buf *const buf) | ||
{ | ||
LOG_INF("Vendor callback to host"); | ||
|
||
if (setup->wIndex == WEBUSB_REQ_GET_URL) { | ||
uint8_t index = USB_GET_DESCRIPTOR_INDEX(setup->wValue); | ||
|
||
if (index != SAMPLE_WEBUSB_LANDING_PAGE) { | ||
return -ENOTSUP; | ||
} | ||
|
||
LOG_INF("Get URL request, index %u", index); | ||
net_buf_add_mem(buf, &webusb_origin_url, | ||
MIN(net_buf_tailroom(buf), sizeof(webusb_origin_url))); | ||
|
||
return 0; | ||
} | ||
|
||
return -ENOTSUP; | ||
} | ||
|
||
USBD_DESC_BOS_VREQ_DEFINE(bos_vreq_webusb, sizeof(bos_cap_webusb), &bos_cap_webusb, | ||
SAMPLE_WEBUSB_VENDOR_CODE, webusb_to_host_cb, NULL); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this is defined in a header?
'3', 0x00, '9', 0x00, '5', 0x00, '6', 0x00, '2', 0x00, 'B', 0x00, \ | ||
'3', 0x00, '}', 0x00, 0x00, 0x00, 0x00, 0x00 | ||
|
||
struct msosv2_descriptor { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be possible to somehow take the advantage of the new stack to enable automatic struct msosv2_function_subset_header
insertion when there is more than 1 interface?
The old stack did have #66449 as a solution, but that's fragile approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not think we can handle it. IMO it is better to write a comprehensive documentation about it, with some examples. I think the average user has no idea where and how to use MSOSv2 descriptors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comprehensive documentation is not a real solution but a way to avoid having to come up with a real solution. While the average user might not have idea about individual MSOSv2 descriptors, it would be good to provide "just-working" experience (if possible).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer a generic way to register vendor requests targeting the device (not a class nor an interface) from the application code. This could easily be used for handling MSOSv2 vendor requests, but wouldn't be limited to that (not all vendor requests would require a BOS).
5291081
to
6f692c4
Compare
@tmon-nordic @henrikbrixandersen can you please take another look? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new bRequest registration seems fine, just few things to fix.
* @param vto_dev Vendor callback for to-device direction request | ||
*/ | ||
#define USBD_VREQUEST_DEFINE(name, vcode, vto_host, vto_dev) \ | ||
static struct usbd_vreq_node name = { \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer some prefix on the node, e.g.
static struct usbd_vreq_node name = { \ | |
static struct usbd_vreq_node usbd_vreq_node_##name = { \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then the user does not know the real structure name. This makes sense for more abstract macros, but not here.
'3', 0x00, '}', 0x00, 0x00, 0x00, 0x00, 0x00 | ||
|
||
struct msosv2_descriptor { | ||
struct msosv2_descriptor_set_header header; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If not implement it right now, at least add a TODO: Add subset header when there is more than one interface.
See #66449 for more information.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have aligned it with the descriptor in the legacy sample and added a comment.
Allow the user to register a vendor request node identified by the vendor code (bRequest) and containing two callbacks to handle the vendor request. The device stack uses the vendor request node to call the vendor request callbacks when it receives a request of type Vendor, recipient Device, and bRequest value equal to the vendor code. Signed-off-by: Johann Fischer <johann.fischer@nordicsemi.no>
Platform capability descriptors such as MSOSv2 or WebUSB BOS have a vendor request code that is used by the host to perform vendor-specific requests. Add a convenient way to define and register a platform capability descriptor with a vendor request node. Signed-off-by: Johann Fischer <johann.fischer@nordicsemi.no>
6f692c4
to
eb96943
Compare
Add a WebUSB sample that uses the new USB device support. Signed-off-by: Johann Fischer <johann.fischer@nordicsemi.no>
eb96943
to
210cda7
Compare
@henrikbrixandersen PTAL |
Support BOS descriptor with vendor request code and add WebUSB sample for the new USB device stack.