Răsfoiți Sursa

support usb ble host

sakumisu 2 ani în urmă
părinte
comite
b37f494304

+ 5 - 0
SConscript

@@ -103,6 +103,8 @@ if GetDepend(['PKG_CHERRYUSB_HOST']):
         src += Glob('class/wireless/usbh_rndis.c')
     if GetDepend(['PKG_CHERRYUSB_HOST_CDC_ECM']):
         src += Glob('class/cdc/usbh_cdc_ecm.c')
+    if GetDepend(['PKG_CHERRYUSB_HOST_BLUETOOTH']):
+        src += Glob('class/wireless/usbh_bluetooth.c')
 
     if GetDepend(['PKG_CHERRYUSB_HOST_DWC2']):
         src += Glob('port/dwc2/usb_hc_dwc2.c')
@@ -136,6 +138,9 @@ if GetDepend(['PKG_CHERRYUSB_HOST']):
     if GetDepend('RT_USING_DFS'):
         src += Glob('third_party/rt-thread-5.0/dfs_usbh_msc.c')
 
+    if GetDepend('PKG_USING_NIMBLE'):
+        src += Glob('third_party/nimble-latest/ble_hci_usbh.c')
+
 src += Glob('third_party/rt-thread-5.0/msh_cmd.c')
 
 group = DefineGroup('CherryUSB', src, depend = ['PKG_USING_CHERRYUSB'], CPPPATH = path, CPPDEFINES = CPPDEFINES)

+ 255 - 0
class/wireless/usbh_bluetooth.c

