From bfc1139d800ad041d0fa59d5a642c398bf37b2dc Mon Sep 17 00:00:00 2001 From: sakumisu <1203593632@qq.com> Date: Wed, 4 Dec 2024 23:04:12 +0800 Subject: [PATCH] docs: add vendor rst --- docs/source/demo/usbd_vendor.rst | 44 +++++++++++ docs/source/demo/usbh_vendor.rst | 127 +++++++++++++++++++++++++++++++ docs/source/index.rst | 2 + 3 files changed, 173 insertions(+) create mode 100644 docs/source/demo/usbd_vendor.rst create mode 100644 docs/source/demo/usbh_vendor.rst 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