// SPDX-License-Identifier: GPL-2.0-or-later/* * * Bluetooth HCI UART driver for Intel devices * * Copyright (C) 2015 Intel Corporation */ #include <linux/kernel.h>#include <linux/errno.h>#include <linux/skbuff.h>#include <linux/firmware.h>#include <linux/module.h>#include <linux/wait.h>#include <linux/tty.h>#include <linux/platform_device.h>#include <linux/gpio/consumer.h>#include <linux/acpi.h>#include <linux/interrupt.h>#include <linux/pm_runtime.h> #include <net/bluetooth/bluetooth.h>#include <net/bluetooth/hci_core.h> #include "hci_uart.h"#include "btintel.h" #define STATE_BOOTLOADER 0#define STATE_DOWNLOADING 1#define STATE_FIRMWARE_LOADED 2#define STATE_FIRMWARE_FAILED 3#define STATE_BOOTING 4#define STATE_LPM_ENABLED 5#define STATE_TX_ACTIVE 6#define STATE_SUSPENDED 7#define STATE_LPM_TRANSACTION 8 #define HCI_LPM_WAKE_PKT 0xf0#define HCI_LPM_PKT 0xf1#define HCI_LPM_MAX_SIZE 10#define HCI_LPM_HDR_SIZE HCI_EVENT_HDR_SIZE #define LPM_OP_TX_NOTIFY 0x00#define LPM_OP_SUSPEND_ACK 0x02#define LPM_OP_RESUME_ACK 0x03 #define LPM_SUSPEND_DELAY_MS 1000 struct hci_lpm_pkt { __u8 opcode; __u8 dlen; __u8 data[];} __packed; struct intel_device { struct list_head list; struct platform_device *pdev; struct gpio_desc *reset; struct hci_uart *hu; struct mutex hu_lock; int irq;}; static LIST_HEAD(intel_device_list);static DEFINE_MUTEX(intel_device_list_lock); struct intel_data { struct sk_buff *rx_skb; struct sk_buff_head txq; struct work_struct busy_work; struct hci_uart *hu; unsigned long flags;}; static u8 intel_convert_speed(unsigned int speed){ switch (speed) { case 9600: return 0x00; case 19200: return 0x01; case 38400: return 0x02; case 57600: return 0x03; case 115200: return 0x04; case 230400: return 0x05; case 460800: return 0x06; case 921600: return 0x07; case 1843200: return 0x08; case 3250000: return 0x09; case 2000000: return 0x0a; case 3000000: return 0x0b; default: return 0xff; }} static int intel_wait_booting(struct hci_uart *hu){ struct intel_data *intel = hu->priv; int err; err = wait_on_bit_timeout(&intel->flags, STATE_BOOTING, TASK_INTERRUPTIBLE, msecs_to_jiffies(1000)); if (err == -EINTR) { bt_dev_err(hu->hdev, "Device boot interrupted"); return -EINTR; } if (err) { bt_dev_err(hu->hdev, "Device boot timeout"); return -ETIMEDOUT; } return err;} static int intel_wait_lpm_transaction(struct hci_uart *hu){ struct intel_data *intel = hu->priv; int err; err = wait_on_bit_timeout(&intel->flags, STATE_LPM_TRANSACTION, TASK_INTERRUPTIBLE, msecs_to_jiffies(1000)); if (err == -EINTR) { bt_dev_err(hu->hdev, "LPM transaction interrupted"); return -EINTR; } if (err) { bt_dev_err(hu->hdev, "LPM transaction timeout"); return -ETIMEDOUT; } return err;} static int intel_lpm_suspend(struct hci_uart *hu){ static const u8 suspend[] = { 0x01, 0x01, 0x01 }; struct intel_data *intel = hu->priv; struct sk_buff *skb; if (!test_bit(STATE_LPM_ENABLED, &intel->flags) || test_bit(STATE_SUSPENDED, &intel->flags)) return 0; if (test_bit(STATE_TX_ACTIVE, &intel->flags)) return -EAGAIN; bt_dev_dbg(hu->hdev, "Suspending"); skb = bt_skb_alloc(sizeof(suspend), GFP_KERNEL); if (!skb) { bt_dev_err(hu->hdev, "Failed to alloc memory for LPM packet"); return -ENOMEM; } skb_put_data(skb, suspend, sizeof(suspend)); hci_skb_pkt_type(skb) = HCI_LPM_PKT; set_bit(STATE_LPM_TRANSACTION, &intel->flags); /* LPM flow is a priority, enqueue packet at list head */ skb_queue_head(&intel->txq, skb); hci_uart_tx_wakeup(hu); intel_wait_lpm_transaction(hu); /* Even in case of failure, continue and test the suspended flag */ clear_bit(STATE_LPM_TRANSACTION, &intel->flags); if (!test_bit(STATE_SUSPENDED, &intel->flags)) { bt_dev_err(hu->hdev, "Device suspend error"); return -EINVAL; } bt_dev_dbg(hu->hdev, "Suspended"); hci_uart_set_flow_control(hu, true); return 0;} static int intel_lpm_resume(struct hci_uart *hu){ struct intel_data *intel = hu->priv; struct sk_buff *skb; if (!test_bit(STATE_LPM_ENABLED, &intel->flags) || !test_bit(STATE_SUSPENDED, &intel->flags)) return 0; bt_dev_dbg(hu->hdev, "Resuming"); hci_uart_set_flow_control(hu, false); skb = bt_skb_alloc(0, GFP_KERNEL); if (!skb) { bt_dev_err(hu->hdev, "Failed to alloc memory for LPM packet"); return -ENOMEM; } hci_skb_pkt_type(skb) = HCI_LPM_WAKE_PKT; set_bit(STATE_LPM_TRANSACTION, &intel->flags); /* LPM flow is a priority, enqueue packet at list head */ skb_queue_head(&intel->txq, skb); hci_uart_tx_wakeup(hu); intel_wait_lpm_transaction(hu); /* Even in case of failure, continue and test the suspended flag */ clear_bit(STATE_LPM_TRANSACTION, &intel->flags); if (test_bit(STATE_SUSPENDED, &intel->flags)) { bt_dev_err(hu->hdev, "Device resume error"); return -EINVAL; } bt_dev_dbg(hu->hdev, "Resumed"); return 0;} static int intel_lpm_host_wake(struct hci_uart *hu){ static const u8 lpm_resume_ack[] = { LPM_OP_RESUME_ACK, 0x00 }; struct intel_data *intel = hu->priv; struct sk_buff *skb; hci_uart_set_flow_control(hu, false); clear_bit(STATE_SUSPENDED, &intel->flags); skb = bt_skb_alloc(sizeof(lpm_resume_ack), GFP_KERNEL); if (!skb) { bt_dev_err(hu->hdev, "Failed to alloc memory for LPM packet"); return -ENOMEM; } skb_put_data(skb, lpm_resume_ack, sizeof(lpm_resume_ack)); hci_skb_pkt_type(skb) = HCI_LPM_PKT; /* LPM flow is a priority, enqueue packet at list head */ skb_queue_head(&intel->txq, skb); hci_uart_tx_wakeup(hu); bt_dev_dbg(hu->hdev, "Resumed by controller"); return 0;} static irqreturn_t intel_irq(int irq, void *dev_id){ struct intel_device *idev = dev_id; dev_info(&idev->pdev->dev, "hci_intel irq\n"); mutex_lock(&idev->hu_lock); if (idev->hu) intel_lpm_host_wake(idev->hu); mutex_unlock(&idev->hu_lock); /* Host/Controller are now LPM resumed, trigger a new delayed suspend */ pm_runtime_get(&idev->pdev->dev); pm_runtime_put_autosuspend(&idev->pdev->dev); return IRQ_HANDLED;} static int intel_set_power(struct hci_uart *hu, bool powered){ struct intel_device *idev; int err = -ENODEV; if (!hu->tty->dev) return err; mutex_lock(&intel_device_list_lock); list_for_each_entry(idev, &intel_device_list, list) { /* tty device and pdev device should share the same parent * which is the UART port. */ if (hu->tty->dev->parent != idev->pdev->dev.parent) continue; if (!idev->reset) { err = -ENOTSUPP; break; } BT_INFO("hu %p, Switching compatible pm device (%s) to %u", hu, dev_name(&idev->pdev->dev), powered); gpiod_set_value(idev->reset, powered); /* Provide to idev a hu reference which is used to run LPM * transactions (lpm suspend/resume) from PM callbacks. * hu needs to be protected against concurrent removing during * these PM ops. */ mutex_lock(&idev->hu_lock); idev->hu = powered ? hu : NULL; mutex_unlock(&idev->hu_lock); if (idev->irq < 0) break; if (powered && device_can_wakeup(&idev->pdev->dev)) { err = devm_request_threaded_irq(&idev->pdev->dev, idev->irq, NULL, intel_irq, IRQF_ONESHOT, "bt-host-wake", idev); if (err) { BT_ERR("hu %p, unable to allocate irq-%d", hu, idev->irq); break; } device_wakeup_enable(&idev->pdev->dev); pm_runtime_set_active(&idev->pdev->dev); pm_runtime_use_autosuspend(&idev->pdev->dev); pm_runtime_set_autosuspend_delay(&idev->pdev->dev, LPM_SUSPEND_DELAY_MS); pm_runtime_enable(&idev->pdev->dev); } else if (!powered && device_may_wakeup(&idev->pdev->dev)) { devm_free_irq(&idev->pdev->dev, idev->irq, idev); device_wakeup_disable(&idev->pdev->dev); pm_runtime_dont_use_autosuspend(&idev->pdev->dev); pm_runtime_disable(&idev->pdev->dev); } } mutex_unlock(&intel_device_list_lock); return err;} static void intel_busy_work(struct work_struct *work){ struct intel_data *intel = container_of(work, struct intel_data, busy_work); struct intel_device *idev; if (!intel->hu->tty->dev) return; /* Link is busy, delay the suspend */ mutex_lock(&intel_device_list_lock); list_for_each_entry(idev, &intel_device_list, list) { if (intel->hu->tty->dev->parent == idev->pdev->dev.parent) { pm_runtime_get(&idev->pdev->dev); pm_runtime_put_autosuspend(&idev->pdev->dev); break; } } mutex_unlock(&intel_device_list_lock);} static int intel_open(struct hci_uart *hu){ struct intel_data *intel; BT_DBG("hu %p", hu); if (!hci_uart_has_flow_control(hu)) return -EOPNOTSUPP; intel = kzalloc_obj(*intel); if (!intel) return -ENOMEM; skb_queue_head_init(&intel->txq); INIT_WORK(&intel->busy_work, intel_busy_work); intel->hu = hu; hu->priv = intel; if (!intel_set_power(hu, true)) set_bit(STATE_BOOTING, &intel->flags); return 0;} static int intel_close(struct hci_uart *hu){ struct intel_data *intel = hu->priv; BT_DBG("hu %p", hu); cancel_work_sync(&intel->busy_work); intel_set_power(hu, false); skb_queue_purge(&intel->txq); kfree_skb(intel->rx_skb); kfree(intel); hu->priv = NULL; return 0;} static int intel_flush(struct hci_uart *hu){ struct intel_data *intel = hu->priv; BT_DBG("hu %p", hu); skb_queue_purge(&intel->txq); return 0;} static int inject_cmd_complete(struct hci_dev *hdev, __u16 opcode){ struct sk_buff *skb; struct hci_event_hdr *hdr; struct hci_ev_cmd_complete *evt; skb = bt_skb_alloc(sizeof(*hdr) + sizeof(*evt) + 1, GFP_KERNEL); if (!skb) return -ENOMEM; hdr = skb_put(skb, sizeof(*hdr)); hdr->evt = HCI_EV_CMD_COMPLETE; hdr->plen = sizeof(*evt) + 1; evt = skb_put(skb, sizeof(*evt)); evt->ncmd = 0x01; evt->opcode = cpu_to_le16(opcode); skb_put_u8(skb, 0x00); hci_skb_pkt_type(skb) = HCI_EVENT_PKT; return hci_recv_frame(hdev, skb);} static int intel_set_baudrate(struct hci_uart *hu, unsigned int speed){ struct intel_data *intel = hu->priv; struct hci_dev *hdev = hu->hdev; u8 speed_cmd[] = { 0x06, 0xfc, 0x01, 0x00 }; struct sk_buff *skb; int err; /* This can be the first command sent to the chip, check * that the controller is ready. */ err = intel_wait_booting(hu); clear_bit(STATE_BOOTING, &intel->flags); /* In case of timeout, try to continue anyway */ if (err && err != -ETIMEDOUT) return err; bt_dev_info(hdev, "Change controller speed to %d", speed); speed_cmd[3] = intel_convert_speed(speed); if (speed_cmd[3] == 0xff) { bt_dev_err(hdev, "Unsupported speed"); return -EINVAL; } /* Device will not accept speed change if Intel version has not been * previously requested. */ skb = __hci_cmd_sync(hdev, 0xfc05, 0, NULL, HCI_CMD_TIMEOUT); if (IS_ERR(skb)) { bt_dev_err(hdev, "Reading Intel version information failed (%ld)", PTR_ERR(skb)); return PTR_ERR(skb); } kfree_skb(skb); skb = bt_skb_alloc(sizeof(speed_cmd), GFP_KERNEL); if (!skb) { bt_dev_err(hdev, "Failed to alloc memory for baudrate packet"); return -ENOMEM;Lines 1–500 of 1225. Load more
// SPDX-License-Identifier: GPL-2.0-or-later /* * * Bluetooth HCI UART driver for Intel devices * * Copyright (C) 2015 Intel Corporation */ #include <linux/kernel.h> #include <linux/errno.h> #include <linux/skbuff.h> #include <linux/firmware.h> #include <linux/module.h> #include <linux/wait.h> #include <linux/tty.h> #include <linux/platform_device.h> #include <linux/gpio/consumer.h> #include <linux/acpi.h> #include <linux/interrupt.h> #include <linux/pm_runtime.h> #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> #include "hci_uart.h" #include "btintel.h" #define STATE_BOOTLOADER 0 #define STATE_DOWNLOADING 1 #define STATE_FIRMWARE_LOADED 2 #define STATE_FIRMWARE_FAILED 3 #define STATE_BOOTING 4 #define STATE_LPM_ENABLED 5 #define STATE_TX_ACTIVE 6 #define STATE_SUSPENDED 7 #define STATE_LPM_TRANSACTION 8 #define HCI_LPM_WAKE_PKT 0xf0 #define HCI_LPM_PKT 0xf1 #define HCI_LPM_MAX_SIZE 10 #define HCI_LPM_HDR_SIZE HCI_EVENT_HDR_SIZE #define LPM_OP_TX_NOTIFY 0x00 #define LPM_OP_SUSPEND_ACK 0x02 #define LPM_OP_RESUME_ACK 0x03 #define LPM_SUSPEND_DELAY_MS 1000 struct hci_lpm_pkt { __u8 opcode; __u8 dlen; __u8 data[]; } __packed; struct intel_device { struct list_head list; struct platform_device *pdev; struct gpio_desc *reset; struct hci_uart *hu; struct mutex hu_lock; int irq; }; static LIST_HEAD(intel_device_list); static DEFINE_MUTEX(intel_device_list_lock); struct intel_data { struct sk_buff *rx_skb; struct sk_buff_head txq; struct work_struct busy_work; struct hci_uart *hu; unsigned long flags; }; static u8 intel_convert_speed(unsigned int speed) { switch (speed) { case 9600: return 0x00; case 19200: return 0x01; case 38400: return 0x02; case 57600: return 0x03; case 115200: return 0x04; case 230400: return 0x05; case 460800: return 0x06; case 921600: return 0x07; case 1843200: return 0x08; case 3250000: return 0x09; case 2000000: return 0x0a; case 3000000: return 0x0b; default: return 0xff; } } static int intel_wait_booting(struct hci_uart *hu) { struct intel_data *intel = hu->priv; int err; err = wait_on_bit_timeout(&intel->flags, STATE_BOOTING, TASK_INTERRUPTIBLE, msecs_to_jiffies(1000)); if (err == -EINTR) { bt_dev_err(hu->hdev, "Device boot interrupted"); return -EINTR; } if (err) { bt_dev_err(hu->hdev, "Device boot timeout"); return -ETIMEDOUT; } return err; } static int intel_wait_lpm_transaction(struct hci_uart *hu) { struct intel_data *intel = hu->priv; int err; err = wait_on_bit_timeout(&intel->flags, STATE_LPM_TRANSACTION, TASK_INTERRUPTIBLE, msecs_to_jiffies(1000)); if (err == -EINTR) { bt_dev_err(hu->hdev, "LPM transaction interrupted"); return -EINTR; } if (err) { bt_dev_err(hu->hdev, "LPM transaction timeout"); return -ETIMEDOUT; } return err; } static int intel_lpm_suspend(struct hci_uart *hu) { static const u8 suspend[] = { 0x01, 0x01, 0x01 }; struct intel_data *intel = hu->priv; struct sk_buff *skb; if (!test_bit(STATE_LPM_ENABLED, &intel->flags) || test_bit(STATE_SUSPENDED, &intel->flags)) return 0; if (test_bit(STATE_TX_ACTIVE, &intel->flags)) return -EAGAIN; bt_dev_dbg(hu->hdev, "Suspending"); skb = bt_skb_alloc(sizeof(suspend), GFP_KERNEL); if (!skb) { bt_dev_err(hu->hdev, "Failed to alloc memory for LPM packet"); return -ENOMEM; } skb_put_data(skb, suspend, sizeof(suspend)); hci_skb_pkt_type(skb) = HCI_LPM_PKT; set_bit(STATE_LPM_TRANSACTION, &intel->flags); /* LPM flow is a priority, enqueue packet at list head */ skb_queue_head(&intel->txq, skb); hci_uart_tx_wakeup(hu); intel_wait_lpm_transaction(hu); /* Even in case of failure, continue and test the suspended flag */ clear_bit(STATE_LPM_TRANSACTION, &intel->flags); if (!test_bit(STATE_SUSPENDED, &intel->flags)) { bt_dev_err(hu->hdev, "Device suspend error"); return -EINVAL; } bt_dev_dbg(hu->hdev, "Suspended"); hci_uart_set_flow_control(hu, true); return 0; } static int intel_lpm_resume(struct hci_uart *hu) { struct intel_data *intel = hu->priv; struct sk_buff *skb; if (!test_bit(STATE_LPM_ENABLED, &intel->flags) || !test_bit(STATE_SUSPENDED, &intel->flags)) return 0; bt_dev_dbg(hu->hdev, "Resuming"); hci_uart_set_flow_control(hu, false); skb = bt_skb_alloc(0, GFP_KERNEL); if (!skb) { bt_dev_err(hu->hdev, "Failed to alloc memory for LPM packet"); return -ENOMEM; } hci_skb_pkt_type(skb) = HCI_LPM_WAKE_PKT; set_bit(STATE_LPM_TRANSACTION, &intel->flags); /* LPM flow is a priority, enqueue packet at list head */ skb_queue_head(&intel->txq, skb); hci_uart_tx_wakeup(hu); intel_wait_lpm_transaction(hu); /* Even in case of failure, continue and test the suspended flag */ clear_bit(STATE_LPM_TRANSACTION, &intel->flags); if (test_bit(STATE_SUSPENDED, &intel->flags)) { bt_dev_err(hu->hdev, "Device resume error"); return -EINVAL; } bt_dev_dbg(hu->hdev, "Resumed"); return 0; } static int intel_lpm_host_wake(struct hci_uart *hu) { static const u8 lpm_resume_ack[] = { LPM_OP_RESUME_ACK, 0x00 }; struct intel_data *intel = hu->priv; struct sk_buff *skb; hci_uart_set_flow_control(hu, false); clear_bit(STATE_SUSPENDED, &intel->flags); skb = bt_skb_alloc(sizeof(lpm_resume_ack), GFP_KERNEL); if (!skb) { bt_dev_err(hu->hdev, "Failed to alloc memory for LPM packet"); return -ENOMEM; } skb_put_data(skb, lpm_resume_ack, sizeof(lpm_resume_ack)); hci_skb_pkt_type(skb) = HCI_LPM_PKT; /* LPM flow is a priority, enqueue packet at list head */ skb_queue_head(&intel->txq, skb); hci_uart_tx_wakeup(hu); bt_dev_dbg(hu->hdev, "Resumed by controller"); return 0; } static irqreturn_t intel_irq(int irq, void *dev_id) { struct intel_device *idev = dev_id; dev_info(&idev->pdev->dev, "hci_intel irq\n"); mutex_lock(&idev->hu_lock); if (idev->hu) intel_lpm_host_wake(idev->hu); mutex_unlock(&idev->hu_lock); /* Host/Controller are now LPM resumed, trigger a new delayed suspend */ pm_runtime_get(&idev->pdev->dev); pm_runtime_put_autosuspend(&idev->pdev->dev); return IRQ_HANDLED; } static int intel_set_power(struct hci_uart *hu, bool powered) { struct intel_device *idev; int err = -ENODEV; if (!hu->tty->dev) return err; mutex_lock(&intel_device_list_lock); list_for_each_entry(idev, &intel_device_list, list) { /* tty device and pdev device should share the same parent * which is the UART port. */ if (hu->tty->dev->parent != idev->pdev->dev.parent) continue; if (!idev->reset) { err = -ENOTSUPP; break; } BT_INFO("hu %p, Switching compatible pm device (%s) to %u", hu, dev_name(&idev->pdev->dev), powered); gpiod_set_value(idev->reset, powered); /* Provide to idev a hu reference which is used to run LPM * transactions (lpm suspend/resume) from PM callbacks. * hu needs to be protected against concurrent removing during * these PM ops. */ mutex_lock(&idev->hu_lock); idev->hu = powered ? hu : NULL; mutex_unlock(&idev->hu_lock); if (idev->irq < 0) break; if (powered && device_can_wakeup(&idev->pdev->dev)) { err = devm_request_threaded_irq(&idev->pdev->dev, idev->irq, NULL, intel_irq, IRQF_ONESHOT, "bt-host-wake", idev); if (err) { BT_ERR("hu %p, unable to allocate irq-%d", hu, idev->irq); break; } device_wakeup_enable(&idev->pdev->dev); pm_runtime_set_active(&idev->pdev->dev); pm_runtime_use_autosuspend(&idev->pdev->dev); pm_runtime_set_autosuspend_delay(&idev->pdev->dev, LPM_SUSPEND_DELAY_MS); pm_runtime_enable(&idev->pdev->dev); } else if (!powered && device_may_wakeup(&idev->pdev->dev)) { devm_free_irq(&idev->pdev->dev, idev->irq, idev); device_wakeup_disable(&idev->pdev->dev); pm_runtime_dont_use_autosuspend(&idev->pdev->dev); pm_runtime_disable(&idev->pdev->dev); } } mutex_unlock(&intel_device_list_lock); return err; } static void intel_busy_work(struct work_struct *work) { struct intel_data *intel = container_of(work, struct intel_data, busy_work); struct intel_device *idev; if (!intel->hu->tty->dev) return; /* Link is busy, delay the suspend */ mutex_lock(&intel_device_list_lock); list_for_each_entry(idev, &intel_device_list, list) { if (intel->hu->tty->dev->parent == idev->pdev->dev.parent) { pm_runtime_get(&idev->pdev->dev); pm_runtime_put_autosuspend(&idev->pdev->dev); break; } } mutex_unlock(&intel_device_list_lock); } static int intel_open(struct hci_uart *hu) { struct intel_data *intel; BT_DBG("hu %p", hu); if (!hci_uart_has_flow_control(hu)) return -EOPNOTSUPP; intel = kzalloc_obj(*intel); if (!intel) return -ENOMEM; skb_queue_head_init(&intel->txq); INIT_WORK(&intel->busy_work, intel_busy_work); intel->hu = hu; hu->priv = intel; if (!intel_set_power(hu, true)) set_bit(STATE_BOOTING, &intel->flags); return 0; } static int intel_close(struct hci_uart *hu) { struct intel_data *intel = hu->priv; BT_DBG("hu %p", hu); cancel_work_sync(&intel->busy_work); intel_set_power(hu, false); skb_queue_purge(&intel->txq); kfree_skb(intel->rx_skb); kfree(intel); hu->priv = NULL; return 0; } static int intel_flush(struct hci_uart *hu) { struct intel_data *intel = hu->priv; BT_DBG("hu %p", hu); skb_queue_purge(&intel->txq); return 0; } static int inject_cmd_complete(struct hci_dev *hdev, __u16 opcode) { struct sk_buff *skb; struct hci_event_hdr *hdr; struct hci_ev_cmd_complete *evt; skb = bt_skb_alloc(sizeof(*hdr) + sizeof(*evt) + 1, GFP_KERNEL); if (!skb) return -ENOMEM; hdr = skb_put(skb, sizeof(*hdr)); hdr->evt = HCI_EV_CMD_COMPLETE; hdr->plen = sizeof(*evt) + 1; evt = skb_put(skb, sizeof(*evt)); evt->ncmd = 0x01; evt->opcode = cpu_to_le16(opcode); skb_put_u8(skb, 0x00); hci_skb_pkt_type(skb) = HCI_EVENT_PKT; return hci_recv_frame(hdev, skb); } static int intel_set_baudrate(struct hci_uart *hu, unsigned int speed) { struct intel_data *intel = hu->priv; struct hci_dev *hdev = hu->hdev; u8 speed_cmd[] = { 0x06, 0xfc, 0x01, 0x00 }; struct sk_buff *skb; int err; /* This can be the first command sent to the chip, check * that the controller is ready. */ err = intel_wait_booting(hu); clear_bit(STATE_BOOTING, &intel->flags); /* In case of timeout, try to continue anyway */ if (err && err != -ETIMEDOUT) return err; bt_dev_info(hdev, "Change controller speed to %d", speed); speed_cmd[3] = intel_convert_speed(speed); if (speed_cmd[3] == 0xff) { bt_dev_err(hdev, "Unsupported speed"); return -EINVAL; } /* Device will not accept speed change if Intel version has not been * previously requested. */ skb = __hci_cmd_sync(hdev, 0xfc05, 0, NULL, HCI_CMD_TIMEOUT); if (IS_ERR(skb)) { bt_dev_err(hdev, "Reading Intel version information failed (%ld)", PTR_ERR(skb)); return PTR_ERR(skb); } kfree_skb(skb); skb = bt_skb_alloc(sizeof(speed_cmd), GFP_KERNEL); if (!skb) { bt_dev_err(hdev, "Failed to alloc memory for baudrate packet"); return -ENOMEM;