[PATCH 1/1] [Add support Mediatek mt7921U]
Marcel Holtmann
marcel at holtmann.org
Tue Dec 22 16:36:49 EST 2020
Hi Mark,
> This patch adds the support of enabling MT7921U, it's USB-based
> Bluetooth function.
>
> There are some component in the Mediatek driver.
> 1. Btmtk_main: it's common code for Mediatek devices,
> such as firmware download, chip initialization,
> state machine handling and etc.
> 2. Btmtkusb: it's for usb interface,
> such as usb endpoint enumeration, urb handling and etc.
>
> Firstly, we update the common part and usb part for MT7921U.
> Secondly, we will add the support MT7921S, it's SDIO-based device.
> Finally, we will add the procedure to support uart/pcie interfaces.
create a btmtk.[ch] module like the other vendors did if it makes sense. Otherwise just skip that part for now and get btmtkusb.c driver working. You can later unify between all 3 transports.
I would do the latter since it would first make sense to really see where the common parts are. And I have to be frank, this driver needs massive cleanup. I am not going to accept this tons of copy-and-paste left and right.
Please provide the content of /sys/kernel/debug/usb/devices in the commit message.
>
> Signed-off-by: Mark-YW Chen <mark-yw.chen at mediatek.com>
> ---
> drivers/bluetooth/btmtk_main.c | 1735 +++++++++++++++++++++++++++
> drivers/bluetooth/btmtk_main.h | 578 +++++++++
> drivers/bluetooth/btmtk_usb.h | 60 +
> drivers/bluetooth/btmtkusb.c | 2050 ++++++++++++++++++++++++++++++++
> 4 files changed, 4423 insertions(+)
> create mode 100644 drivers/bluetooth/btmtk_main.c
> create mode 100644 drivers/bluetooth/btmtk_main.h
> create mode 100644 drivers/bluetooth/btmtk_usb.h
> create mode 100644 drivers/bluetooth/btmtkusb.c
>
> diff --git a/drivers/bluetooth/btmtk_main.c b/drivers/bluetooth/btmtk_main.c
> new file mode 100644
> index 000000000000..3038eda057e8
> --- /dev/null
> +++ b/drivers/bluetooth/btmtk_main.c
> @@ -0,0 +1,1735 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (c) 2020 MediaTek Inc.
> +
> +/*
> + * Bluetooth support for MediaTek SDIO/USB/UART devices
> + *
> + */
> +
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/input.h>
> +#include <linux/pm_wakeup.h>
> +#include <linux/reboot.h>
> +#include <linux/string.h>
> +#include "btmtk_main.h"
> +
> +#define MTKBT_UNSLEEPABLE_LOCK(x, y) spin_lock_irqsave(x, y)
> +#define MTKBT_UNSLEEPABLE_UNLOCK(x, y) spin_unlock_irqsave(x, y)
NO. Period.
Please don’t have these abstractions.
> +
> +/* TODO, need to modify the state mutex for each hci dev*/
> +static DEFINE_MUTEX(btmtk_chip_state_mutex);
> +#define CHIP_STATE_MUTEX_LOCK() mutex_lock(&btmtk_chip_state_mutex)
> +#define CHIP_STATE_MUTEX_UNLOCK() mutex_unlock(&btmtk_chip_state_mutex)
> +static DEFINE_MUTEX(btmtk_fops_state_mutex);
> +#define FOPS_MUTEX_LOCK() mutex_lock(&btmtk_fops_state_mutex)
> +#define FOPS_MUTEX_UNLOCK() mutex_unlock(&btmtk_fops_state_mutex)
> +
I have no idea why you need global locks. You are doing something wrong if you do.
> +static int btmtk_fops_get_state(struct btmtk_dev *bdev);
> +u8 btmtk_log_lvl = BTMTK_LOG_LVL_DEF;
> +
No. Use bt_dev_dbg() or BT_DBG() which both are dynamic_debug capable.
> +/* To support dynamic mount of interface can be probed */
> +static int btmtk_intf_num = BT_MCU_MINIMUM_INTERFACE_NUM;
> +/* To allow g_bdev being sized from btmtk_intf_num setting */
> +static struct btmtk_dev **g_bdev;
NO. Period. No global dev instances.
> +
> +const u8 RESET_EVENT[] = { 0x0E, 0x04, 0x01, 0x03, 0x0c, 0x00 };
> +const u8 READ_ISO_PACKET_SIZE_CMD[] = { 0x01, 0x98, 0xFD, 0x02 };
> +
> +u8 wmt_over_hci_header[] = { 0x01, 0x6F, 0xFC};
> +
Need to be all static and I would rather have it inline where they are used.
> +/*btmtk main information*/
> +static struct btmtk_main_info main_info;
NO. Period. Same as above, no global structs.
> +
> +/* State machine table that clarify through each HIF events,
> + * To specify HIF event on
> + * Entering / End / Error
> + */
> +static const struct btmtk_cif_state g_cif_state[] = {
> + /* HIF_EVENT_PROBE */
> + {BTMTK_STATE_PROBE, BTMTK_STATE_WORKING, BTMTK_STATE_DISCONNECT},
> + /* HIF_EVENT_DISCONNECT */
> + {BTMTK_STATE_DISCONNECT, BTMTK_STATE_DISCONNECT, BTMTK_STATE_DISCONNECT},
> + /* HIF_EVENT_SUSPEND */
> + {BTMTK_STATE_SUSPEND, BTMTK_STATE_SUSPEND, BTMTK_STATE_FW_DUMP},
> + /* HIF_EVENT_RESUME */
> + {BTMTK_STATE_RESUME, BTMTK_STATE_WORKING, BTMTK_STATE_FW_DUMP},
> + /* HIF_EVENT_STANDBY */
> + {BTMTK_STATE_STANDBY, BTMTK_STATE_STANDBY, BTMTK_STATE_FW_DUMP},
> + /* BTMTK_STATE_FW_DUMP */
> + {BTMTK_STATE_SUBSYS_RESET, BTMTK_STATE_WORKING, BTMTK_STATE_FW_DUMP},
> + /* BTMTK_STATE_FW_DUMP */
> + {BTMTK_STATE_FW_DUMP, BTMTK_STATE_DISCONNECT, BTMTK_STATE_FW_DUMP},
> + /* BTMTK_STATE_FW_DUMP */
> + {BTMTK_STATE_FW_DUMP, BTMTK_STATE_FW_DUMP, BTMTK_STATE_FW_DUMP},
> +};
> +
> +__weak int btmtk_cif_register(void)
> +{
> + BTMTK_ERR("No cif register function");
> + return -1;
> +}
> +
> +__weak int btmtk_cif_deregister(void)
> +{
> + BTMTK_ERR("No cif deregister function");
> + return -1;
> +}
Remove this. This is just pointless.
> +
> +int btmtk_get_chip_state(struct btmtk_dev *bdev)
> +{
> + int state = BTMTK_STATE_INIT;
> +
> + CHIP_STATE_MUTEX_LOCK();
> + state = bdev->interface_state;
> + CHIP_STATE_MUTEX_UNLOCK();
> +
> + return state;
> +}
> +
> +void btmtk_set_chip_state(struct btmtk_dev *bdev, int new_state)
> +{
> + static const char * const state_msg[] = {
> + "UNKNOWN", "INIT", "DISCONNECT", "PROBE", "WORKING", "SUSPEND", "RESUME",
> + "FW_DUMP", "STANDBY", "SUBSYS_RESET",
> + };
> +
> + BTMTK_INFO("%s: %s(%d) -> %s(%d)", __func__, state_msg[bdev->interface_state],
> + bdev->interface_state, state_msg[new_state], new_state);
> +
> + CHIP_STATE_MUTEX_LOCK();
> + bdev->interface_state = new_state;
> + CHIP_STATE_MUTEX_UNLOCK();
> +}
> +
> +static int btmtk_fops_get_state(struct btmtk_dev *bdev)
> +{
> + int state = BTMTK_FOPS_STATE_INIT;
> +
> + FOPS_MUTEX_LOCK();
> + state = bdev->fops_state;
> + FOPS_MUTEX_UNLOCK();
> +
> + return state;
> +}
> +
> +static void btmtk_fops_set_state(struct btmtk_dev *bdev, int new_state)
> +{
> + static const char * const fstate_msg[] = {
> + "UNKNOWN", "INIT", "OPENING", "OPENED", "CLOSING", "CLOSED",
> + };
> +
> + BTMTK_INFO("%s: FOPS_%s(%d) -> FOPS_%s(%d)", __func__, fstate_msg[bdev->fops_state],
> + bdev->fops_state, fstate_msg[new_state], new_state);
> + FOPS_MUTEX_LOCK();
> + bdev->fops_state = new_state;
> + FOPS_MUTEX_UNLOCK();
> +}
> +
> +struct btmtk_main_info *btmtk_get_main_info(void)
> +{
> + return &main_info;
> +}
> +
> +static int main_init(void)
> +{
> + int i = 0;
> +
> + BTMTK_INFO("%s", __func__);
> +
> + /* Check if user changes default minimum supported intf count */
> + if (btmtk_intf_num < BT_MCU_MINIMUM_INTERFACE_NUM) {
> + btmtk_intf_num = BT_MCU_MINIMUM_INTERFACE_NUM;
> + BTMTK_WARN("%s minimum interface is %d", __func__, btmtk_intf_num);
> + }
> +
> + g_bdev = kzalloc((sizeof(*g_bdev) * btmtk_intf_num), GFP_KERNEL);
> + if (!g_bdev) {
> + BTMTK_WARN("%s insufficient memory", __func__);
> + return -ENOMEM;
> + }
> +
> + for (i = 0; i < btmtk_intf_num; i++) {
> + g_bdev[i] = btmtk_allocate_dev_memory(NULL);
> + if (g_bdev[i])
> + btmtk_fops_set_state(g_bdev[i], BTMTK_FOPS_STATE_INIT);
> + else
> + return -ENOMEM;
> + }
> +
> + return 0;
> +}
> +
> +static int main_exit(void)
> +{
> + int i = 0;
> +
> + BTMTK_INFO("%s releasing intf count <%d>", __func__, btmtk_intf_num);
> +
> + if (!g_bdev) {
> + BTMTK_WARN("%s g_data is NULL", __func__);
> + return 0;
> + }
> +
> + BTMTK_INFO("%s: Register reboot_notifier callback success.", __func__);
> +
> + for (i = 0; i < btmtk_intf_num; i++) {
> + if (!g_bdev[i])
> + btmtk_free_dev_memory(NULL, g_bdev[i]);
> + }
> +
> + kfree(g_bdev);
> + return 0;
> +}
> +
> +static inline struct sk_buff *h4_recv_buf(struct hci_dev *hdev,
> + struct sk_buff *skb,
> + const unsigned char *buffer,
> + int count,
> + const struct h4_recv_pkt *pkts,
> + int pkts_count)
> +{
NO. Period. You are not going to copy of this function. We provide h4_recv.h for this.
> +
> + if (!hdev || !buffer) {
> + BTMTK_ERR("%s, invalid parameters!", __func__);
> + return ERR_PTR(-EINVAL);
> + }
> +
> + bdev = hci_get_drvdata(hdev);
> + if (!bdev) {
> + BTMTK_ERR("%s, bdev is invalid", __func__);
> + return ERR_PTR(-EINVAL);
> + }
> + if (IS_ERR(skb))
> + skb = NULL;
> +
> + while (count) {
> + int i, len;
> +
> + if (!skb) {
> + for (i = 0; i < pkts_count; i++) {
> + if (buffer[0] != (&pkts[i])->type)
> + continue;
> +
> + skb = bt_skb_alloc((&pkts[i])->maxlen,
> + GFP_ATOMIC);
> + if (!skb) {
> + BTMTK_ERR("%s, alloc skb failed!", __func__);
> + return ERR_PTR(-ENOMEM);
> + }
> +
> + hci_skb_pkt_type(skb) = (&pkts[i])->type;
> + hci_skb_expect(skb) = (&pkts[i])->hlen;
> + break;
> + }
> +
> + /* Check for invalid packet type */
> + if (!skb) {
> + BTMTK_ERR("%s,skb is invalid, buffer[0] = %d!", __func__,
> + buffer[0]);
> + return ERR_PTR(-EILSEQ);
> + }
> +
> + count -= 1;
> + buffer += 1;
> + }
> +
> + len = min_t(uint, hci_skb_expect(skb) - skb->len, count);
> + memcpy(skb_put(skb, len), buffer, len);
> +
> + count -= len;
> + buffer += len;
> +
> + if (skb->len < hci_skb_expect(skb))
> + continue;
> +
> + for (i = 0; i < pkts_count; i++) {
> + if (hci_skb_pkt_type(skb) == (&pkts[i])->type)
> + break;
> + }
> +
> + if (i >= pkts_count) {
> + BTMTK_ERR("%s, pkt type is invalid!", __func__);
> + kfree_skb(skb);
> + return ERR_PTR(-EILSEQ);
> + }
> +
> + if (skb->len == (&pkts[i])->hlen) {
> + u16 dlen;
> +
> + switch ((&pkts[i])->lsize) {
> + case 0:
> + /* No variable data length */
> + dlen = 0;
> + break;
> + case 1:
> + dlen = skb->data[(&pkts[i])->loff];
> + hci_skb_expect(skb) += dlen;
> +
> + if (skb_tailroom(skb) < dlen) {
> + BTMTK_ERR("%s, skb_tailroom is not enough, dlen:%d!",
> + __func__, dlen);
> + kfree_skb(skb);
> + return ERR_PTR(-EMSGSIZE);
> + }
> + break;
> + case 2:
> + /* Double octet variable length */
> + dlen = get_unaligned_le16(skb->data +
> + (&pkts[i])->loff);
> + hci_skb_expect(skb) += dlen;
> +
> + if (skb_tailroom(skb) < dlen) {
> + BTMTK_ERR("%s, tailroom isn't enough in case 2, dlen:%d!",
> + __func__, dlen);
> + kfree_skb(skb);
> + return ERR_PTR(-EMSGSIZE);
> + }
> + break;
> + default:
> + /* Unsupported variable length */
> + BTMTK_ERR("%s, Unsupported variable length!", __func__);
> + kfree_skb(skb);
> + return ERR_PTR(-EILSEQ);
> + }
> +
> + if (!dlen) {
> + /* No more data, complete frame */
> + (&pkts[i])->recv(hdev, skb);
> + skb = NULL;
> + }
> + } else {
> + /* Complete frame */
> + (&pkts[i])->recv(hdev, skb);
> + skb = NULL;
> + }
> + }
> +
> + return skb;
> +}
> +
> +static const struct h4_recv_pkt mtk_recv_pkts[] = {
> + { H4_RECV_ACL, .recv = btmtk_recv_acl },
> + { H4_RECV_SCO, .recv = hci_recv_frame },
> + { H4_RECV_EVENT, .recv = btmtk_recv_event },
> +};
> +
> +int btmtk_recv(struct hci_dev *hdev, const u8 *data, size_t count)
> +{
> + struct btmtk_dev *bdev = NULL;
> + const unsigned char *p_left = data;
> + int sz_left = count;
> + int err;
> +
> + if (!hdev || !data) {
> + BTMTK_ERR("%s, invalid parameters!", __func__);
> + return -EINVAL;
> + }
> +
> + bdev = hci_get_drvdata(hdev);
> + if (!bdev) {
> + BTMTK_ERR("%s, bdev is NULL!", __func__);
> + return -EINVAL;
> + }
> +
> + while (sz_left > 0) {
> + /* The serial data received from MT7622 BT controller is
> + * at all time padded around with the STP header and tailer.
> + *
> + * A full STP packet is looking like
> + * -----------------------------------
> + * | STP header | H:4 | STP tailer |
> + * -----------------------------------
> + * but it doesn't guarantee to contain a full H:4 packet which
> + * means that it's possible for multiple STP packets forms a
> + * full H:4 packet that means extra STP header + length doesn't
> + * indicate a full H:4 frame, things can fragment. Whose length
> + * recorded in STP header just shows up the most length the
> + * H:4 engine can handle currently.
> + */
> +
> + bdev->rx_skb = h4_recv_buf(hdev, bdev->rx_skb, data,
> + count, mtk_recv_pkts,
> + ARRAY_SIZE(mtk_recv_pkts));
> +
> + if (IS_ERR(bdev->rx_skb)) {
> + err = PTR_ERR(bdev->rx_skb);
> + pr_err("Frame reassembly failed (%d)", err);
> + bdev->rx_skb = NULL;
> + return err;
> + }
> +
> + sz_left -= count;
> + p_left += count;
> + }
> +
> + return 0;
> +}
> +
> +static int btmtk_dispatch_pkt(struct hci_dev *hdev, struct sk_buff *skb)
> +{
> + struct btmtk_dev *bdev = hci_get_drvdata(hdev);
> + int state = BTMTK_STATE_INIT;
> +
> + if ((bt_cb(skb)->pkt_type == HCI_ACLDATA_PKT) &&
> + skb->data[0] == 0x6f &&
> + skb->data[1] == 0xfc) {
> + static int dump_data_counter;
> + static int dump_data_length;
> +
> + state = btmtk_get_chip_state(bdev);
> + if (state != BTMTK_STATE_FW_DUMP) {
> + BTMTK_INFO("%s: FW dump begin", __func__);
> + dump_data_counter = 0;
> + dump_data_length = 0;
> + btmtk_set_chip_state(bdev, BTMTK_STATE_FW_DUMP);
> + }
> +
> + dump_data_counter++;
> + dump_data_length += skb->len;
> +
> + if (dump_data_counter % 1000 == 0) {
> + BTMTK_INFO("%s: FW dump on-going, total_packet = %d, total_length = %d",
> + __func__, dump_data_counter, dump_data_length);
> + }
> +
> + if (dump_data_counter < 20)
> + BTMTK_INFO("%s: FW dump data (%d): %s",
> + __func__, dump_data_counter, &skb->data[4]);
> +
> + if (skb->data[skb->len - 4] == 'e' &&
> + skb->data[skb->len - 3] == 'n' &&
> + skb->data[skb->len - 2] == 'd') {
> + BTMTK_INFO("%s: FW dump end, dump_data_counter = %d",
> + __func__, dump_data_counter);
> + }
> + } else if (memcmp(skb->data, RESET_EVENT, sizeof(RESET_EVENT)) == 0) {
> + BTMTK_INFO("%s: Get RESET_EVENT", __func__);
> + }
> + return 0;
> +}
> +
> +int btmtk_recv_acl(struct hci_dev *hdev, struct sk_buff *skb)
> +{
> + struct btmtk_dev *bdev = NULL;
> +
> + if (!hdev || !skb) {
> + BTMTK_ERR("%s, invalid parameters!", __func__);
> + return -EINVAL;
> + }
> +
> + bdev = hci_get_drvdata(hdev);
> + if (!bdev || !bdev->workqueue) {
> + BTMTK_ERR("%s, bdev or workqueue is invalid!", __func__);
> + return -EINVAL;
> + }
> +
> + skb_queue_tail(&bdev->rx_q, skb);
> + queue_work(bdev->workqueue, &bdev->rx_work);
> +
> + return 0;
> +}
> +
> +int btmtk_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
> +{
> + struct btmtk_dev *bdev = NULL;
> +
> + if (!hdev || !skb) {
> + BTMTK_ERR("%s, invalid parameters!", __func__);
> + return -EINVAL;
> + }
> +
> + bdev = hci_get_drvdata(hdev);
> + if (!bdev || !bdev->workqueue) {
> + BTMTK_ERR("%s, bdev or workqueue is invalid!", __func__);
> + kfree_skb(skb);
> + return -EINVAL;
> + }
> +
> + skb_queue_tail(&bdev->rx_q, skb);
> + queue_work(bdev->workqueue, &bdev->rx_work);
> +
> + return 0;
> +}
> +
> +int btmtk_main_send_cmd(struct btmtk_dev *bdev, const u8 *cmd,
> + const int cmd_len, const u8 *event, const int event_len,
> + int delay, int retry, int pkt_type)
> +{
> + struct sk_buff *skb = NULL;
> + int ret = 0;
> + int state = BTMTK_STATE_INIT;
> +
> + if (!bdev || !bdev->hdev || !cmd || cmd_len <= 0) {
> + BTMTK_ERR("%s, invalid parameters!", __func__);
> + ret = -EINVAL;
> + goto exit;
> + }
> +
> + if (memcmp(cmd, wmt_over_hci_header, sizeof(wmt_over_hci_header)) &&
> + pkt_type != BTMTK_TX_ACL_FROM_DRV &&
> + bdev->power_state != BTMTK_DONGLE_STATE_POWER_ON) {
> + BTMTK_WARN("%s: chip power isn't on, ignore this command, state is %d",
> + __func__, bdev->power_state);
> + goto exit;
> + }
> +
> + state = btmtk_get_chip_state(bdev);
> + if (state == BTMTK_STATE_FW_DUMP) {
> + BTMTK_WARN("%s: FW dumping ongoing, don't send any cmd to FW!!!", __func__);
> + ret = -1;
> + goto exit;
> + }
> +
> + skb = alloc_skb(cmd_len + BT_SKB_RESERVE, GFP_ATOMIC);
> + if (!skb) {
> + BTMTK_ERR("%s allocate skb failed!!", __func__);
> + goto exit;
> + }
> +
> + skb_reserve(skb, 7);
> + bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
> + memcpy(skb->data, cmd, cmd_len);
> + skb->len = cmd_len;
> +
> + ret = main_info.hif_hook.send_and_recv(bdev,
> + skb,
> + event, event_len,
> + delay, retry, pkt_type);
> +
> + if (ret < 0)
> + BTMTK_ERR("%s send_and_recv failed!!", __func__);
> +
> +exit:
> + BTMTK_DBG("%s end!!", __func__);
> + return ret;
> +}
> +
> +static void btmtk_load_code_from_bin(const struct firmware **fw_firmware,
> + char *bin_name, struct device *dev,
> + u8 **image, u32 *code_len)
> +{
> + int err = 0;
> + int retry = 10;
> +
> + if (!bin_name) {
> + BTMTK_ERR("%s, invalid parameters!", __func__);
> + return;
> + }
> +
> + do {
> + err = request_firmware(fw_firmware, bin_name, dev);
> + if (err == 0) {
> + break;
> + } else if (retry <= 0) {
> + *fw_firmware = NULL;
> + BTMTK_INFO("%s: request_firmware %d times fail, file not exist, err = %d",
> + __func__, 10, err);
> + return;
> + }
> + BTMTK_INFO("%s: request_firmware fail, file not exist, err = %d, retry = %d",
> + __func__, err, retry);
> + msleep(100);
> + } while (retry-- > 0);
> +
> + *image = (u8 *)(*fw_firmware)->data;
> + *code_len = (*fw_firmware)->size;
> +}
> +
> +static void btmtk_print_bt_patch_info(struct btmtk_dev *bdev, u8 *fwbuf)
> +{
> + struct _PATCH_HEADER *patchhdr = NULL;
> + struct _GLOBAL_DESCR *globaldesrc = NULL;
> +
> + if (!fwbuf) {
> + BTMTK_WARN("%s, fwbuf is NULL!", __func__);
> + return;
> + }
> +
> + patchhdr = (struct _PATCH_HEADER *)fwbuf;
> +
> + if (is_mt7922(bdev->chip_id) || is_mt7961(bdev->chip_id))
> + globaldesrc = (struct _GLOBAL_DESCR *)(fwbuf + FW_ROM_PATCH_HEADER_SIZE);
> +
> + BTMTK_INFO("[btmtk] =============== Patch Info ==============");
> + if (patchhdr) {
> + BTMTK_INFO("[btmtk] Built Time = %s", patchhdr->ucdatetime);
> + BTMTK_INFO("[btmtk] Hw Ver = 0x%04x", patchhdr->u2hwver);
> + BTMTK_INFO("[btmtk] Sw Ver = 0x%04x", patchhdr->u2swver);
> + BTMTK_INFO("[btmtk] Magic Number = 0x%08x", patchhdr->u4magicnum);
> +
> + BTMTK_INFO("[btmtk] Platform = %c%c%c%c",
> + patchhdr->ucplatform[0],
> + patchhdr->ucplatform[1],
> + patchhdr->ucplatform[2],
> + patchhdr->ucplatform[3]);
> + }
> +
> + if (globaldesrc) {
> + BTMTK_INFO("[btmtk] Patch Ver = 0x%08x", globaldesrc->u4patchver);
> + BTMTK_INFO("[btmtk] Section num = 0x%08x", globaldesrc->u4sectionnum);
> + }
> +
> + BTMTK_INFO("[btmtk] =========================================");
> +}
> +
> +static void btmtk_print_wifi_patch_info(struct btmtk_dev *bdev, u8 *fwbuf)
> +{
> + struct _PATCH_HEADER *patchhdr = NULL;
> + struct _GLOBAL_DESCR *globaldesrc = NULL;
> +
> + if (!fwbuf) {
> + BTMTK_WARN("%s, fwbuf is NULL!", __func__);
> + return;
> + }
> +
> + patchhdr = (struct _PATCH_HEADER *)fwbuf;
> +
> + if (is_mt7922(bdev->chip_id) || is_mt7961(bdev->chip_id))
> + globaldesrc = (struct _GLOBAL_DESCR *)(fwbuf + FW_ROM_PATCH_HEADER_SIZE);
> +
> + BTMTK_INFO("[btmtk] =============== Wifi Patch Info ==============");
> + if (patchhdr) {
> + BTMTK_INFO("[btmtk] Built Time = %s", patchhdr->ucdatetime);
> + BTMTK_INFO("[btmtk] Hw Ver = 0x%04x",
> + ((patchhdr->u2hwver & 0x00ff) << 8) |
> + ((patchhdr->u2hwver & 0xff00) >> 8));
> + BTMTK_INFO("[btmtk] Sw Ver = 0x%04x",
> + ((patchhdr->u2swver & 0x00ff) << 8) |
> + ((patchhdr->u2swver & 0xff00) >> 8));
> + BTMTK_INFO("[btmtk] Magic Number = 0x%08x", be2cpu32(patchhdr->u4magicnum));
> +
> + BTMTK_INFO("[btmtk] Platform = %c%c%c%c",
> + patchhdr->ucplatform[0],
> + patchhdr->ucplatform[1],
> + patchhdr->ucplatform[2],
> + patchhdr->ucplatform[3]);
> + }
> +
> + if (globaldesrc) {
> + BTMTK_INFO("[btmtk] Patch Ver = 0x%08x",
> + be2cpu32(globaldesrc->u4patchver));
> + BTMTK_INFO("[btmtk] Section num = 0x%08x",
> + be2cpu32(globaldesrc->u4sectionnum));
> + } else {
> + BTMTK_WARN("%s, globaldesrc is NULL!", __func__);
> + }
> +
> + BTMTK_INFO("[btmtk] =========================================");
> +}
> +
> +static int btmtk_send_wmt_download_cmd(struct btmtk_dev *bdev, u8 *cmd,
> + int cmd_len, u8 *event, int event_len,
> + struct _SECTION_MAP *sectionmap,
> + u8 fw_state, u8 dma_flag, bool patch_flag)
> +{
> + int payload_len = 0;
> + int ret = -1;
> + int i = 0;
> + u32 revert_secspec = 0;
> +
> + if (!bdev || !cmd || !event || !sectionmap) {
> + BTMTK_ERR("%s: invalid parameter!", __func__);
> + return ret;
> + }
> +
> + /* prepare HCI header */
> + cmd[0] = 0x01;
> + cmd[1] = 0x6F;
> + cmd[2] = 0xFC;
> +
> + /* prepare WMT header */
> + cmd[4] = 0x01;
> + cmd[5] = 0x01;
> +
> + if (fw_state == 0) {
> + /* prepare WMT DL cmd */
> + payload_len = SEC_MAP_NEED_SEND_SIZE + 2;
> +
> + cmd[3] = (payload_len + 4) & 0xFF;
> + cmd[6] = payload_len & 0xFF;
> + cmd[7] = (payload_len >> 8) & 0xFF;
> + cmd[8] = 0x00;
> + cmd[9] = dma_flag; /* 1:using DMA to download, 0:using legacy wmt cmd*/
> + cmd_len = SEC_MAP_NEED_SEND_SIZE + PATCH_HEADER_SIZE;
> +
> + if (patch_flag)
> + for (i = 0; i < SECTION_SPEC_NUM; i++) {
> + revert_secspec = be2cpu32(sectionmap->u4secspec[i]);
> + memcpy(&cmd[PATCH_HEADER_SIZE] + i * sizeof(u32),
> + (u8 *)&revert_secspec, sizeof(u32));
> + }
> + else
> + memcpy(&cmd[PATCH_HEADER_SIZE], (u8 *)(sectionmap->u4secspec),
> + SEC_MAP_NEED_SEND_SIZE);
> +
> + ret = btmtk_main_send_cmd(bdev, cmd, cmd_len,
> + event, event_len, DELAY_TIMES, RETRY_TIMES,
> + BTMTK_TX_CMD_FROM_DRV);
> + if (ret < 0) {
> + BTMTK_ERR("%s: send wmd dl cmd failed, terminate!", __func__);
> + return PATCH_ERR;
> + }
> +
> + if (bdev->recv_evt_len >= event_len)
> + return bdev->io_buf[PATCH_STATUS];
> +
> + ret = PATCH_ERR;
> + } else {
> + BTMTK_ERR("%s: fw state is error!", __func__);
> + }
> +
> + return ret;
> +}
> +
> +static int btmtk_load_fw_patch_using_wmt_cmd(struct btmtk_dev *bdev,
> + u8 *image, u8 *fwbuf, u8 *event,
> + int event_len, u32 patch_len, int offset)
> +{
> + int ret = 0;
> + u32 cur_len = 0;
> + s32 sent_len;
> + int first_block = 1;
> + u8 phase;
> + int delay = PATCH_DOWNLOAD_PHASE1_2_DELAY_TIME;
> + int retry = PATCH_DOWNLOAD_PHASE1_2_RETRY;
> +
> + if (!bdev || !image || !fwbuf) {
> + BTMTK_WARN("%s, invalid parameters!", __func__);
> + ret = -1;
> + goto exit;
> + }
> +
> + /* loading rom patch */
> + while (1) {
> + s32 sent_len_max = UPLOAD_PATCH_UNIT - PATCH_HEADER_SIZE;
> +
> + sent_len = (patch_len - cur_len) >= sent_len_max ?
> + sent_len_max : (patch_len - cur_len);
> +
> + if (sent_len > 0) {
> + if (first_block == 1) {
> + if (sent_len < sent_len_max)
> + phase = PATCH_PHASE3;
> + else
> + phase = PATCH_PHASE1;
> + first_block = 0;
> + } else if (sent_len == sent_len_max) {
> + if (patch_len - cur_len == sent_len_max)
> + phase = PATCH_PHASE3;
> + else
> + phase = PATCH_PHASE2;
> + } else {
> + phase = PATCH_PHASE3;
> + }
> +
> + /* prepare HCI header */
> + image[0] = 0x02;
> + image[1] = 0x6F;
> + image[2] = 0xFC;
> + image[3] = (sent_len + 5) & 0xFF;
> + image[4] = ((sent_len + 5) >> 8) & 0xFF;
> +
> + /* prepare WMT header */
> + image[5] = 0x01;
> + image[6] = 0x01;
> + image[7] = (sent_len + 1) & 0xFF;
> + image[8] = ((sent_len + 1) >> 8) & 0xFF;
> +
> + image[9] = phase;
> + memcpy(&image[10], fwbuf + offset + cur_len, sent_len);
> + if (phase == PATCH_PHASE3) {
> + delay = PATCH_DOWNLOAD_PHASE3_DELAY_TIME;
> + retry = PATCH_DOWNLOAD_PHASE3_RETRY;
> + }
> +
> + cur_len += sent_len;
> + BTMTK_DBG("%s: sent_len = %d, cur_len = %d, phase = %d", __func__,
> + sent_len, cur_len, phase);
> +
> + ret = btmtk_main_send_cmd(bdev, image, sent_len + PATCH_HEADER_SIZE,
> + event, event_len, delay, retry,
> + BTMTK_TX_ACL_FROM_DRV);
> + if (ret < 0) {
> + BTMTK_INFO("%s: send patch failed, terminate", __func__);
> + goto exit;
> + }
> + } else {
> + break;
> + }
> + }
> +
> +exit:
> + return ret;
> +}
> +
> +static int btmtk_send_fw_rom_patch_79xx(struct btmtk_dev *bdev,
> + u8 *fwbuf, bool patch_flag)
> +{
> + u8 *pos;
> + int loop_count = 0;
> + int ret = 0;
> + u32 section_num = 0;
> + u32 section_offset = 0;
> + u32 dl_size = 0;
> + int patch_status = 0;
> + int retry = 20;
> + u8 dma_flag = PATCH_DOWNLOAD_USING_WMT;
> + struct _SECTION_MAP *sectionmap;
> + struct _GLOBAL_DESCR *globaldescr;
> + u8 event[] = {0x04, 0xE4, 0x05, 0x02, 0x01, 0x01, 0x00, 0x00}; /* event[7] is status*/
> +
> + if (!fwbuf) {
> + BTMTK_WARN("%s, fwbuf is NULL!", __func__);
> + ret = -1;
> + goto exit;
> + }
> +
> + globaldescr = (struct _GLOBAL_DESCR *)(fwbuf + FW_ROM_PATCH_HEADER_SIZE);
> +
> + BTMTK_INFO("%s: loading rom patch...\n", __func__);
> +
> + if (patch_flag)
> + section_num = be2cpu32(globaldescr->u4sectionnum);
> + else
> + section_num = globaldescr->u4sectionnum;
> + BTMTK_INFO("%s: section_num = 0x%08x\n", __func__, section_num);
> +
> + pos = kmalloc(UPLOAD_PATCH_UNIT, GFP_ATOMIC);
> + if (!pos) {
> + BTMTK_ERR("%s: alloc memory failed", __func__);
> + goto exit;
> + }
> +
> + do {
> + sectionmap = (struct _SECTION_MAP *)(fwbuf + FW_ROM_PATCH_HEADER_SIZE +
> + FW_ROM_PATCH_GD_SIZE + FW_ROM_PATCH_SEC_MAP_SIZE * loop_count);
> + dma_flag = PATCH_DOWNLOAD_USING_WMT;
> + if (patch_flag) {
> + /* wifi is big-endian */
> + section_offset = be2cpu32(sectionmap->u4secoffset);
> + dl_size = be2cpu32(sectionmap->bin_info_spec.u4dlsize);
> + dma_flag = be2cpu32(sectionmap->bin_info_spec.u4dlmodecrctype) & 0xFF;
> + } else {
> + /* BT is little-endian */
> + section_offset = sectionmap->u4secoffset;
> + dl_size = sectionmap->bin_info_spec.u4dlsize;
> + /*
> + * loop_count = 0: BGF patch
> + * 1: BT ILM
> + * only BT ILM support DL DMA for Buzzard
> + */
> + dma_flag = le2cpu32(sectionmap->bin_info_spec.u4dlmodecrctype) & 0xFF;
> + }
> + BTMTK_INFO("%s:loop=%d, sec_offset=0x%08x, dl patch_len=0x%08x, dl mode=%d",
> + __func__, loop_count, section_offset, dl_size, dma_flag);
> + if (dl_size > 0) {
> + retry = 20;
> + do {
> + patch_status = btmtk_send_wmt_download_cmd(bdev, pos, 0,
> + event, sizeof(event) - 1,
> + sectionmap, 0, dma_flag,
> + patch_flag);
> + BTMTK_INFO("%s: patch_status %d", __func__, patch_status);
> +
> + if (patch_status > PATCH_READY || patch_status == PATCH_ERR) {
> + BTMTK_ERR("%s: patch_status error", __func__);
> + ret = -1;
> + goto err;
> + } else if (patch_status == PATCH_READY) {
> + BTMTK_INFO("%s: no need to load rom patch section%d",
> + __func__, loop_count);
> + goto next_section;
> + } else if (patch_status == PATCH_IS_DOWNLOAD_BY_OTHER) {
> + msleep(100);
> + retry--;
> + } else if (patch_status == PATCH_NEED_DOWNLOAD) {
> + break; /* Download ROM patch directly */
> + }
> + } while (retry > 0);
> +
> + if (patch_status == PATCH_IS_DOWNLOAD_BY_OTHER) {
> + BTMTK_WARN("%s: Hold by another fun more than 2 seconds", __func__);
> + ret = -1;
> + goto err;
> + }
> +
> + if (dma_flag == PATCH_DOWNLOAD_USING_DMA && main_info.hif_hook.dl_dma) {
> + /* using DMA to download fw patch*/
> + ret = main_info.hif_hook.dl_dma(bdev,
> + pos, fwbuf,
> + dl_size, section_offset);
> + if (ret < 0) {
> + BTMTK_ERR("%s: dl using dma failed!", __func__);
> + goto err;
> + }
> + } else {
> + /* using legacy wmt cmd to download fw patch */
> + ret = btmtk_load_fw_patch_using_wmt_cmd(bdev, pos, fwbuf, event,
> + sizeof(event) - 1,
> + dl_size, section_offset);
> + if (ret < 0) {
> + BTMTK_ERR("%s: dl using wmt cmd failed!", __func__);
> + goto err;
> + }
> + }
> + }
> +next_section:
> + continue;
> + } while (++loop_count < section_num);
> +
> +err:
> + kfree(pos);
> + pos = NULL;
> +
> +exit:
> + return ret;
> +}
> +
> +int btmtk_load_rom_patch_79xx(struct btmtk_dev *bdev, bool patch_flag)
> +{
> + int ret = 0;
> + const struct firmware *fw_firmware = NULL;
> + u8 *rom_patch = NULL;
> + unsigned int rom_patch_len = 0;
> +
> + BTMTK_ERR("%s, patch_flag = %d!", __func__, patch_flag);
> +
> + if (!bdev) {
> + BTMTK_ERR("%s, invalid parameters!", __func__);
> + return -EINVAL;
> + }
> +
> + if (patch_flag) {
> + if (bdev->flavor)
> + /* if flavor equals 1, it represent 7920, else it represent 7921*/
> + snprintf(bdev->rom_patch_bin_file_name, MAX_BIN_FILE_NAME_LEN,
> + "WIFI_MT%04x_patch_mcu_1a_%x_hdr.bin",
> + bdev->chip_id & 0xffff, (bdev->fw_version & 0xff) + 1);
> + else
> + snprintf(bdev->rom_patch_bin_file_name, MAX_BIN_FILE_NAME_LEN,
> + "WIFI_MT%04x_patch_mcu_1_%x_hdr.bin",
> + bdev->chip_id & 0xffff, (bdev->fw_version & 0xff) + 1);
> + }
> +
> + btmtk_load_code_from_bin(&fw_firmware, bdev->rom_patch_bin_file_name, NULL,
> + &rom_patch, &rom_patch_len);
> +
> + if (!rom_patch) {
> + BTMTK_ERR("%s: please assign a rom patch(/etc/firmware/%s)or(/lib/firmware/%s)",
> + __func__, bdev->rom_patch_bin_file_name, bdev->rom_patch_bin_file_name);
> + ret = -1;
> + goto err;
> + }
> +
> + if (patch_flag)
> + /*Display rom patch info*/
> + btmtk_print_wifi_patch_info(bdev, rom_patch);
> + else
> + btmtk_print_bt_patch_info(bdev, rom_patch);
> +
> + ret = btmtk_send_fw_rom_patch_79xx(bdev, rom_patch, patch_flag);
> + if (ret < 0) {
> + BTMTK_ERR("%s, btmtk_send_fw_rom_patch_79xx failed!", __func__);
> + goto err;
> + }
> +
> + bdev->power_state = BTMTK_DONGLE_STATE_POWER_OFF;
> + BTMTK_INFO("%s end", __func__);
> +
> +err:
> + if (fw_firmware)
> + release_firmware(fw_firmware);
> + return ret;
> +}
> +
> +int btmtk_load_rom_patch(struct btmtk_dev *bdev)
> +{
> + int err = -1;
> +
> + if (!bdev || !bdev->hdev) {
> + BTMTK_ERR("%s: invalid parameters!", __func__);
> + return err;
> + }
> +
> + if (is_mt7922(bdev->chip_id) || is_mt7961(bdev->chip_id)) {
> + err = btmtk_load_rom_patch_79xx(bdev, BT_DOWNLOAD);
> + if (err < 0) {
> + BTMTK_ERR("%s: btmtk_load_rom_patch_79xx bt patch failed!", __func__);
> + return err;
> + }
> +
> + err = btmtk_load_rom_patch_79xx(bdev, WIFI_DOWNLOAD);
> + if (err < 0) {
> + BTMTK_WARN("%s: btmtk_load_rom_patch_79xx wifi patch failed!", __func__);
> + err = 0;
> + }
> + } else {
> + BTMTK_WARN("%s: unknown chip id (%d)", __func__, bdev->chip_id);
> + }
> +
> + return err;
> +}
> +
> +struct btmtk_dev *btmtk_get_dev(void)
> +{
> + int i = 0;
> + struct btmtk_dev *tmp_bdev = NULL;
> +
> + BTMTK_INFO("%s", __func__);
> +
> + for (i = 0; i < btmtk_intf_num; i++) {
> + if (!g_bdev[i]->hdev) {
> + if (i == 0)
> + g_bdev[i]->dongle_index = i;
> + else
> + g_bdev[i]->dongle_index = g_bdev[i - 1]->dongle_index + 1;
> +
> + tmp_bdev = g_bdev[i];
> +
> + /* Hook pre-defined table on state machine */
> + g_bdev[i]->cif_state = (struct btmtk_cif_state *)g_cif_state;
> + break;
> + }
> + }
> +
> + return tmp_bdev;
> +}
> +
> +void btmtk_release_dev(struct btmtk_dev *bdev)
> +{
> + int i = 0;
> + struct btmtk_dev *tmp_bdev = NULL;
> +
> + tmp_bdev = bdev;
> + if (!tmp_bdev) {
> + for (i = 0; i < btmtk_intf_num; i++) {
> + if (memcmp(tmp_bdev, g_bdev[i], sizeof(*tmp_bdev)) == 0) {
> + memset(tmp_bdev, 0, sizeof(*tmp_bdev));
> +
> + tmp_bdev = NULL;
> + break;
> + }
> + }
> + }
> +}
> +
> +struct btmtk_dev *btmtk_allocate_dev_memory(struct device *dev)
> +{
> + struct btmtk_dev *bdev;
> + size_t len = sizeof(*bdev);
> +
> + if (!dev)
> + bdev = devm_kzalloc(dev, len, GFP_KERNEL);
> + else
> + bdev = kzalloc(len, GFP_KERNEL);
> +
> + if (!bdev)
> + return NULL;
> +
> + btmtk_set_chip_state(bdev, BTMTK_STATE_INIT);
> +
> + return bdev;
> +}
> +
> +void btmtk_free_dev_memory(struct device *dev, struct btmtk_dev *bdev)
> +{
> + if (!bdev) {
> + if (!dev)
> + devm_kfree(dev, bdev);
> + else
> + kfree(bdev);
> + }
> +}
> +
> +int btmtk_send_wmt_power_on_cmd(struct btmtk_dev *bdev)
> +{
> + /* Support 7668 and 7961 */
> + u8 cmd[] = { 0x01, 0x6F, 0xFC, 0x06, 0x01, 0x06, 0x02, 0x00, 0x00, 0x01 };
> + u8 event[] = { 0x04, 0xE4, 0x05, 0x02, 0x06, 0x01, 0x00 };
> + int ret = -1, retry = RETRY_TIMES;
> +
> + if (!bdev) {
> + BTMTK_ERR("%s: bdev is NULL !", __func__);
> + return ret;
> + }
> +
> +retry_again:
> +
> + ret = btmtk_main_send_cmd(bdev, cmd, sizeof(cmd), event, sizeof(event),
> + WMT_DELAY_TIMES, RETRY_TIMES, BTMTK_TX_CMD_FROM_DRV);
> + if (ret < 0) {
> + BTMTK_ERR("%s: failed(%d)", __func__, ret);
> + bdev->power_state = BTMTK_DONGLE_STATE_ERROR;
> + ret = -1;
> + } else if (ret == 0 && bdev->recv_evt_len > 0) {
> + switch (bdev->io_buf[6]) {
> + case 0: /* successful */
> + BTMTK_INFO("%s: OK", __func__);
> + bdev->power_state = BTMTK_DONGLE_STATE_POWER_ON;
> + break;
> + case 2: /* TODO:retry */
> + if (retry > 0) {
> + retry--;
> + BTMTK_INFO("%s: need to try again", __func__);
> + mdelay(50);
> + goto retry_again;
> + }
> + break;
> + default:
> + BTMTK_WARN("%s: Unknown result: %02X", __func__, bdev->io_buf[6]);
> + bdev->power_state = BTMTK_DONGLE_STATE_ERROR;
> + ret = -1;
> + break;
> + }
> + }
> +
> + return ret;
> +}
> +
> +int btmtk_send_wmt_power_off_cmd(struct btmtk_dev *bdev)
> +{
> + /* Support 7668 and 7961 */
> + u8 cmd[] = { 0x01, 0x6F, 0xFC, 0x06, 0x01, 0x06, 0x02, 0x00, 0x00, 0x00 };
> + /* To-Do, for event check */
> + u8 event[] = { 0x04, 0xE4, 0x05, 0x02, 0x06, 0x01, 0x00 };
> + int ret = -1;
> +
> + if (!bdev) {
> + BTMTK_ERR("%s: bdev is NULL !", __func__);
> + return ret;
> + }
> +
> + if (bdev->power_state == BTMTK_DONGLE_STATE_POWER_OFF) {
> + BTMTK_WARN("%s: power_state already power off", __func__);
> + return 0;
> + }
> +
> + ret = btmtk_main_send_cmd(bdev, cmd, sizeof(cmd), event, sizeof(event),
> + DELAY_TIMES, RETRY_TIMES, BTMTK_TX_CMD_FROM_DRV);
> + if (ret < 0) {
> + BTMTK_ERR("%s: failed(%d)", __func__, ret);
> + bdev->power_state = BTMTK_DONGLE_STATE_ERROR;
> + return ret;
> + }
> +
> + bdev->power_state = BTMTK_DONGLE_STATE_POWER_OFF;
> + BTMTK_INFO("%s done", __func__);
> + return ret;
> +}
> +
> +int btmtk_cap_init(struct btmtk_dev *bdev)
> +{
> + if (!bdev) {
> + BTMTK_ERR("%s, bdev is NULL!", __func__);
> + return -1;
> + }
> +
> + main_info.hif_hook.reg_read(bdev, CHIP_ID, &bdev->chip_id);
> + if (is_mt7922(bdev->chip_id) || is_mt7961(bdev->chip_id)) {
> + main_info.hif_hook.reg_read(bdev, FLAVOR, &bdev->flavor);
> + main_info.hif_hook.reg_read(bdev, FW_VERSION, &bdev->fw_version);
> + } else {
> + BTMTK_ERR("Unknown Mediatek device(%04X)\n", bdev->chip_id);
> + return -1;
> + }
> +
> + BTMTK_INFO("%s: Chip ID = 0x%x", __func__, bdev->chip_id);
> + BTMTK_INFO("%s: flavor = 0x%x", __func__, bdev->flavor);
> + BTMTK_INFO("%s: FW Ver = 0x%x", __func__, bdev->fw_version);
> +
> + memset(bdev->rom_patch_bin_file_name, 0, MAX_BIN_FILE_NAME_LEN);
> + if ((bdev->fw_version & 0xff) == 0xff) {
> + BTMTK_ERR("%s: failed, wrong FW version : 0x%x !", __func__, bdev->fw_version);
> + return -1;
> + }
> +
> + /* Bin filename format : "BT_RAM_CODE_MT%04x_%x_%x_hdr.bin"
> + * $$$$ : chip id
> + * % : fw version & 0xFF + 1 (in HEX)
> + */
> + bdev->flavor = (bdev->flavor & 0x00000080) >> 7;
> + BTMTK_INFO("%s: flavor1 = 0x%x", __func__, bdev->flavor);
> +
> + /* if flavor equals 1, it represent 7920, else it represent 7921 */
> + if (bdev->flavor)
> + snprintf(bdev->rom_patch_bin_file_name, MAX_BIN_FILE_NAME_LEN,
> + "BT_RAM_CODE_MT%04x_1a_%x_hdr.bin",
> + bdev->chip_id & 0xffff, (bdev->fw_version & 0xff) + 1);
> + else
> + snprintf(bdev->rom_patch_bin_file_name, MAX_BIN_FILE_NAME_LEN,
> + "BT_RAM_CODE_MT%04x_1_%x_hdr.bin",
> + bdev->chip_id & 0xffff, (bdev->fw_version & 0xff) + 1);
> +
> + BTMTK_INFO("%s: rom patch file name is %s", __func__, bdev->rom_patch_bin_file_name);
> +
> + return 0;
> +}
> +
> +int btmtk_send_init_cmds(struct btmtk_dev *bdev)
> +{
> + int ret = -1;
> +
> + if (!bdev) {
> + BTMTK_ERR("%s: bdev is NULL !", __func__);
> + goto exit;
> + }
> +
> + BTMTK_INFO("%s", __func__);
> +
> + ret = btmtk_send_wmt_power_on_cmd(bdev);
> + if (ret < 0) {
> + if (bdev->power_state != BTMTK_DONGLE_STATE_POWER_ON)
> + BTMTK_ERR("%s, btmtk_send_wmt_power_on_cmd failed!", __func__);
> + goto exit;
> + }
> +
> +exit:
> + return ret;
> +}
> +
> +int btmtk_send_deinit_cmds(struct btmtk_dev *bdev)
> +{
> + int ret = -1;
> +
> + if (!bdev) {
> + BTMTK_ERR("%s: bdev is NULL !", __func__);
> + return ret;
> + }
> +
> + BTMTK_INFO("%s", __func__);
> +
> + ret = btmtk_send_wmt_power_off_cmd(bdev);
> + if (bdev->power_state != BTMTK_DONGLE_STATE_POWER_OFF) {
> + BTMTK_WARN("Power off failed, reset it");
> + btmtk_send_assert_cmd(bdev);
> + }
> +
> + return ret;
> +}
> +
> +int btmtk_send_assert_cmd(struct btmtk_dev *bdev)
> +{
> + int ret = 0;
> + int state;
> + u8 buf[] = { 0x01, 0x6F, 0xFC, 0x05, 0x01, 0x02, 0x01, 0x00, 0x08 };
> + struct sk_buff *skb = NULL;
> +
> + if (!bdev) {
> + BTMTK_ERR("%s, invalid parameters!", __func__);
> + ret = -EINVAL;
> + goto exit;
> + }
> +
> + state = btmtk_get_chip_state(bdev);
> + if (state == BTMTK_STATE_FW_DUMP) {
> + BTMTK_WARN("%s: FW dumping already!!!", __func__);
> + return ret;
> + }
> +
> + BTMTK_INFO("%s: send assert cmd", __func__);
> +
> + skb = alloc_skb(sizeof(buf) + BT_SKB_RESERVE, GFP_ATOMIC);
> + if (!skb) {
> + BTMTK_ERR("%s allocate skb failed!!", __func__);
> + goto exit;
> + }
> + bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
> + memcpy(skb->data, buf, sizeof(buf));
> + skb->len = sizeof(buf);
> +
> + ret = main_info.hif_hook.send_cmd(bdev, skb, 100, 20, (int)BTMTK_TX_CMD_FROM_DRV);
> + if (ret < 0)
> + BTMTK_ERR("%s failed!!", __func__);
> + else
> + BTMTK_INFO("%s: OK", __func__);
> +
> +exit:
> + return ret;
> +}
> +
> +static int bt_flush(struct hci_dev *hdev)
> +{
> + return 0;
> +}
Please follow the naming convention for the HCI ops callbacks. See the two other MTK drivers.
> +
> +static int bt_close(struct hci_dev *hdev)
> +{
> + int ret = -1;
> + int state = BTMTK_STATE_INIT;
> + int fstate = BTMTK_FOPS_STATE_INIT;
> + struct btmtk_dev *bdev = NULL;
> +
> + if (!hdev) {
> + BTMTK_ERR("%s: invalid parameters!", __func__);
> + return ret;
> + }
> +
> + bdev = hci_get_drvdata(hdev);
> + if (!bdev) {
> + BTMTK_ERR("%s: bdev is invalid!", __func__);
> + return ret;
> + }
> +
> + fstate = btmtk_fops_get_state(bdev);
> + if (fstate != BTMTK_FOPS_STATE_OPENED) {
> + BTMTK_WARN("%s: fops is not allow close(%d)", __func__, fstate);
> + goto err;
> + }
> + btmtk_fops_set_state(bdev, BTMTK_FOPS_STATE_CLOSING);
> +
> + state = btmtk_get_chip_state(bdev);
> + if (state != BTMTK_STATE_WORKING && state != BTMTK_STATE_STANDBY) {
> + BTMTK_WARN("%s: not in working state and standby state(%d).", __func__, state);
> + goto exit;
> + }
> +
> + BTMTK_INFO("%s, enter", __func__);
> +
> + if (main_info.hif_hook.cif_mutex_lock)
> + main_info.hif_hook.cif_mutex_lock(bdev);
> +
> + if (state != BTMTK_STATE_STANDBY) {
> + ret = btmtk_send_deinit_cmds(bdev);
> + if (ret < 0) {
> + BTMTK_ERR("%s, btmtk_send_deinit_cmds failed", __func__);
> + goto unlock;
> + }
> + }
> +
> + /* Flush RX works */
> + flush_work(&bdev->rx_work);
> +
> + /* Drop queues */
> + skb_queue_purge(&bdev->rx_q);
> +
> + main_info.hif_hook.close(hdev);
> +
> +unlock:
> + if (main_info.hif_hook.cif_mutex_unlock)
> + main_info.hif_hook.cif_mutex_unlock(bdev);
> +exit:
> + btmtk_fops_set_state(bdev, BTMTK_FOPS_STATE_CLOSED);
> +
> +err:
> + return 0;
> +}
> +
> +static int bt_open(struct hci_dev *hdev)
> +{
> + int ret = -1;
> + int state = BTMTK_STATE_INIT;
> + int fstate = BTMTK_FOPS_STATE_INIT;
> + struct btmtk_dev *bdev = NULL;
> +
> + BTMTK_INFO("%s: MTK BT Driver Version : %s", __func__, VERSION);
> +
> + if (!hdev) {
> + BTMTK_ERR("%s: invalid parameters!", __func__);
> + return -EFAULT;
> + }
> +
> + bdev = hci_get_drvdata(hdev);
> + if (!bdev) {
> + BTMTK_ERR("%s: bdev is invalid", __func__);
> + return -EFAULT;
> + }
> +
> + state = btmtk_get_chip_state(bdev);
> + if (state == BTMTK_STATE_INIT || state == BTMTK_STATE_DISCONNECT) {
> + ret = -EAGAIN;
> + goto failed;
> + }
> +
> + if (state != BTMTK_STATE_WORKING && state != BTMTK_STATE_STANDBY) {
> + BTMTK_WARN("%s: not in working state and standby state(%d).", __func__, state);
> + ret = -ENODEV;
> + goto failed;
> + }
> +
> + fstate = btmtk_fops_get_state(bdev);
> + if (fstate == BTMTK_FOPS_STATE_OPENED) {
> + BTMTK_WARN("%s: fops opened!", __func__);
> + ret = 0;
> + goto failed;
> + } else if ((fstate == BTMTK_FOPS_STATE_CLOSING) ||
> + (fstate == BTMTK_FOPS_STATE_OPENING)) {
> + BTMTK_WARN("%s: fops open/close is on-going !", __func__);
> + ret = -EAGAIN;
> + goto failed;
> + }
> +
> + BTMTK_INFO("%s", __func__);
> + btmtk_fops_set_state(bdev, BTMTK_FOPS_STATE_OPENING);
> + ret = main_info.hif_hook.open(hdev);
> + if (ret < 0) {
> + BTMTK_ERR("%s, cif_open failed", __func__);
> + goto failed;
> + }
> +
> + ret = btmtk_send_init_cmds(bdev);
> + if (ret < 0) {
> + BTMTK_ERR("%s, btmtk_send_init_cmds failed", __func__);
> + goto failed;
> + }
> +
> + if (main_info.hif_hook.open_done)
> + main_info.hif_hook.open_done(bdev);
> +
> + btmtk_fops_set_state(bdev, BTMTK_FOPS_STATE_OPENED);
> +
> + return 0;
> +
> +failed:
> + btmtk_fops_set_state(bdev, BTMTK_FOPS_STATE_CLOSED);
> +
> + return ret;
> +}
> +
> +static int bt_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
> +{
> + int ret = -1;
> + int state = BTMTK_STATE_INIT;
> + int fstate = BTMTK_FOPS_STATE_INIT;
> + struct btmtk_dev *bdev = NULL;
> +
> + if (!hdev || !skb) {
> + BTMTK_ERR("%s, invalid parameters!", __func__);
> + return -ENODEV;
> + }
> +
> + bdev = hci_get_drvdata(hdev);
> + if (!bdev) {
> + BTMTK_ERR("%s, bdev is invalid!", __func__);
> + return -ENODEV;
> + }
> +
> + fstate = btmtk_fops_get_state(bdev);
> + if (fstate != BTMTK_FOPS_STATE_OPENED) {
> + BTMTK_WARN("%s: fops is not open yet(%d)!", __func__, fstate);
> + ret = -ENODEV;
> + goto exit;
> + }
> +
> + state = btmtk_get_chip_state(bdev);
> + if (state != BTMTK_STATE_WORKING) {
> + BTMTK_WARN("%s: chip state is %d.", __func__, state);
> + if (state == BTMTK_STATE_DISCONNECT) {
> + ret = -ENODEV;
> + } else {
> + msleep(3000);
> + ret = -EAGAIN;
> + }
> + goto exit;
> + }
> +
> + if (bdev->power_state == BTMTK_DONGLE_STATE_POWER_OFF) {
> + BTMTK_WARN("%s: dongle state already power off, do not write", __func__);
> + ret = -EFAULT;
> + goto exit;
> + }
> +
> + memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
> +
> + /* For Ble ISO packet size */
> + if (memcmp(skb->data, READ_ISO_PACKET_SIZE_CMD, sizeof(READ_ISO_PACKET_SIZE_CMD)) == 0) {
> + bdev->iso_threshold = skb->data[sizeof(READ_ISO_PACKET_SIZE_CMD)] +
> + (skb->data[sizeof(READ_ISO_PACKET_SIZE_CMD) + 1] << 8);
> + BTMTK_INFO("%s: Ble iso pkt size is %d", __func__, bdev->iso_threshold);
> + }
> +
> + ret = main_info.hif_hook.send_cmd(bdev, skb, 0, 0, (int)BTMTK_TX_PKT_FROM_HOST);
> + if (ret < 0)
> + BTMTK_ERR("%s failed!!", __func__);
> +exit:
> + return ret;
> +}
> +
> +static int bt_setup(struct hci_dev *hdev)
> +{
> + BTMTK_INFO("%s", __func__);
> + return 0;
> +}
> +
> +void btmtk_reg_hif_hook(struct hif_hook_ptr *hook)
> +{
> + memcpy(&main_info.hif_hook, hook, sizeof(struct hif_hook_ptr));
> +}
> +
> +static void btmtk_rx_work(struct work_struct *work)
> +{
> + int err = 0, skip_pkt = 0;
> + struct btmtk_dev *bdev = container_of(work, struct btmtk_dev, rx_work);
> + struct sk_buff *skb;
> + int fstate = BTMTK_FOPS_STATE_INIT;
> + int state = 0;
> +
> + BTMTK_DBG("%s enter", __func__);
> +
> + while ((skb = skb_dequeue(&bdev->rx_q))) {
> + skip_pkt = btmtk_dispatch_pkt(bdev->hdev, skb);
> + if (skip_pkt != 0) {
> + kfree_skb(skb);
> + continue;
> + }
> +
> + if (hci_skb_pkt_type(skb) == HCI_EVENT_PKT) {
> + if (main_info.hif_hook.event_filter(bdev, skb)) {
> + kfree_skb(skb);
> + continue;
> + }
> + }
> +
> + fstate = btmtk_fops_get_state(bdev);
> + if (fstate != BTMTK_FOPS_STATE_OPENED) {
> + kfree_skb(skb);
> + continue;
> + }
> +
> + state = btmtk_get_chip_state(bdev);
> + if (state != BTMTK_STATE_WORKING) {
> + kfree_skb(skb);
> + continue;
> + }
> +
> + err = hci_recv_frame(bdev->hdev, skb);
> + if (err < 0) {
> + if (err != -ENXIO)
> + BTMTK_ERR("%s failed, err = %d", __func__, err);
> + return;
> + }
> + }
> +}
> +
> +void btmtk_free_hci_device(struct btmtk_dev *bdev, int hci_bus_type)
> +{
> + if (!bdev)
> + return;
> +
> + flush_work(&bdev->rx_work);
> +
> + skb_queue_purge(&bdev->rx_q);
> + destroy_workqueue(bdev->workqueue);
> +
> + BTMTK_INFO("%s", __func__);
> +
> + if (bdev->hdev)
> + hci_free_dev(bdev->hdev);
> +
> + bdev->chip_reset = 0;
> + BTMTK_INFO("%s done", __func__);
> +}
> +
> +int btmtk_allocate_hci_device(struct btmtk_dev *bdev, int hci_bus_type)
> +{
> + struct hci_dev *hdev;
> + int err = 0;
> +
> + if (!bdev) {
> + BTMTK_ERR("%s, bdev is NULL!", __func__);
> + err = -EINVAL;
> + goto exit;
> + }
> +
> + BTMTK_INFO("%s", __func__);
> + hdev = hci_alloc_dev();
> + if (!hdev) {
> + BTMTK_ERR("%s, hdev is NULL!", __func__);
> + err = -ENOMEM;
> + goto exit;
> + }
> +
> + hdev->bus = hci_bus_type;
> + hci_set_drvdata(hdev, bdev);
> +
> + hdev->dev_type = 0x00;
> +
> + bdev->hdev = hdev;
> +
> + hdev->open = bt_open;
> + hdev->close = bt_close;
> + hdev->flush = bt_flush;
> + hdev->send = bt_send_frame;
> + hdev->setup = bt_setup;
> +
> + INIT_WORK(&bdev->rx_work, btmtk_rx_work);
> +
> + init_waitqueue_head(&bdev->p_wait_event_q);
> +
> + skb_queue_head_init(&bdev->rx_q);
> +
> + bdev->workqueue = alloc_workqueue("BTMTK_RX_WQ", WQ_HIGHPRI | WQ_UNBOUND |
> + WQ_MEM_RECLAIM, 1);
> + if (!bdev->workqueue) {
> + BTMTK_ERR("%s, bdev->workqueue is NULL!", __func__);
> + err = -ENOMEM;
> + goto exit;
> + }
> +
> + BTMTK_INFO("%s done", __func__);
> +
> +exit:
> + return err;
> +}
> +
> +int btmtk_register_hci_device(struct btmtk_dev *bdev)
> +{
> + struct hci_dev *hdev;
> + int err = 0;
> +
> + hdev = bdev->hdev;
> +
> + err = hci_register_dev(hdev);
> + if (err < 0) {
> + BTMTK_INFO("%s can't register", __func__);
> + hci_free_dev(hdev);
> + goto exit;
> + }
> +
> + test_and_clear_bit(HCI_SETUP, &hdev->dev_flags);
> +
> +exit:
> + return err;
> +}
> +
> +int btmtk_deregister_hci_device(struct btmtk_dev *bdev)
> +{
> + int err = 0;
> +
> + if (bdev && bdev->hdev)
> + hci_unregister_dev(bdev->hdev);
> +
> + return err;
> +}
Please avoid any of these abstractions.
> +
> +static int btmtk_main_allocate_memory(struct btmtk_dev *bdev)
> +{
> + BTMTK_INFO("%s", __func__);
> +
> + if (!bdev->rom_patch_bin_file_name) {
> + bdev->rom_patch_bin_file_name = kzalloc(MAX_BIN_FILE_NAME_LEN, GFP_KERNEL);
> + if (!bdev->rom_patch_bin_file_name) {
> + BTMTK_ERR("%s: alloc memory fail rom_patch_bin_file_name", __func__);
> + return -ENOMEM;
> + }
> + }
> +
> + if (!bdev->io_buf) {
> + bdev->io_buf = kzalloc(IO_BUF_SIZE, GFP_KERNEL);
> + if (!bdev->io_buf) {
> + BTMTK_ERR("%s: alloc memory fail io_buf", __func__);
> + return -ENOMEM;
> + }
> + }
> +
> + BTMTK_INFO("%s: Done", __func__);
> + return 0;
> +}
> +
> +static void btmtk_main_free_memory(struct btmtk_dev *bdev)
> +{
> + kfree(bdev->rom_patch_bin_file_name);
> + bdev->rom_patch_bin_file_name = NULL;
> +
> + kfree(bdev->io_buf);
> + bdev->io_buf = NULL;
> +
> + BTMTK_INFO("%s: Success", __func__);
> +}
> +
> +int btmtk_main_cif_initialize(struct btmtk_dev *bdev, int hci_bus)
> +{
> + int err = 0;
> +
> + err = btmtk_main_allocate_memory(bdev);
> + if (err < 0) {
> + BTMTK_ERR("btmtk_main_allocate_memory failed!");
> + goto end;
> + }
> +
> + err = btmtk_allocate_hci_device(bdev, hci_bus);
> + if (err < 0) {
> + BTMTK_ERR("btmtk_allocate_hci_device failed!");
> + goto free_mem;
> + }
> +
> + err = btmtk_cap_init(bdev);
> + if (err < 0) {
> + BTMTK_ERR("btmtk_cap_init failed!");
> + goto free_hci_dev;
> + }
> +
> + return 0;
> +
> +free_hci_dev:
> + btmtk_free_hci_device(bdev, hci_bus);
> +free_mem:
> + btmtk_main_free_memory(bdev);
> +end:
> + return err;
> +}
> +
> +void btmtk_main_cif_uninitialize(struct btmtk_dev *bdev, int hci_bus)
> +{
> + btmtk_free_hci_device(bdev, hci_bus);
> + btmtk_main_free_memory(bdev);
> +}
> +
> +int btmtk_main_cif_disconnect_notify(struct btmtk_dev *bdev, int hci_bus)
> +{
> + btmtk_deregister_hci_device(bdev);
> + btmtk_free_hci_device(bdev, hci_bus);
> +
> + bdev->power_state = BTMTK_DONGLE_STATE_POWER_OFF;
> + btmtk_release_dev(bdev);
> +
> + return 0;
> +}
> +
> +/**
> + * Kernel Module init/exit Functions
> + */
> +static int __init main_driver_init(void)
> +{
> + int ret = 0;
> + int i;
> +
> + /* Mediatek Driver Version */
> + BTMTK_INFO("%s: MTK BT Driver Version : %s", __func__, VERSION);
> +
> + ret = main_init();
> + if (ret < 0)
> + return ret;
> +
> + for (i = 0; i < btmtk_intf_num; i++)
> + btmtk_set_chip_state(g_bdev[i], BTMTK_STATE_DISCONNECT);
> +
> + ret = btmtk_cif_register();
> + if (ret < 0) {
> + BTMTK_ERR("*** USB registration failed(%d)! ***", ret);
> + main_exit();
> + return ret;
> + }
> +
> + BTMTK_INFO("%s: Done", __func__);
> + return ret;
> +}
NO. Period. Use module_usb_driver() and if you need anything more, you are doing something wrong.
> +
> +static void __exit main_driver_exit(void)
> +{
> + BTMTK_INFO("%s", __func__);
> + btmtk_cif_deregister();
> + main_exit();
> +}
> +module_init(main_driver_init);
> +module_exit(main_driver_exit);
> +
> +/**
> + * Module Common Information
> + */
> +MODULE_DESCRIPTION("Mediatek Bluetooth Driver");
> +MODULE_VERSION(VERSION SUBVER);
> +MODULE_LICENSE("GPL");
> +module_param(btmtk_intf_num, int, 0444);
> diff --git a/drivers/bluetooth/btmtk_main.h b/drivers/bluetooth/btmtk_main.h
> new file mode 100644
> index 000000000000..ce8447ff0484
> --- /dev/null
> +++ b/drivers/bluetooth/btmtk_main.h
> @@ -0,0 +1,578 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +// Copyright (c) 2020 MediaTek Inc.
> +
> +/*
> + * Bluetooth support for MediaTek SDIO/USB/UART devices
> + *
> + */
> +
> +#ifndef __BTMTK_MAIN_H__
> +#define __BTMTK_MAIN_H__
> +#include <linux/version.h>
> +#include <linux/firmware.h>
> +#include <linux/slab.h>
> +#include <linux/module.h>
> +
> +#include <net/bluetooth/bluetooth.h>
> +#include <net/bluetooth/hci_core.h>
> +
> +#include <linux/spinlock.h>
> +#include <linux/kallsyms.h>
> +#include <linux/device.h>
> +#include <asm/unaligned.h>
> +
> +/* Define for proce node */
> +#include <linux/proc_fs.h>
> +#include <linux/seq_file.h>
> +
> +/* Define for whole chip reset */
> +#include <linux/of.h>
> +#include <linux/of_gpio.h>
> +
> +#include <linux/kthread.h>
> +#include <linux/freezer.h>
> +
> +/** Driver version */
> +#define VERSION "7.0.2020110301"
> +#define SUBVER ":turnkey"
> +
> +#define BTMTKUART_RX_STATE_ACTIVE 1
> +#define BTMTKUART_RX_STATE_WAKEUP 2
> +#define BTMTKUART_RX_STATE_RESET 3
> +
> +/**
> + * Maximum rom patch file name length
> + */
> +#define MAX_BIN_FILE_NAME_LEN 64
> +
> +/**
> + * Type definition
> + */
> +#ifndef TRUE
> + #define TRUE 1
> +#endif
> +#ifndef FALSE
> + #define FALSE 0
> +#endif
> +
> +#define MIN(a, b) (((a) < (b)) ? (a) : (b))
> +#define MAX(a, b) (((a) > (b)) ? (a) : (b))
No, no and no. Linux has definitions for this.
> +
> +/**
> + * Log and level definition
> + */
> +#define BTMTK_LOG_LVL_ERR 1
> +#define BTMTK_LOG_LVL_WARN 2
> +#define BTMTK_LOG_LVL_INFO 3
> +#define BTMTK_LOG_LVL_DBG 4
> +#define BTMTK_LOG_LVL_MAX BTMTK_LOG_LVL_DBG
> +#define BTMTK_LOG_LVL_DEF BTMTK_LOG_LVL_INFO /* default setting */
Use bt_dev_{warn,err,info,debug} function.
> +
> +#define HCI_LOG_MAX_BUF_SIZE 66
> +#define WMT_OVER_HCI_HEADER_SIZE 3
> +
> +extern u8 btmtk_log_lvl;
> +
> +#define BTMTK_ERR(fmt, ...) \
> + do { if (btmtk_log_lvl >= BTMTK_LOG_LVL_ERR) \
> + pr_warn("[btmtk_err] ***" fmt"***\n", ##__VA_ARGS__); } while (0)
> +#define BTMTK_WARN(fmt, ...) \
> + do { if (btmtk_log_lvl >= BTMTK_LOG_LVL_WARN) \
> + pr_warn("[btmtk_warn] " fmt"\n", ##__VA_ARGS__); } while (0)
> +#define BTMTK_INFO(fmt, ...) \
> + do { if (btmtk_log_lvl >= BTMTK_LOG_LVL_INFO) \
> + pr_warn("[btmtk_info] " fmt"\n", ##__VA_ARGS__); } while (0)
> +#define BTMTK_DBG(fmt, ...) \
> + do { if (btmtk_log_lvl >= BTMTK_LOG_LVL_DBG) \
> + pr_warn("[btmtk_dbg] " fmt"\n", ##__VA_ARGS__); } while (0)
> +
> +#define BTMTK_INFO_RAW(p, l, fmt, ...) \
> + do { \
> + if (btmtk_log_lvl >= BTMTK_LOG_LVL_INFO) { \
> + int raw_count = 0; \
> + char str[HCI_LOG_MAX_BUF_SIZE * 3 + 1]; \
> + char *p_str = str; \
> + const unsigned char *ptr = p; \
> + pr_warn("[btmtk_info] " fmt, ##__VA_ARGS__); \
> + for (raw_count = 0; raw_count < MIN(l, HCI_LOG_MAX_BUF_SIZE); ++raw_count)\
> + p_str += sprintf(p_str, " %02X", ptr[raw_count]); \
> + *p_str = '\0'; \
> + pr_warn("%s\n", str); \
> + } \
> + } while (0)
> +
> +#define BTMTK_DBG_RAW(p, l, fmt, ...) \
> + do { \
> + if (btmtk_log_lvl >= BTMTK_LOG_LVL_DBG) { \
> + int raw_count = 0; \
> + char str[HCI_LOG_MAX_BUF_SIZE * 3 + 1]; \
> + char *p_str = str; \
> + const unsigned char *ptr = p; \
> + pr_warn("[btmtk_debug] " fmt, ##__VA_ARGS__); \
> + for (raw_count = 0; raw_count < MIN(l, HCI_LOG_MAX_BUF_SIZE); ++raw_count)\
> + p_str += sprintf(p_str, " %02X", ptr[raw_count]); \
> + *p_str = '\0'; \
> + pr_warn("%s\n", str); \
> + } \
> + } while (0)
> +
NO. Period. We have hexdump helpers if this is really wanted. Also use btmon to trace your HCI packets.
> +#define BTMTK_CIF_IS_NULL(bdev, cif_event) \
> + (!bdev || !(&bdev->cif_state[cif_event]))
> +
> +/**
> + *
> + * HCI packet type
> + */
> +#define MTK_HCI_COMMAND_PKT 0x01
> +#define MTK_HCI_ACLDATA_PKT 0x02
> +#define MTK_HCI_SCODATA_PKT 0x03
> +#define MTK_HCI_EVENT_PKT 0x04
> +#define HCI_ISO_PKT 0x05
> +#define HCI_ISO_PKT_HEADER_SIZE 4
> +#define HCI_ISO_PKT_WITH_ACL_HEADER_SIZE 5
NO. Please stop copying defines that are already defined.
> +
> +/**
> + * ROM patch related
> + */
> +#define PATCH_HCI_HEADER_SIZE 4
> +#define PATCH_WMT_HEADER_SIZE 5
> +#define PATCH_HEADER_SIZE (PATCH_HCI_HEADER_SIZE + PATCH_WMT_HEADER_SIZE + 1)
> +
> +#define UPLOAD_PATCH_UNIT 2048
> +#define PATCH_INFO_SIZE 30
> +#define PATCH_PHASE1 1
> +#define PATCH_PHASE2 2
> +#define PATCH_PHASE3 3
> +
> +/* It is for mt7961 download rom patch*/
> +#define FW_ROM_PATCH_HEADER_SIZE 32
> +#define FW_ROM_PATCH_GD_SIZE 64
> +#define FW_ROM_PATCH_SEC_MAP_SIZE 64
> +#define SEC_MAP_NEED_SEND_SIZE 52
> +#define PATCH_STATUS 7
> +
> +#define IO_BUF_SIZE (HCI_MAX_EVENT_SIZE > 256 ? HCI_MAX_EVENT_SIZE : 256)
> +#define EVENT_COMPARE_SIZE 64
> +
> +#define SECTION_SPEC_NUM 13
> +
> +/**
> + * Disable RESUME_RESUME
> + */
> +#ifndef BT_DISABLE_RESET_RESUME
> +#define BT_DISABLE_RESET_RESUME 0
> +#endif
> +
> +#define WIFI_DOWNLOAD TRUE
> +#define BT_DOWNLOAD FALSE
> +
> +#define SWAP32(x)\
> + ((u32)(\
> + (((u32)(x) & (u32)0x000000ffUL) << 24) |\
> + (((u32)(x) & (u32)0x0000ff00UL) << 8) |\
> + (((u32)(x) & (u32)0x00ff0000UL) >> 8) |\
> + (((u32)(x) & (u32)0xff000000UL) >> 24)))
> +
> +/* Endian byte swapping codes */
> +#ifdef __LITTLE_ENDIAN
> +#define cpu2le32(x) ((uint32_t)(x))
> +#define le2cpu32(x) ((uint32_t)(x))
> +#define cpu2be32(x) SWAP32((x))
> +#define be2cpu32(x) SWAP32((x))
> +#else
> +#define cpu2le32(x) SWAP32((x))
> +#define le2cpu32(x) SWAP32((x))
> +#define cpu2be32(x) ((uint32_t)(x))
> +#define be2cpu32(x) ((uint32_t)(x))
> +#endif
NO. Period. We have proper endian functionality.
> +
> +#define FW_VERSION 0x80021004
> +#define CHIP_ID 0x70010200
> +#define FLAVOR 0x70010020
> +#define COMP_EVENT_TIMO 5000
> +
> +#define hci_dev_test_and_clear_flag(hdev, nr) test_and_clear_bit((nr), (hdev)->dev_flags)
> +
> +/* h4_recv */
> +#define hci_skb_pkt_type(skb) bt_cb((skb))->pkt_type
> +#define hci_skb_expect(skb) bt_cb((skb))->expect
> +#define hci_skb_opcode(skb) bt_cb((skb))->hci.opcode
> +
> +/* HCI bus types */
> +#define HCI_VIRTUAL 0
> +#define HCI_USB 1
> +#define HCI_PCCARD 2
> +#define HCI_UART 3
> +#define HCI_RS232 4
> +#define HCI_PCI 5
> +#define HCI_SDIO 6
> +#define HCI_SPI 7
> +#define HCI_I2C 8
> +#define HCI_SMD 9
> +
NO. Period. See comments above.
Frankly it is insulting that I have to review a patch like this. Please do cleanups and not just dump a patch to me that has all these duplicates in there.
> +#define HCI_TYPE_SIZE 1
> +/* this for 79XX need download patch staus
> + * 0:
> + * patch download is not complete, BT driver need to download patch
> + * 1:
> + * patch is downloading by Wifi,BT driver need to retry until status = PATCH_READY
> + * 2:
> + * patch download is complete, BT driver no need to download patch
> + */
> +#define PATCH_ERR -1
> +#define PATCH_NEED_DOWNLOAD 0
> +#define PATCH_IS_DOWNLOAD_BY_OTHER 1
> +#define PATCH_READY 2
> +
> +/* 0:
> + * using legacy wmt cmd/evt to download fw patch, usb/sdio just support 0 now
> + * 1:
> + * using DMA to download fw patch
> + */
> +#define PATCH_DOWNLOAD_USING_WMT 0
> +#define PATCH_DOWNLOAD_USING_DMA 1
> +
> +#define PATCH_DOWNLOAD_PHASE1_2_DELAY_TIME 1
> +#define PATCH_DOWNLOAD_PHASE1_2_RETRY 5
> +#define PATCH_DOWNLOAD_PHASE3_DELAY_TIME 20
> +#define PATCH_DOWNLOAD_PHASE3_RETRY 20
> +
> +/* * delay and retrey for main_send_cmd */
> +#define WMT_DELAY_TIMES 100
> +#define DELAY_TIMES 20
> +#define RETRY_TIMES 20
> +
> +/* Expected minimum supported interface */
> +#define BT_MCU_MINIMUM_INTERFACE_NUM 4
> +
> +/* Bus event */
> +#define HIF_EVENT_PROBE 0
> +#define HIF_EVENT_DISCONNECT 1
> +#define HIF_EVENT_SUSPEND 2
> +#define HIF_EVENT_RESUME 3
> +#define HIF_EVENT_STANDBY 4
> +#define HIF_EVENT_SUBSYS_RESET 5
> +#define HIF_EVENT_WHOLE_CHIP_RESET 6
> +#define HIF_EVENT_FW_DUMP 7
> +
> +#define CHAR2HEX_SIZE 4
> +
> +#define EDR_MIN -32
> +#define EDR_MAX 20
> +#define EDR_MIN_LV9 13
> +#define BLE_MIN -29
> +#define BLE_MAX 20
> +#define EDR_MIN_R1 -64
> +#define EDR_MAX_R1 40
> +#define EDR_MIN_LV9_R1 26
> +#define BLE_MIN_R1 -58
> +#define BLE_MAX_R1 40
> +#define EDR_MIN_R2 -128
> +#define EDR_MAX_R2 80
> +#define EDR_MIN_LV9_R2 52
> +#define BLE_MIN_R2 -116
> +#define BLE_MAX_R2 80
> +
> +#define ERR_PWR -9999
> +
> +enum {
> + RES_1 = 0,
> + RES_DOT_5,
> + RES_DOT_25
> +};
> +
> +enum {
> + CHECK_SINGLE_SKU_PWR_MODE = 0,
> + CHECK_SINGLE_SKU_EDR_MAX,
> + CHECK_SINGLE_SKU_BLE,
> + CHECK_SINGLE_SKU_BLE_2M,
> + CHECK_SINGLE_SKU_BLE_LR_S2,
> + CHECK_SINGLE_SKU_BLE_LR_S8,
> + CHECK_SINGLE_SKU_ALL
> +};
> +
> +struct btmtk_cif_state {
> + unsigned char ops_enter;
> + unsigned char ops_end;
> + unsigned char ops_error;
> +};
> +
> +enum TX_TYPE {
> + BTMTK_TX_CMD_FROM_DRV = 0, /* send hci cmd and wmt cmd by driver */
> + BTMTK_TX_ACL_FROM_DRV, /* send acl pkt with load rompatch by driver */
> + BTMTK_TX_PKT_FROM_HOST, /* send pkt from host, include acl and hci */
> +};
> +
> +enum {
> + BTMTK_DONGLE_STATE_UNKNOWN,
> + BTMTK_DONGLE_STATE_POWER_ON,
> + BTMTK_DONGLE_STATE_POWER_OFF,
> + BTMTK_DONGLE_STATE_ERROR,
> +};
> +
> +enum {
> + HW_ERR_NONE = 0x00,
> + HW_ERR_CODE_CHIP_RESET = 0xF0,
> + HW_ERR_CODE_USB_DISC = 0xF1,
> + HW_ERR_CODE_CORE_DUMP = 0xF2,
> + HW_ERR_CODE_POWER_ON = 0xF3,
> + HW_ERR_CODE_POWER_OFF = 0xF4,
> + HW_ERR_CODE_SET_SLEEP_CMD = 0xF5,
> + HW_ERR_CODE_RESET_STACK_AFTER_WOBLE = 0xF6,
> +};
> +
> +/* Please keep sync with btmtk_set_state function */
> +enum {
> + /* BTMTK_STATE_UNKNOWN = 0, */
> + BTMTK_STATE_INIT = 1,
> + BTMTK_STATE_DISCONNECT,
> + BTMTK_STATE_PROBE,
> + BTMTK_STATE_WORKING,
> + BTMTK_STATE_SUSPEND,
> + BTMTK_STATE_RESUME,
> + BTMTK_STATE_FW_DUMP,
> + BTMTK_STATE_STANDBY,
> + BTMTK_STATE_SUBSYS_RESET,
> +};
> +
> +/* Please keep sync with btmtk_fops_set_state function */
> +enum {
> + /* BTMTK_FOPS_STATE_UNKNOWN = 0, */
> + BTMTK_FOPS_STATE_INIT = 1,
> + BTMTK_FOPS_STATE_OPENING, /* during opening */
> + BTMTK_FOPS_STATE_OPENED, /* open in fops_open */
> + BTMTK_FOPS_STATE_CLOSING, /* during closing */
> + BTMTK_FOPS_STATE_CLOSED, /* closed */
> +};
> +
> +enum {
> + BTMTK_EVENT_COMPARE_STATE_UNKNOWN,
> + BTMTK_EVENT_COMPARE_STATE_NOTHING_NEED_COMPARE,
> + BTMTK_EVENT_COMPARE_STATE_NEED_COMPARE,
> + BTMTK_EVENT_COMPARE_STATE_COMPARE_SUCCESS,
> +};
> +
> +struct h4_recv_pkt {
> + u8 type; /* Packet type */
> + u8 hlen; /* Header length */
> + u8 loff; /* Data length offset in header */
> + u8 lsize; /* Data length field size */
> + u16 maxlen; /* Max overall packet length */
> + int (*recv)(struct hci_dev *hdev, struct sk_buff *skb);
> +};
> +
> +struct _PATCH_HEADER {
> + u8 ucdatetime[16];
> + u8 ucplatform[4];
> + u16 u2hwver;
> + u16 u2swver;
> + u32 u4magicnum;
> +};
> +
> +struct _GLOBAL_DESCR {
> + u32 u4patchver;
> + u32 u4subsys;
> + u32 u4featureopt;
> + u32 u4sectionnum;
> +};
> +
> +struct _SECTION_MAP {
> + u32 u4sectype;
> + u32 u4secoffset;
> + u32 u4secsize;
> + union {
> + u32 u4secspec[SECTION_SPEC_NUM];
> + struct {
> + u32 u4dladdr;
> + u32 u4dlsize;
> + u32 u4seckeyidx;
> + u32 u4alignlen;
> + u32 u4sectype;
> + u32 u4dlmodecrctype;
> + u32 u4crc;
> + u32 reserved[6];
> + } bin_info_spec;
> + };
> +};
> +
> +#define H4_RECV_ACL \
> + .type = HCI_ACLDATA_PKT, \
> + .hlen = HCI_ACL_HDR_SIZE, \
> + .loff = 2, \
> + .lsize = 2, \
> + .maxlen = HCI_MAX_FRAME_SIZE \
> +
> +#define H4_RECV_SCO \
> + .type = HCI_SCODATA_PKT, \
> + .hlen = HCI_SCO_HDR_SIZE, \
> + .loff = 2, \
> + .lsize = 1, \
> + .maxlen = HCI_MAX_SCO_SIZE
> +
> +#define H4_RECV_EVENT \
> + .type = HCI_EVENT_PKT, \
> + .hlen = HCI_EVENT_HDR_SIZE, \
> + .loff = 1, \
> + .lsize = 1, \
> + .maxlen = HCI_MAX_EVENT_SIZE
> +
> +struct btmtk_dev {
> + struct hci_dev *hdev;
> + unsigned long hdev_flags;
> + unsigned long flags;
> + void *intf_dev;
> + void *cif_dev;
> +
> + struct work_struct work;
> + struct work_struct waker;
> + struct work_struct reset_waker;
> +
> + int recv_evt_len;
> + int tx_in_flight;
> + /* for tx skb buffer */
> + spinlock_t txlock;
> + /* for rx skb buffer */
> + spinlock_t rxlock;
> + struct sk_buff *evt_skb;
> + struct sk_buff *sco_skb;
> +
> + /* For ble iso packet size */
> + int iso_threshold;
> +
> + unsigned int sco_num;
> + int isoc_altsetting;
> +
> + int suspend_count;
> +
> + /* For tx queue */
> + unsigned long tx_state;
> +
> + /* For rx queue */
> + struct workqueue_struct *workqueue;
> + struct sk_buff_head rx_q;
> + struct work_struct rx_work;
> + struct sk_buff *rx_skb;
> +
> + wait_queue_head_t p_wait_event_q;
> +
> + unsigned int subsys_reset;
> + unsigned int chip_reset;
> + unsigned char *rom_patch_bin_file_name;
> + unsigned int chip_id;
> + unsigned int flavor;
> + unsigned int fw_version;
> + unsigned char dongle_index;
> + unsigned char power_state;
> + unsigned char fops_state;
> + unsigned char interface_state;
> + struct btmtk_cif_state *cif_state;
> +
> + /* io buffer for usb control transfer */
> + unsigned char *io_buf;
> +};
> +
> +typedef int (*cif_open_ptr)(struct hci_dev *hdev);
> +typedef int (*cif_close_ptr)(struct hci_dev *hdev);
> +typedef int (*cif_reg_read_ptr)(struct btmtk_dev *bdev, u32 reg, u32 *val);
> +typedef int (*cif_reg_write_ptr)(struct btmtk_dev *bdev, u32 reg, u32 val);
> +typedef int (*cif_send_cmd_ptr)(struct btmtk_dev *bdev, struct sk_buff *skb,
> + int delay, int retry, int pkt_type);
> +typedef int (*cif_send_and_recv_ptr)(struct btmtk_dev *bdev,
> + struct sk_buff *skb,
> + const u8 *event, const int event_len,
> + int delay, int retry, int pkt_type);
> +typedef int (*cif_event_filter_ptr)(struct btmtk_dev *bdev, struct sk_buff *skb);
> +typedef int (*cif_subsys_reset_ptr)(struct btmtk_dev *bdev);
> +typedef int (*cif_whole_reset_ptr)(struct btmtk_dev *bdev);
> +typedef void (*cif_chip_reset_notify_ptr)(struct btmtk_dev *bdev);
> +typedef void (*cif_mutex_lock_ptr)(struct btmtk_dev *bdev);
> +typedef void (*cif_mutex_unlock_ptr)(struct btmtk_dev *bdev);
> +typedef void (*cif_open_done_ptr)(struct btmtk_dev *bdev);
> +typedef int (*cif_dl_dma_ptr)(struct btmtk_dev *bdev, u8 *image,
> + u8 *fwbuf, int section_dl_size, int section_offset);
> +
> +struct hif_hook_ptr {
> + cif_open_ptr open;
> + cif_close_ptr close;
> + cif_reg_read_ptr reg_read;
> + cif_reg_write_ptr reg_write;
> + cif_send_cmd_ptr send_cmd;
> + cif_send_and_recv_ptr send_and_recv;
> + cif_event_filter_ptr event_filter;
> + cif_subsys_reset_ptr subsys_reset;
> + cif_whole_reset_ptr whole_reset;
> + cif_chip_reset_notify_ptr chip_reset_notify;
> + cif_mutex_lock_ptr cif_mutex_lock;
> + cif_mutex_unlock_ptr cif_mutex_unlock;
> + cif_open_done_ptr open_done;
> + cif_dl_dma_ptr dl_dma;
> +};
> +
> +struct btmtk_main_info {
> + struct hif_hook_ptr hif_hook;
> +};
> +
> +static inline int is_mt7922(u32 chip_id)
> +{
> + chip_id &= 0xFFFF;
> + if (chip_id == 0x7922)
> + return 1;
> + return 0;
> +}
> +
> +static inline int is_mt7961(u32 chip_id)
> +{
> + chip_id &= 0xFFFF;
> + if (chip_id == 0x7961)
> + return 1;
> + return 0;
> +}
> +
> +int btmtk_get_chip_state(struct btmtk_dev *bdev);
> +void btmtk_set_chip_state(struct btmtk_dev *bdev, int new_state);
> +int btmtk_allocate_hci_device(struct btmtk_dev *bdev, int hci_bus_type);
> +void btmtk_free_hci_device(struct btmtk_dev *bdev, int hci_bus_type);
> +int btmtk_register_hci_device(struct btmtk_dev *bdev);
> +int btmtk_deregister_hci_device(struct btmtk_dev *bdev);
> +int btmtk_recv(struct hci_dev *hdev, const u8 *data, size_t count);
> +int btmtk_recv_event(struct hci_dev *hdev, struct sk_buff *skb);
> +int btmtk_recv_acl(struct hci_dev *hdev, struct sk_buff *skb);
> +int btmtk_send_init_cmds(struct btmtk_dev *hdev);
> +int btmtk_send_deinit_cmds(struct btmtk_dev *hdev);
> +int btmtk_main_send_cmd(struct btmtk_dev *bdev, const u8 *cmd,
> + const int cmd_len, const u8 *event, const int event_len,
> + int delay, int retry, int pkt_type);
> +int btmtk_send_wmt_power_on_cmd(struct btmtk_dev *hdev);
> +int btmtk_send_wmt_power_off_cmd(struct btmtk_dev *hdev);
> +int btmtk_uart_send_wakeup_cmd(struct hci_dev *hdev);
> +int btmtk_uart_send_set_uart_cmd(struct hci_dev *hdev);
> +int btmtk_load_rom_patch(struct btmtk_dev *bdev);
> +struct btmtk_dev *btmtk_get_dev(void);
> +void btmtk_release_dev(struct btmtk_dev *bdev);
> +struct btmtk_dev *btmtk_allocate_dev_memory(struct device *dev);
> +void btmtk_free_dev_memory(struct device *dev, struct btmtk_dev *bdev);
> +void btmtk_reset_waker(struct work_struct *work);
> +struct btmtk_main_info *btmtk_get_main_info(void);
> +/** file_operations: stpbtfwlog */
> +int btmtk_fops_openfwlog(struct inode *inode, struct file *file);
> +int btmtk_fops_closefwlog(struct inode *inode, struct file *file);
> +ssize_t btmtk_fops_readfwlog(struct file *filp, char __user *buf, size_t count, loff_t *f_pos);
> +ssize_t btmtk_fops_writefwlog(struct file *filp, const char __user *buf, size_t count,
> + loff_t *f_pos);
> +unsigned int btmtk_fops_pollfwlog(struct file *filp, poll_table *wait);
> +long btmtk_fops_unlocked_ioctlfwlog(struct file *filp, unsigned int cmd, unsigned long arg);
> +
> +/* Auto enable picus */
> +int btmtk_picus_enable(struct btmtk_dev *bdev);
> +int btmtk_picus_disable(struct btmtk_dev *bdev);
> +
> +void btmtk_reg_hif_hook(struct hif_hook_ptr *hook);
> +int btmtk_main_cif_initialize(struct btmtk_dev *bdev, int hci_bus);
> +void btmtk_main_cif_uninitialize(struct btmtk_dev *bdev, int hci_bus);
> +int btmtk_main_cif_disconnect_notify(struct btmtk_dev *bdev, int hci_bus);
> +int btmtk_send_assert_cmd(struct btmtk_dev *bdev);
> +int btmtk_efuse_read(struct btmtk_dev *bdev, u16 addr, u8 *value);
> +
> +void btmtk_set_country_code_from_wifi(char *code);
> +
> +#endif /* __BTMTK_MAIN_H__ */
> diff --git a/drivers/bluetooth/btmtk_usb.h b/drivers/bluetooth/btmtk_usb.h
> new file mode 100644
> index 000000000000..92d11e808e78
> --- /dev/null
> +++ b/drivers/bluetooth/btmtk_usb.h
> @@ -0,0 +1,60 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +// Copyright (c) 2020 MediaTek Inc.
> +
> +/*
> + * Bluetooth support for MediaTek USB devices
> + *
> + */
> +
> +#ifndef _BTMTK_USB_H_
> +#define _BTMTK_USB_H_
> +#include <linux/usb.h>
> +#include "btmtk_main.h"
> +
> +#define HCI_MAX_COMMAND_SIZE 255
> +#define URB_MAX_BUFFER_SIZE (4 * 1024)
> +
> +#define BT0_MCU_INTERFACE_NUM 0
> +#define BT1_MCU_INTERFACE_NUM 3
> +#define BT_MCU_INTERFACE_NUM_MAX 4
> +#define BT_MCU_NUM_MAX 2
> +
> +/**
> + * Send cmd dispatch evt
> + */
> +#define HCI_EV_VENDOR 0xff
> +#define HCI_USB_IO_BUF_SIZE 256
> +
> +extern u8 wmt_over_hci_header[];
> +
> +struct btmtk_usb_dev {
> + struct usb_endpoint_descriptor *intr_ep;
> + struct usb_endpoint_descriptor *bulk_tx_ep;
> + struct usb_endpoint_descriptor *bulk_rx_ep;
> + struct usb_endpoint_descriptor *isoc_tx_ep;
> + struct usb_endpoint_descriptor *isoc_rx_ep;
> +
> + struct usb_device *udev;
> + struct usb_interface *intf;
> + struct usb_interface *isoc;
> + struct usb_interface *iso_channel;
> +
> + struct usb_anchor tx_anchor;
> + struct usb_anchor intr_anchor;
> + struct usb_anchor bulk_anchor;
> + struct usb_anchor isoc_anchor;
> + struct usb_anchor ctrl_anchor;
> +
> + __u8 cmdreq_type;
> + __u8 cmdreq;
> +
> + int new_isoc_altsetting;
> + int new_isoc_altsetting_interface;
> +
> + unsigned char *o_usb_buf;
> +
> + unsigned char *urb_intr_buf;
> + unsigned char *urb_bulk_buf;
> + unsigned char *urb_ble_isoc_buf;
> +};
> +#endif
> diff --git a/drivers/bluetooth/btmtkusb.c b/drivers/bluetooth/btmtkusb.c
> new file mode 100644
> index 000000000000..36e00ddebe62
> --- /dev/null
> +++ b/drivers/bluetooth/btmtkusb.c
> @@ -0,0 +1,2050 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (c) 2020 MediaTek Inc.
> +
> +/*
> + * Bluetooth support for MediaTek USB devices
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/firmware.h>
> +#include <asm/unaligned.h>
> +#include <linux/usb/quirks.h>
> +#include <net/bluetooth/bluetooth.h>
> +#include <net/bluetooth/hci_core.h>
> +#include "btmtk_usb.h"
> +#include "btmtk_main.h"
> +
> +static struct usb_driver btusb_driver;
> +static int intf_to_idx[BT_MCU_INTERFACE_NUM_MAX] = {0, -1, -1, 1};
> +static struct btmtk_usb_dev g_usb_dev[BT_MCU_MINIMUM_INTERFACE_NUM][BT_MCU_NUM_MAX];
> +
> +static const struct usb_device_id btusb_table[] = {
> + /* Mediatek MT7961 */
> + { USB_DEVICE_AND_INTERFACE_INFO(0x0e8d, 0x7961, 0xe0, 0x01, 0x01) },
> + /* Mediatek MT7922 */
> + { USB_DEVICE_AND_INTERFACE_INFO(0x0e8d, 0x7922, 0xe0, 0x01, 0x01) },
> +
> + { } /* Terminating entry */
> +};
> +
> +static char event_need_compare[EVENT_COMPARE_SIZE] = {0};
> +static char event_need_compare_len;
> +static char event_compare_status;
> +
> +static DEFINE_MUTEX(btmtk_usb_ops_mutex);
> +#define USB_OPS_MUTEX_LOCK() mutex_lock(&btmtk_usb_ops_mutex)
> +#define USB_OPS_MUTEX_UNLOCK() mutex_unlock(&btmtk_usb_ops_mutex)
> +
> +MODULE_DEVICE_TABLE(usb, btusb_table);
> +
> +#define BTUSB_MAX_ISOC_FRAMES 24
> +
> +#define BTUSB_INTR_RUNNING 0
> +#define BTUSB_BULK_RUNNING 1
> +#define BTUSB_ISOC_RUNNING 2
> +#define BTUSB_SUSPENDING 3
> +#define BTUSB_DID_ISO_RESUME 4
> +#define BTUSB_BLE_ISOC_RUNNING 5
Looks like a massive copy from btusb.c without giving any credit.
Anyhow, it would be useful that you describe what endpoints the device has and what is suppose to send and receiving over what endpoint. Using btusb.c as a blueprint is not a good idea. It is a lot more complicated than you standard USB driver.
Regards
Marcel
More information about the Linux-mediatek
mailing list