@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2024, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "usbh_core.h"
+#include "usbh_bluetooth.h"
+
+#define DEV_FORMAT "/dev/bluetooth"
+
+static struct usbh_bluetooth g_bluetooth_class;
+
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_bluetooth_cmd_buf[512];
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_bluetooth_event_buf[512];
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_bluetooth_acl_buf[1024];
+
+static int usbh_bluetooth_connect(struct usbh_hubport *hport, uint8_t intf)
+{
+    struct usb_endpoint_descriptor *ep_desc;
+    int ret;
+    uint8_t mult;
+    uint16_t mps;
+
+    struct usbh_bluetooth *bluetooth_class = &g_bluetooth_class;
+
+    if (hport->config.config_desc.bNumInterfaces == (intf + 1)) {
+        return 0;
+    }
+
+    memset(bluetooth_class, 0, sizeof(struct usbh_bluetooth));
+
+    bluetooth_class->hport = hport;
+    bluetooth_class->intf = intf;
+    bluetooth_class->num_of_intf_altsettings = hport->config.intf[intf + 1].altsetting_num;
+
+    hport->config.intf[intf].priv = bluetooth_class;
+
+    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 (USB_GET_ENDPOINT_TYPE(ep_desc->bmAttributes) == USB_ENDPOINT_TYPE_INTERRUPT) {
+            if (ep_desc->bEndpointAddress & 0x80) {
+                USBH_EP_INIT(bluetooth_class->intin, ep_desc);
+            } else {
+                return -USB_ERR_NOTSUPP;
+            }
+        } else {
+            if (ep_desc->bEndpointAddress & 0x80) {
+                USBH_EP_INIT(bluetooth_class->bulkin, ep_desc);
+            } else {
+                USBH_EP_INIT(bluetooth_class->bulkout, ep_desc);
+            }
+        }
+    }
+
+    USB_LOG_INFO("Num of altsettings:%u\r\n", bluetooth_class->num_of_intf_altsettings);
+
+    for (uint8_t i = 0; i < bluetooth_class->num_of_intf_altsettings; i++) {
+        USB_LOG_INFO("Altsetting:%u\r\n", i);
+        for (uint8_t j = 0; j < hport->config.intf[intf + 1].altsetting[i].intf_desc.bNumEndpoints; j++) {
+            ep_desc = &bluetooth_class->hport->config.intf[intf + 1].altsetting[i].ep[j].ep_desc;
+
+            mult = USB_GET_MULT(ep_desc->wMaxPacketSize);
+            mps = USB_GET_MAXPACKETSIZE(ep_desc->wMaxPacketSize);
+
+            USB_LOG_INFO("\tEp=%02x Attr=%02u Mps=%d Interval=%02u Mult=%02u\r\n",
+                         ep_desc->bEndpointAddress,
+                         ep_desc->bmAttributes,
+                         mps,
+                         ep_desc->bInterval,
+                         mult);
+        }
+    }
+
+    ret = usbh_set_interface(hport, intf, 0);
+    if (ret < 0) {
+        return ret;
+    }
+    USB_LOG_INFO("Bluetooth select altsetting 0\r\n");
+
+    snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT);
+    USB_LOG_INFO("Register Bluetooth Class:%s\r\n", hport->config.intf[intf].devname);
+    usbh_bluetooth_run(bluetooth_class);
+    return ret;
+}
+
+static int usbh_bluetooth_disconnect(struct usbh_hubport *hport, uint8_t intf)
+{
+    int ret = 0;
+
+    struct usbh_bluetooth *bluetooth_class = (struct usbh_bluetooth *)hport->config.intf[intf].priv;
+
+    if (hport->config.config_desc.bNumInterfaces == (intf + 1)) {
+        return 0;
+    }
+
+    if (bluetooth_class) {
+        if (bluetooth_class->bulkin) {
+            usbh_kill_urb(&bluetooth_class->bulkin_urb);
+        }
+
+        if (bluetooth_class->bulkout) {
+            usbh_kill_urb(&bluetooth_class->bulkout_urb);
+        }
+
+        if (bluetooth_class->intin) {
+            usbh_kill_urb(&bluetooth_class->intin_urb);
+        }
+
+        // if (bluetooth_class->isoin) {
+        //     usbh_kill_urb(&bluetooth_class->isoin_urb);
+        // }
+
+        // if (bluetooth_class->isoin) {
+        //     usbh_kill_urb(&bluetooth_class->isoinin_urb);
+        // }
+
+        if (hport->config.intf[intf].devname[0] != '\0') {
+            USB_LOG_INFO("Unregister Bluetooth Class:%s\r\n", hport->config.intf[intf].devname);
+            usbh_bluetooth_stop(bluetooth_class);
+        }
+
+        memset(bluetooth_class, 0, sizeof(struct usbh_bluetooth));
+    }
+
+    return ret;
+}
+
+int usbh_bluetooth_hci_cmd(struct usbh_bluetooth *bluetooth_class, uint8_t *buffer, uint32_t buflen)
+{
+    struct usb_setup_packet *setup = bluetooth_class->hport->setup;
+
+    uint16_t opcode = (((uint16_t)buffer[1] << 8) | (uint16_t)buffer[0]);
+
+    USB_LOG_DBG("opcode:%04x, param len:%d\r\n", opcode, buffer[2]);
+
+    setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_DEVICE;
+    setup->bRequest = 0x00;
+    setup->wValue = 0;
+    setup->wIndex = bluetooth_class->intf;
+    setup->wLength = buflen;
+
+    memcpy(g_bluetooth_cmd_buf, buffer, buflen);
+    return usbh_control_transfer(bluetooth_class->hport, setup, g_bluetooth_cmd_buf);
+}
+
+int usbh_bluetooth_hci_acl_out(struct usbh_bluetooth *bluetooth_class, uint8_t *buffer, uint32_t buflen)
+{
+    int ret;
+    struct usbh_urb *urb = &bluetooth_class->bulkout_urb;
+
+    usbh_bulk_urb_fill(urb, bluetooth_class->hport, bluetooth_class->bulkout, buffer, buflen, USB_OSAL_WAITING_FOREVER, NULL, NULL);
+    ret = usbh_submit_urb(urb);
+    if (ret == 0) {
+        ret = urb->actual_length;
+    }
+    return ret;
+}
+
+void usbh_bluetooth_hci_event_rx_thread(void *argument)
+{
+    int ret;
+    uint32_t ep_mps;
+    uint32_t interval;
+    uint8_t retry = 0;
+
+    ep_mps = USB_GET_MAXPACKETSIZE(g_bluetooth_class.intin->wMaxPacketSize);
+    interval = g_bluetooth_class.intin->bInterval;
+
+    while (1) {
+        usbh_int_urb_fill(&g_bluetooth_class.intin_urb, g_bluetooth_class.hport, g_bluetooth_class.intin, g_bluetooth_event_buf, ep_mps, USB_OSAL_WAITING_FOREVER, NULL, NULL);
+        ret = usbh_submit_urb(&g_bluetooth_class.intin_urb);
+        if (ret < 0) {
+            if (ret == -USB_ERR_SHUTDOWN) {
+                goto delete;
+            } else if (ret == -USB_ERR_NAK) {
+                usb_osal_msleep(interval);
+                continue;
+            } else {
+                retry++;
+                if (retry == 3) {
+                    retry = 0;
+                    goto delete;
+                }
+                usb_osal_msleep(interval);
+                continue;
+            }
+        }
+        usbh_bluetooth_hci_rx_callback(USB_BLUETOOTH_HCI_EVT, g_bluetooth_event_buf, g_bluetooth_class.intin_urb.actual_length);
+        usb_osal_msleep(interval);
+    }
+    // clang-format off
+delete : USB_LOG_INFO("Delete hc event rx thread\r\n");
+    usb_osal_thread_delete(NULL);
+    // clang-format om
+}
+
+void usbh_bluetooth_hci_acl_rx_thread(void *argument)
+{
+    int ret;
+    uint32_t ep_mps;
+    uint8_t retry = 0;
+
+    ep_mps = USB_GET_MAXPACKETSIZE(g_bluetooth_class.bulkin->wMaxPacketSize);
+
+    while (1) {
+        usbh_bulk_urb_fill(&g_bluetooth_class.bulkin_urb, g_bluetooth_class.hport, g_bluetooth_class.bulkin, g_bluetooth_acl_buf, ep_mps, USB_OSAL_WAITING_FOREVER, NULL, NULL);
+        ret = usbh_submit_urb(&g_bluetooth_class.bulkin_urb);
+        if (ret < 0) {
+            if (ret == -USB_ERR_SHUTDOWN) {
+                goto delete;
+            } else {
+                retry++;
+                if (retry == 3) {
+                    retry = 0;
+                    goto delete;
+                }
+                continue;
+            }
+        }
+        usbh_bluetooth_hci_rx_callback(USB_BLUETOOTH_HCI_ACL, g_bluetooth_acl_buf, g_bluetooth_class.bulkin_urb.actual_length);
+    }
+    // clang-format off
+delete : USB_LOG_INFO("Delete hc acl rx thread\r\n");
+    usb_osal_thread_delete(NULL);
+    // clang-format om
+}
+
+__WEAK void usbh_bluetooth_hci_rx_callback(uint8_t hci_type, uint8_t *data, uint32_t len)
+{
+}
+
+__WEAK void usbh_bluetooth_run(struct usbh_bluetooth *bluetooth_class)
+{
+}
+
+__WEAK void usbh_bluetooth_stop(struct usbh_bluetooth *bluetooth_class)
+{
+}
+
+static const struct usbh_class_driver bluetooth_class_driver = {
+    .driver_name = "bluetooth",
+    .connect = usbh_bluetooth_connect,
+    .disconnect = usbh_bluetooth_disconnect
+};
+
+CLASS_INFO_DEFINE const struct usbh_class_info bluetooth_class_info = {
+    .match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
+    .class = USB_DEVICE_CLASS_WIRELESS,
+    .subclass = 0x01,
+    .protocol = 0x01,
+    .vid = 0x00,
+    .pid = 0x00,
+    .class_driver = &bluetooth_class_driver
+};

