summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorsakumisu <[email protected]>2024-12-04 23:04:12 +0800
committersakumisu <[email protected]>2024-12-04 23:04:12 +0800
commitbfc1139d800ad041d0fa59d5a642c398bf37b2dc (patch)
treee1da25bf26e8c25d55951c24bd3e4d9c203fb7c3 /docs
parent8d2afc154085b7ffca08ec2cb82d06c400b9a950 (diff)
docs: add vendor rst
Diffstat (limited to 'docs')
-rw-r--r--docs/source/demo/usbd_vendor.rst44
-rw-r--r--docs/source/demo/usbh_vendor.rst127
-rw-r--r--docs/source/index.rst2
3 files changed, 173 insertions, 0 deletions
diff --git a/docs/source/demo/usbd_vendor.rst b/docs/source/demo/usbd_vendor.rst
new file mode 100644
index 00000000..b38631b1
--- /dev/null
+++ b/docs/source/demo/usbd_vendor.rst
@@ -0,0 +1,44 @@
+vendor device 驱动编写
+===========================
+
+本节主要介绍如何编写一个 vendor device 驱动。
+
+- 首先复制一份 class/template/usbd_xxx.c 文件
+- 实现以下三个回调函数,通常来说,vendor 驱动只需要实现 vendor_handler
+
+.. code-block:: C
+
+ intf->class_interface_handler = xxx_class_interface_request_handler;
+ intf->class_endpoint_handler = NULL;
+ intf->vendor_handler = NULL;
+ intf->notify_handler = xxx_notify_handler;
+
+- 举例如下
+
+case1 演示对于主机 IN 数据的处理,将数据拷贝到 *data 中,并指定*len 的长度。协议栈会自动发送给主机,不需要用户手动调用发送 API。
+
+case2 演示对于主机 OUT 数据的处理,当执行到此函数时,说明数据都已经接收完成,可以直接读取 *data 中的数据,长度为 *len。
+
+.. code-block:: C
+
+ static int xxx_vendor_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+ {
+ USB_LOG_WRN("XXX Class request: "
+ "bRequest 0x%02x\r\n",
+ setup->bRequest);
+
+ switch (setup->bRequest) {
+ case 1:
+ memcpy(*data, xxx, sizeof(xxx));
+ *len = sizeof(xxx);
+ case 2:
+ hexdump(*data, *len);
+ default:
+ USB_LOG_WRN("Unhandled XXX Class bRequest 0x%02x\r\n", setup->bRequest);
+ return -1;
+ }
+
+ return 0;
+ }
+
+- 最后使用形如 usbd_add_interface(busid, usbd_xxx_init_intf(&intf)) 注册接口 \ No newline at end of file
diff --git a/docs/source/demo/usbh_vendor.rst b/docs/source/demo/usbh_vendor.rst
new file mode 100644
index 00000000..b86bda60
--- /dev/null
+++ b/docs/source/demo/usbh_vendor.rst
@@ -0,0 +1,127 @@
+vendor host 驱动编写
+===========================
+
+本节主要介绍如何编写一个 vendor host 驱动。
+
+- 首先复制一份 class/template/usbh_xxx.c 文件
+
+- 定义 class 驱动并使用 CLASS_INFO_DEFINE 前缀,这样,枚举完成后,协议栈自动通过 usbd_class_find_driver 来查找对应的驱动。
+
+.. code-block:: C
+
+ static const struct usbh_class_driver xxx_class_driver = {
+ .driver_name = "xxx",
+ .connect = usbh_xxx_connect,
+ .disconnect = usbh_xxx_disconnect
+ };
+
+ CLASS_INFO_DEFINE const struct usbh_class_info xxx_class_info = {
+ .match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
+ .bInterfaceClass = 0,
+ .bInterfaceSubClass = 0,
+ .bInterfaceProtocol = 0,
+ .id_table = NULL,
+ .class_driver = &xxx_class_driver
+ };
+
+
+- 实现 connect 和 disconnect 函数, 在 connect 函数中,需要分配一个 xxx_class 结构体,在 disconnect 函数中释放 urb 和 xxx_class。
+
+.. code-block:: C
+
+ struct usbh_xxx {
+ struct usbh_hubport *hport;
+ struct usb_endpoint_descriptor *xxxin;
+ struct usb_endpoint_descriptor *xxxout;
+ struct usbh_urb xxxin_urb;
+ struct usbh_urb xxxout_urb;
+
+ uint8_t intf; /* interface number */
+ uint8_t minor;
+
+ void *user_data;
+ };
+
+ static int usbh_xxx_connect(struct usbh_hubport *hport, uint8_t intf)
+ {
+ struct usb_endpoint_descriptor *ep_desc;
+ int ret;
+
+ struct usbh_xxx *xxx_class = usbh_xxx_class_alloc();
+ if (xxx_class == NULL) {
+ USB_LOG_ERR("Fail to alloc xxx_class\r\n");
+ return -USB_ERR_NOMEM;
+ }
+
+ return ret;
+ }
+
+
+ static int usbh_xxx_disconnect(struct usbh_hubport *hport, uint8_t intf)
+ {
+ int ret = 0;
+
+ struct usbh_xxx *xxx_class = (struct usbh_xxx *)hport->config.intf[intf].priv;
+
+ if (xxx_class) {
+ if (xxx_class->xxxin) {
+ usbh_kill_urb(&xxx_class->xxxin_urb);
+ }
+
+ if (xxx_class->xxxout) {
+ usbh_kill_urb(&xxx_class->xxxout_urb);
+ }
+
+ if (hport->config.intf[intf].devname[0] != '\0') {
+ USB_LOG_INFO("Unregister xxx Class:%s\r\n", hport->config.intf[intf].devname);
+ usbh_xxx_stop(xxx_class);
+ }
+
+ usbh_xxx_class_free(xxx_class);
+ }
+
+ return ret;
+ }
+
+- 初始化端点
+
+.. code-block:: C
+
+ for (uint8_t i = 0; i < hport->config.intf[intf].altsetting[0].intf_desc.bNumEndpoints; i++) {
+ ep_desc = &hport->config.intf[intf].altsetting[0].ep[i].ep_desc;
+ if (ep_desc->bEndpointAddress & 0x80) {
+ USBH_EP_INIT(xxx_class->intin, ep_desc);
+ } else {
+ USBH_EP_INIT(xxx_class->intout, ep_desc);
+ }
+ }
+
+- 最后设计收发 API,根据实际情况设计成同步 or 异步。
+
+.. code-block:: C
+
+ int usbh_xxx_in_transfer(struct usbh_xxx *xxx_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
+ {
+ int ret;
+ struct usbh_urb *urb = &xxx_class->xxxin_urb;
+
+ usbh_xxx_urb_fill(urb, xxx_class->hport, xxx_class->xxxin, buffer, buflen, timeout, NULL, NULL);
+ ret = usbh_submit_urb(urb);
+ if (ret == 0) {
+ ret = urb->actual_length;
+ }
+ return ret;
+ }
+
+ int usbh_xxx_out_transfer(struct usbh_xxx *xxx_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout)
+ {
+ int ret;
+ struct usbh_urb *urb = &xxx_class->xxxout_urb;
+
+ usbh_xxx_urb_fill(urb, xxx_class->hport, xxx_class->xxxout, buffer, buflen, timeout, NULL, NULL);
+ ret = usbh_submit_urb(urb);
+ if (ret == 0) {
+ ret = urb->actual_length;
+ }
+ return ret;
+ } \ No newline at end of file
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 0f535219..68a64f9a 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -112,6 +112,8 @@ CherryUSB 是一个小而美的、可移植性高的、用于嵌入式系统的
demo/usbh_net
demo/usbh_bluetooth
demo/usbh_wifi
+ demo/usbd_vendor
+ demo/usbh_vendor
.. toctree::
:maxdepth: 1