void btintel_hw_error(struct hci_dev *hdev, u8 code) { struct sk_buff *skb; u8 type = 0x00; BT_ERR("%s: Hardware error 0x%2.2x", hdev->name, code); skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { BT_ERR("%s: Reset after hardware error failed (%ld)", hdev->name, PTR_ERR(skb)); return; } kfree_skb(skb); skb = __hci_cmd_sync(hdev, 0xfc22, 1, &type, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { BT_ERR("%s: Retrieving Intel exception info failed (%ld)", hdev->name, PTR_ERR(skb)); return; } if (skb->len != 13) { BT_ERR("%s: Exception info size mismatch", hdev->name); kfree_skb(skb); return; } BT_ERR("%s: Exception info %s", hdev->name, (char *)(skb->data + 1)); kfree_skb(skb); }
int btintel_set_event_mask_mfg(struct hci_dev *hdev, bool debug) { struct sk_buff *skb; u8 param[2]; int err; param[0] = 0x01; param[1] = 0x00; skb = __hci_cmd_sync(hdev, 0xfc11, 2, param, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { err = PTR_ERR(skb); BT_ERR("%s: Entering Intel manufacturer mode failed (%d)", hdev->name, err); return PTR_ERR(skb); } kfree_skb(skb); err = btintel_set_event_mask(hdev, debug); param[0] = 0x00; param[1] = 0x00; skb = __hci_cmd_sync(hdev, 0xfc11, 2, param, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { err = PTR_ERR(skb); BT_ERR("%s: Leaving Intel manufacturer mode failed (%d)", hdev->name, err); return PTR_ERR(skb); } kfree_skb(skb); return err; }
static int rtl_read_rom_version(struct hci_dev *hdev, u8 *version) { struct rtl_rom_version_evt *rom_version; struct sk_buff *skb; /* Read RTL ROM version command */ skb = __hci_cmd_sync(hdev, 0xfc6d, 0, NULL, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { BT_ERR("%s: Read ROM version failed (%ld)", hdev->name, PTR_ERR(skb)); return PTR_ERR(skb); } if (skb->len != sizeof(*rom_version)) { BT_ERR("%s: RTL version event length mismatch", hdev->name); kfree_skb(skb); return -EIO; } rom_version = (struct rtl_rom_version_evt *)skb->data; BT_INFO("%s: rom_version status=%x version=%x", hdev->name, rom_version->status, rom_version->version); *version = rom_version->version; kfree_skb(skb); return 0; }
int btintel_exit_mfg(struct hci_dev *hdev, bool reset, bool patched) { u8 param[] = { 0x00, 0x00 }; struct sk_buff *skb; if (hdev == NULL) { return -1; } /* The 2nd command parameter specifies the manufacturing exit method: * 0x00: Just disable the manufacturing mode (0x00). * 0x01: Disable manufacturing mode and reset with patches deactivated. * 0x02: Disable manufacturing mode and reset with patches activated. */ if (reset) param[1] |= patched ? 0x02 : 0x01; skb = __hci_cmd_sync(hdev, CMD_MANUFACTURER_MODE, 2, param, HCI_CMD_TIMEOUT); if (IS_ERR(skb)) { BT_ERR("%s: Exiting manufacturer mode failed (%ld)", hdev->name, PTR_ERR(skb)); return PTR_ERR(skb); } else { BT_INFO("Exiting manufacturer mode successful"); } kfree_skb(skb); return 0; }
int btintel_set_diag(struct hci_dev *hdev, bool enable) { struct sk_buff *skb; u8 param[3]; int err; if (enable) { param[0] = 0x03; param[1] = 0x03; param[2] = 0x03; } else { param[0] = 0x00; param[1] = 0x00; param[2] = 0x00; } skb = __hci_cmd_sync(hdev, 0xfc43, 3, param, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { err = PTR_ERR(skb); if (err == -ENODATA) goto done; BT_ERR("%s: Changing Intel diagnostic mode failed (%d)", hdev->name, err); return err; } kfree_skb(skb); done: btintel_set_event_mask(hdev, enable); return 0; }
int btintel_read_version(struct hci_dev *hdev, struct intel_version *ver) { struct sk_buff *skb; if (hdev == NULL || ver == NULL) { return -EINVAL;; } skb = __hci_cmd_sync(hdev, CMD_READ_VERSION, 0, NULL, HCI_CMD_TIMEOUT); if (IS_ERR(skb)) { BT_ERR("%s: Reading Intel version information failed (%ld)", hdev->name, PTR_ERR(skb)); return PTR_ERR(skb); } else { BT_INFO("Reading Intel version information successful"); } if (skb->len != sizeof(*ver)) { BT_ERR("%s: Intel version event size mismatch", hdev->name); kfree_skb(skb); return -EILSEQ; } BT_INFO("Exiting btintel_read_version"); memcpy(ver, skb->data, sizeof(*ver)); kfree_skb(skb); return 0; }
int btbcm_check_bdaddr(struct hci_dev *hdev) { struct hci_rp_read_bd_addr *bda; struct sk_buff *skb; skb = __hci_cmd_sync(hdev, HCI_OP_READ_BD_ADDR, 0, NULL, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { int err = PTR_ERR(skb); BT_ERR("%s: BCM: Reading device address failed (%d)", hdev->name, err); return err; } if (skb->len != sizeof(*bda)) { BT_ERR("%s: BCM: Device address length mismatch", hdev->name); kfree_skb(skb); return -EIO; } bda = (struct hci_rp_read_bd_addr *)skb->data; /* The address 00:20:70:02:A0:00 indicates a BCM20702A0 controller * with no configured address. */ if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0)) { BT_INFO("%s: BCM: Using default device address (%pMR)", hdev->name, &bda->bdaddr); set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); } kfree_skb(skb); return 0; }
static int hci_uart_setup(struct hci_dev *hdev) { struct hci_uart *hu = hci_get_drvdata(hdev); struct hci_rp_read_local_version *ver; struct sk_buff *skb; unsigned int speed; int err; /* Init speed if any */ if (hu->init_speed) speed = hu->init_speed; else if (hu->proto->init_speed) speed = hu->proto->init_speed; else speed = 0; if (speed) serdev_device_set_baudrate(hu->serdev, speed); /* Operational speed if any */ if (hu->oper_speed) speed = hu->oper_speed; else if (hu->proto->oper_speed) speed = hu->proto->oper_speed; else speed = 0; if (hu->proto->set_baudrate && speed) { err = hu->proto->set_baudrate(hu, speed); if (err) BT_ERR("%s: failed to set baudrate", hdev->name); else serdev_device_set_baudrate(hu->serdev, speed); } if (hu->proto->setup) return hu->proto->setup(hu); if (!test_bit(HCI_UART_VND_DETECT, &hu->hdev_flags)) return 0; skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { BT_ERR("%s: Reading local version information failed (%ld)", hdev->name, PTR_ERR(skb)); return 0; } if (skb->len != sizeof(*ver)) { BT_ERR("%s: Event length mismatch for version information", hdev->name); } kfree_skb(skb); return 0; }
static int btusb_setup_patchram_packet(struct hci_dev *hdev, u16 opcode, u32 plen, const void *param) { struct sk_buff *skb; skb = __hci_cmd_sync(hdev, opcode, plen, param, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) return PTR_ERR(skb); kfree_skb(skb); return 0; }
static int rtl_download_firmware(struct hci_dev *hdev, const unsigned char *data, int fw_len) { struct rtl_download_cmd *dl_cmd; int frag_num = fw_len / RTL_FRAG_LEN + 1; int frag_len = RTL_FRAG_LEN; int ret = 0; int i; dl_cmd = kmalloc(sizeof(struct rtl_download_cmd), GFP_KERNEL); if (!dl_cmd) return -ENOMEM; for (i = 0; i < frag_num; i++) { struct sk_buff *skb; BT_DBG("download fw (%d/%d)", i, frag_num); dl_cmd->index = i; if (i == (frag_num - 1)) { dl_cmd->index |= 0x80; /* data end */ frag_len = fw_len % RTL_FRAG_LEN; } memcpy(dl_cmd->data, data, frag_len); /* Send download command */ skb = __hci_cmd_sync(hdev, 0xfc20, frag_len + 1, dl_cmd, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { BT_ERR("%s: download fw command failed (%ld)", hdev->name, PTR_ERR(skb)); ret = -PTR_ERR(skb); goto out; } if (skb->len != sizeof(struct rtl_download_response)) { BT_ERR("%s: download fw event length mismatch", hdev->name); kfree_skb(skb); ret = -EIO; goto out; } kfree_skb(skb); data += RTL_FRAG_LEN; } out: kfree(dl_cmd); return ret; }
static int btbcm_reset(struct hci_dev *hdev) { struct sk_buff *skb; skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { int err = PTR_ERR(skb); BT_ERR("%s: BCM: Reset failed (%d)", hdev->name, err); return err; } kfree_skb(skb); return 0; }
int btintel_enter_mfg(struct hci_dev *hdev) { const u8 param[] = { 0x01, 0x00 }; struct sk_buff *skb; skb = __hci_cmd_sync(hdev, 0xfc11, 2, param, HCI_CMD_TIMEOUT); if (IS_ERR(skb)) { bt_dev_err(hdev, "Entering manufacturer mode failed (%ld)", PTR_ERR(skb)); return PTR_ERR(skb); } kfree_skb(skb); return 0; }
static int btusb_setup_bcm92035(struct hci_dev *hdev) { struct sk_buff *skb; u8 val = 0x00; BT_DBG("%s", hdev->name); skb = __hci_cmd_sync(hdev, 0xfc3b, 1, &val, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) BT_ERR("BCM92035 command failed (%ld)", -PTR_ERR(skb)); else kfree_skb(skb); return 0; }
int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) { struct sk_buff *skb; int err; skb = __hci_cmd_sync(hdev, 0xfc31, 6, bdaddr, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { err = PTR_ERR(skb); BT_ERR("%s: Changing Intel device address failed (%d)", hdev->name, err); return err; } kfree_skb(skb); return 0; }
int btbcm_check_bdaddr(struct hci_dev *hdev) { struct hci_rp_read_bd_addr *bda; struct sk_buff *skb; skb = __hci_cmd_sync(hdev, HCI_OP_READ_BD_ADDR, 0, NULL, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { int err = PTR_ERR(skb); BT_ERR("%s: BCM: Reading device address failed (%d)", hdev->name, err); return err; } if (skb->len != sizeof(*bda)) { BT_ERR("%s: BCM: Device address length mismatch", hdev->name); kfree_skb(skb); return -EIO; } bda = (struct hci_rp_read_bd_addr *)skb->data; /* Check if the address indicates a controller with either an * invalid or default address. In both cases the device needs * to be marked as not having a valid address. * * The address 00:20:70:02:A0:00 indicates a BCM20702A0 controller * with no configured address. * * The address 43:24:B3:00:00:00 indicates a BCM4324B3 controller * with waiting for configuration state. * * The address 43:30:B1:00:00:00 indicates a BCM4330B1 controller * with waiting for configuration state. */ if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0) || !bacmp(&bda->bdaddr, BDADDR_BCM4324B3) || !bacmp(&bda->bdaddr, BDADDR_BCM4330B1)) { BT_INFO("%s: BCM: Using default device address (%pMR)", hdev->name, &bda->bdaddr); set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); } kfree_skb(skb); return 0; }
static int btbcm_reset(struct hci_dev *hdev) { struct sk_buff *skb; skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { int err = PTR_ERR(skb); BT_ERR("%s: BCM: Reset failed (%d)", hdev->name, err); return err; } kfree_skb(skb); /* 100 msec delay for module to complete reset process */ msleep(100); return 0; }
static struct sk_buff *btbcm_read_usb_product(struct hci_dev *hdev) { struct sk_buff *skb; skb = __hci_cmd_sync(hdev, 0xfc5a, 0, NULL, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { BT_ERR("%s: BCM: Read USB product info failed (%ld)", hdev->name, PTR_ERR(skb)); return skb; } if (skb->len != 5) { BT_ERR("%s: BCM: USB product length mismatch", hdev->name); kfree_skb(skb); return ERR_PTR(-EIO); } return skb; }
static struct sk_buff *btbcm_read_verbose_config(struct hci_dev *hdev) { struct sk_buff *skb; skb = __hci_cmd_sync(hdev, 0xfc79, 0, NULL, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { BT_ERR("%s: BCM: Read verbose config info failed (%ld)", hdev->name, PTR_ERR(skb)); return skb; } if (skb->len != 7) { BT_ERR("%s: BCM: Verbose config length mismatch", hdev->name); kfree_skb(skb); return ERR_PTR(-EIO); } return skb; }
int btintel_load_ddc_config(struct hci_dev *hdev, const char *ddc_name) { const struct firmware *fw; struct sk_buff *skb; const u8 *fw_ptr; int err; err = request_firmware(&fw, ddc_name, &hdev->dev); if (err < 0) { bt_dev_err(hdev, "Failed to load Intel DDC file %s (%d)", ddc_name, err); return err; } bt_dev_info(hdev, "Found Intel DDC parameters: %s", ddc_name); fw_ptr = fw->data; /* DDC file contains one or more DDC structure which has * Length (1 byte), DDC ID (2 bytes), and DDC value (Length - 2). */ while (fw->size > fw_ptr - fw->data) { u8 cmd_plen = fw_ptr[0] + sizeof(u8); skb = __hci_cmd_sync(hdev, 0xfc8b, cmd_plen, fw_ptr, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { bt_dev_err(hdev, "Failed to send Intel_Write_DDC (%ld)", PTR_ERR(skb)); release_firmware(fw); return PTR_ERR(skb); } fw_ptr += cmd_plen; kfree_skb(skb); } release_firmware(fw); bt_dev_info(hdev, "Applying Intel DDC parameters completed"); return 0; }
int btintel_set_event_mask(struct hci_dev *hdev, bool debug) { u8 mask[8] = { 0x87, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; struct sk_buff *skb; int err; if (debug) mask[1] |= 0x62; skb = __hci_cmd_sync(hdev, 0xfc52, 8, mask, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { err = PTR_ERR(skb); BT_ERR("%s: Setting Intel event mask failed (%d)", hdev->name, err); return err; } kfree_skb(skb); return 0; }
static struct sk_buff *btbcm_read_controller_features(struct hci_dev *hdev) { struct sk_buff *skb; skb = __hci_cmd_sync(hdev, 0xfc6e, 0, NULL, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { BT_ERR("%s: BCM: Read controller features failed (%ld)", hdev->name, PTR_ERR(skb)); return skb; } if (skb->len != 9) { BT_ERR("%s: BCM: Controller features length mismatch", hdev->name); kfree_skb(skb); return ERR_PTR(-EIO); } return skb; }
static struct sk_buff *btbcm_read_local_version(struct hci_dev *hdev) { struct sk_buff *skb; skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { BT_ERR("%s: BCM: Reading local version info failed (%ld)", hdev->name, PTR_ERR(skb)); return skb; } if (skb->len != sizeof(struct hci_rp_read_local_version)) { BT_ERR("%s: BCM: Local version length mismatch", hdev->name); kfree_skb(skb); return ERR_PTR(-EIO); } return skb; }
static int ath_vendor_cmd(struct hci_dev *hdev, uint8_t opcode, uint16_t index, const void *data, size_t dlen) { struct sk_buff *skb; struct ath_vendor_cmd cmd; if (dlen > sizeof(cmd.data)) return -EINVAL; cmd.opcode = opcode; cmd.index = cpu_to_le16(index); cmd.len = dlen; memcpy(cmd.data, data, dlen); skb = __hci_cmd_sync(hdev, 0xfc0b, dlen + 4, &cmd, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) return PTR_ERR(skb); kfree_skb(skb); return 0; }
static int btusb_setup_csr(struct hci_dev *hdev) { struct hci_rp_read_local_version *rp; struct sk_buff *skb; int ret; BT_DBG("%s", hdev->name); skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { BT_ERR("Reading local version failed (%ld)", -PTR_ERR(skb)); return -PTR_ERR(skb); } rp = (struct hci_rp_read_local_version *) skb->data; if (!rp->status) { if (le16_to_cpu(rp->manufacturer) != 10) { /* Clear the reset quirk since this is not an actual * early Bluetooth 1.1 device from CSR. */ clear_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks); /* These fake CSR controllers have all a broken * stored link key handling and so just disable it. */ set_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, &hdev->quirks); } } ret = -bt_to_errno(rp->status); kfree_skb(skb); return ret; }
int btintel_read_version(struct hci_dev *hdev, struct intel_version *ver) { struct sk_buff *skb; 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); } if (skb->len != sizeof(*ver)) { bt_dev_err(hdev, "Intel version event size mismatch"); kfree_skb(skb); return -EILSEQ; } memcpy(ver, skb->data, sizeof(*ver)); kfree_skb(skb); return 0; }
int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, u32 plen, const void *param) { while (plen > 0) { struct sk_buff *skb; u8 cmd_param[253], fragment_len = (plen > 252) ? 252 : plen; cmd_param[0] = fragment_type; memcpy(cmd_param + 1, param, fragment_len); skb = __hci_cmd_sync(hdev, 0xfc09, fragment_len + 1, cmd_param, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) return PTR_ERR(skb); kfree_skb(skb); plen -= fragment_len; param += fragment_len; } return 0; }
int btintel_enter_mfg(struct hci_dev *hdev) { const u8 param[] = { 0x01, 0x00 }; struct sk_buff *skb; if (hdev == NULL) { return -1; } skb = __hci_cmd_sync(hdev, CMD_MANUFACTURER_MODE, 2, param, HCI_CMD_TIMEOUT); if (IS_ERR(skb)) { BT_ERR("%s: Entering manufacturer mode failed (%ld)", hdev->name, PTR_ERR(skb)); return PTR_ERR(skb); } else { BT_INFO("Entering manufacturer mode successful"); } kfree_skb(skb); return 0; }
int btintel_exit_mfg(struct hci_dev *hdev, bool reset, bool patched) { u8 param[] = { 0x00, 0x00 }; struct sk_buff *skb; /* The 2nd command parameter specifies the manufacturing exit method: * 0x00: Just disable the manufacturing mode (0x00). * 0x01: Disable manufacturing mode and reset with patches deactivated. * 0x02: Disable manufacturing mode and reset with patches activated. */ if (reset) param[1] |= patched ? 0x02 : 0x01; skb = __hci_cmd_sync(hdev, 0xfc11, 2, param, HCI_CMD_TIMEOUT); if (IS_ERR(skb)) { bt_dev_err(hdev, "Exiting manufacturer mode failed (%ld)", PTR_ERR(skb)); return PTR_ERR(skb); } kfree_skb(skb); return 0; }
static int ath_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) { struct sk_buff *skb; u8 buf[10]; int err; buf[0] = 0x01; buf[1] = 0x01; buf[2] = 0x00; buf[3] = sizeof(bdaddr_t); memcpy(buf + 4, bdaddr, sizeof(bdaddr_t)); skb = __hci_cmd_sync(hdev, 0xfc0b, sizeof(buf), buf, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { err = PTR_ERR(skb); BT_ERR("%s: Change address command failed (%d)", hdev->name, err); return err; } kfree_skb(skb); return 0; }
int btintel_check_bdaddr(struct hci_dev *hdev) { struct hci_rp_read_bd_addr *bda; struct sk_buff *skb; skb = __hci_cmd_sync(hdev, HCI_OP_READ_BD_ADDR, 0, NULL, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { int err = PTR_ERR(skb); BT_ERR("%s: Reading Intel device address failed (%d)", hdev->name, err); return err; } if (skb->len != sizeof(*bda)) { BT_ERR("%s: Intel device address length mismatch", hdev->name); kfree_skb(skb); return -EIO; } bda = (struct hci_rp_read_bd_addr *)skb->data; /* For some Intel based controllers, the default Bluetooth device * address 00:03:19:9E:8B:00 can be found. These controllers are * fully operational, but have the danger of duplicate addresses * and that in turn can cause problems with Bluetooth operation. */ if (!bacmp(&bda->bdaddr, BDADDR_INTEL)) { BT_ERR("%s: Found Intel default device address (%pMR)", hdev->name, &bda->bdaddr); set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); } kfree_skb(skb); return 0; }