+ 53 - 0
class/wireless/usbh_bluetooth.h

@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2024, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef USBH_BLUETOOTH_H
+#define USBH_BLUETOOTH_H
+
+#define USB_BLUETOOTH_HCI_CMD 1
+#define USB_BLUETOOTH_HCI_EVT 2
+#define USB_BLUETOOTH_HCI_ACL 4
+#define USB_BLUETOOTH_HCI_ISO 5
+
+struct usbh_bluetooth {
+    struct usbh_hubport *hport;
+    struct usb_endpoint_descriptor *bulkin;  /* Bulk IN endpoint */
+    struct usb_endpoint_descriptor *bulkout; /* Bulk OUT endpoint */
+    struct usb_endpoint_descriptor *intin;   /* INTR endpoint */
+    struct usb_endpoint_descriptor *isoin;   /* Bulk IN endpoint */
+    struct usb_endpoint_descriptor *isoout;  /* Bulk OUT endpoint */
+    struct usbh_urb bulkin_urb;              /* Bulk IN urb */
+    struct usbh_urb bulkout_urb;             /* Bulk OUT urb */
+    struct usbh_urb intin_urb;               /* INTR IN urb */
+    struct usbh_urb *isoin_urb;              /* Bulk IN urb */
+    struct usbh_urb *isoout_urb;             /* Bulk OUT urb */
+    uint8_t intf;
+    uint8_t num_of_intf_altsettings;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void usbh_bluetooth_run(struct usbh_bluetooth *bluetooth_class);
+void usbh_bluetooth_stop(struct usbh_bluetooth *bluetooth_class);
+
+/* OpCode(OCF+OGF:2bytes) + ParamLength + Paramas */
+int usbh_bluetooth_hci_cmd(struct usbh_bluetooth *bluetooth_class, uint8_t *buffer, uint32_t buflen);
+/* Handle (12bits) + Packet_Boundary_Flag(2bits) + BC_flag(2bits) + data_len(2bytes) + data */
+int usbh_bluetooth_hci_acl_out(struct usbh_bluetooth *bluetooth_class, uint8_t *buffer, uint32_t buflen);
+void usbh_bluetooth_hci_event_rx_thread(void *argument);
+void usbh_bluetooth_hci_acl_rx_thread(void *argument);
+
+/*  USB_BLUETOOTH_HCI_EVT : EventCode(1byte) + ParamLength + Parama0 + Parama1 + Parama2;
+    USB_BLUETOOTH_HCI_ACL : Handle (12bits) + Packet_Boundary_Flag(2bits) + BC_flag(2bits) + data_len(2bytes) + data
+*/
+void usbh_bluetooth_hci_rx_callback(uint8_t hci_type, uint8_t *data, uint32_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USBH_BLUETOOTH_H */

+ 32 - 0
third_party/nimble-latest/README.md

@@ -0,0 +1,32 @@
+## Note
+
+- ble_hs_startup_set_evmask_tx 函数中 BLE_HCI_OCF_CB_SET_EVENT_MASK2 功能需要关闭
+
+```
+    // if (version >= BLE_HCI_VER_BCS_4_1) {
+    //     /**
+    //      * Enable the following events:
+    //      *     0x0000000000800000 Authenticated Payload Timeout Event
+    //      */
+    //     cmd2.event_mask2 = htole64(0x0000000000800000);
+    //     rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND,
+    //                                       BLE_HCI_OCF_CB_SET_EVENT_MASK2),
+    //                            &cmd2, sizeof(cmd2), NULL, 0);
+    //     if (rc != 0) {
+    //         return rc;
+    //     }
+    // }
+
+```
+
+- 如果使用 rt-thread 中的软件包,请删除软件包中 SConscript 文件以下内容
+
+```
+# if rtconfig.CROSS_TOOL == 'keil':
+    #LOCAL_CCFLAGS += ' --gnu --diag_suppress=111'
+    # __BYTE_ORDER__ & __ORDER_BIG_ENDIAN__ & __ORDER_LITTLE_ENDIAN__ is not defined in keil, the specific values comes from gcc.
+    # CPPDEFINES.append('__ORDER_LITTLE_ENDIAN__=1234')
+    # CPPDEFINES.append('__ORDER_BIG_ENDIAN__=4321')
+    # CPPDEFINES.append('__BYTE_ORDER__=1234')
+    
+```

+ 126 - 0
third_party/nimble-latest/ble_hci_usbh.c

@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2024, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <sysinit/sysinit.h>
+#include <syscfg/syscfg.h>
+#include "os/os_mbuf.h"
+#include <nimble/ble.h>
+#include "nimble/transport.h"
+#include "nimble/transport/hci_h4.h"
+
+#include <usbh_core.h>
+#include <usbh_bluetooth.h>
+
+struct hci_h4_sm g_hci_h4sm;
+
+struct usbh_bluetooth *active_bluetooth_class;
+
+static void hci_dump(uint8_t hci_type, uint8_t *data, uint32_t len)
+{
+    uint32_t i = 0;
+
+    USB_LOG_DBG("hci type:%u\r\n", hci_type);
+
+    for (i = 0; i < len; i++) {
+        if (i % 16 == 0) {
+            USB_LOG_DBG("\r\n");
+        }
+
+        USB_LOG_DBG("%02x ", data[i]);
+    }
+
+    USB_LOG_DBG("\r\n");
+}
+
+static int hci_usb_frame_cb(uint8_t pkt_type, void *data)
+{
+    switch (pkt_type) {
+        case HCI_H4_EVT:
+            return ble_transport_to_hs_evt(data);
+        case HCI_H4_ACL:
+            return ble_transport_to_hs_acl(data);
+        default:
+            assert(0);
+            break;
+    }
+    return -1;
+}
+
+static int ble_usb_transport_init(void)
+{
+    hci_h4_sm_init(&g_hci_h4sm, &hci_h4_allocs_from_ll, hci_usb_frame_cb);
+    return 0;
+}
+
+void usbh_bluetooth_hci_rx_callback(uint8_t hci_type, uint8_t *data, uint32_t len)
+{
+    uint8_t pkt_type = 0;
+
+    if (hci_type == USB_BLUETOOTH_HCI_EVT) {
+        pkt_type = HCI_H4_EVT;
+    } else {
+        pkt_type = HCI_H4_ACL;
+    }
+
+    hci_dump(pkt_type, data, len);
+    hci_h4_sm_rx(&g_hci_h4sm, &pkt_type, 1);
+    hci_h4_sm_rx(&g_hci_h4sm, data, len);
+}
+
+void usbh_bluetooth_run(struct usbh_bluetooth *bluetooth_class)
+{
+    active_bluetooth_class = bluetooth_class;
+    ble_usb_transport_init();
+
+    usb_osal_thread_create("ble_event", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_bluetooth_hci_event_rx_thread, NULL);
+    usb_osal_thread_create("ble_acl", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_bluetooth_hci_acl_rx_thread, NULL);
+}
+
+void usbh_bluetooth_stop(struct usbh_bluetooth *bluetooth_class)
+{
+}
+
+int ble_transport_to_ll_cmd_impl(void *buf)
+{
+    int ret = 0;
+    uint8_t *cmd_pkt_data = (uint8_t *)buf;
+    size_t pkt_len = cmd_pkt_data[2] + 3;
+
+    hci_dump(HCI_H4_CMD, buf, pkt_len);
+
+    ret = usbh_bluetooth_hci_cmd(active_bluetooth_class, buf, pkt_len);
+    if (ret < 0) {
+        ret = BLE_ERR_MEM_CAPACITY;
+    } else {
+        ret = 0;
+    }
+    ble_transport_free(buf);
+
+    return ret;
+}
+
+int ble_transport_to_ll_acl_impl(struct os_mbuf *om)
+{
+    struct os_mbuf *x = om;
+    int ret = 0;
+
+    while (x != NULL) {
+        hci_dump(HCI_H4_ACL, x->om_data, x->om_len);
+
+        ret = usbh_bluetooth_hci_acl_out(active_bluetooth_class, x->om_data, x->om_len);
+        if (ret < 0) {
+            ret = BLE_ERR_MEM_CAPACITY;
+            break;
+        } else {
+            ret = 0;
+        }
+        x = SLIST_NEXT(x, om_next);
+    }
+
+    os_mbuf_free_chain(om);
+
+    return ret;
+}