diff options
Diffstat (limited to 'drivers/bluetooth/btbcm.c')
| -rw-r--r-- | drivers/bluetooth/btbcm.c | 148 |
1 files changed, 79 insertions, 69 deletions
diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c index d0741f3ed7ec..4bba86677adc 100644 --- a/drivers/bluetooth/btbcm.c +++ b/drivers/bluetooth/btbcm.c | |||
| @@ -95,6 +95,78 @@ int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) | |||
| 95 | } | 95 | } |
| 96 | EXPORT_SYMBOL_GPL(btbcm_set_bdaddr); | 96 | EXPORT_SYMBOL_GPL(btbcm_set_bdaddr); |
| 97 | 97 | ||
| 98 | int btbcm_patchram(struct hci_dev *hdev, const char *firmware) | ||
| 99 | { | ||
| 100 | const struct hci_command_hdr *cmd; | ||
| 101 | const struct firmware *fw; | ||
| 102 | const u8 *fw_ptr; | ||
| 103 | size_t fw_size; | ||
| 104 | struct sk_buff *skb; | ||
| 105 | u16 opcode; | ||
| 106 | int err; | ||
| 107 | |||
| 108 | err = request_firmware(&fw, firmware, &hdev->dev); | ||
| 109 | if (err < 0) { | ||
| 110 | BT_INFO("%s: BCM: Patch %s not found", hdev->name, firmware); | ||
| 111 | return err; | ||
| 112 | } | ||
| 113 | |||
| 114 | /* Start Download */ | ||
| 115 | skb = __hci_cmd_sync(hdev, 0xfc2e, 0, NULL, HCI_INIT_TIMEOUT); | ||
| 116 | if (IS_ERR(skb)) { | ||
| 117 | err = PTR_ERR(skb); | ||
| 118 | BT_ERR("%s: BCM: Download Minidrv command failed (%d)", | ||
| 119 | hdev->name, err); | ||
| 120 | goto done; | ||
| 121 | } | ||
| 122 | kfree_skb(skb); | ||
| 123 | |||
| 124 | /* 50 msec delay after Download Minidrv completes */ | ||
| 125 | msleep(50); | ||
| 126 | |||
| 127 | fw_ptr = fw->data; | ||
| 128 | fw_size = fw->size; | ||
| 129 | |||
| 130 | while (fw_size >= sizeof(*cmd)) { | ||
| 131 | const u8 *cmd_param; | ||
| 132 | |||
| 133 | cmd = (struct hci_command_hdr *)fw_ptr; | ||
| 134 | fw_ptr += sizeof(*cmd); | ||
| 135 | fw_size -= sizeof(*cmd); | ||
| 136 | |||
| 137 | if (fw_size < cmd->plen) { | ||
| 138 | BT_ERR("%s: BCM: Patch %s is corrupted", hdev->name, | ||
| 139 | firmware); | ||
| 140 | err = -EINVAL; | ||
| 141 | goto done; | ||
| 142 | } | ||
| 143 | |||
| 144 | cmd_param = fw_ptr; | ||
| 145 | fw_ptr += cmd->plen; | ||
| 146 | fw_size -= cmd->plen; | ||
| 147 | |||
| 148 | opcode = le16_to_cpu(cmd->opcode); | ||
| 149 | |||
| 150 | skb = __hci_cmd_sync(hdev, opcode, cmd->plen, cmd_param, | ||
| 151 | HCI_INIT_TIMEOUT); | ||
| 152 | if (IS_ERR(skb)) { | ||
| 153 | err = PTR_ERR(skb); | ||
| 154 | BT_ERR("%s: BCM: Patch command %04x failed (%d)", | ||
| 155 | hdev->name, opcode, err); | ||
| 156 | goto done; | ||
| 157 | } | ||
| 158 | kfree_skb(skb); | ||
| 159 | } | ||
| 160 | |||
| 161 | /* 250 msec delay after Launch Ram completes */ | ||
| 162 | msleep(250); | ||
| 163 | |||
| 164 | done: | ||
| 165 | release_firmware(fw); | ||
| 166 | return err; | ||
| 167 | } | ||
| 168 | EXPORT_SYMBOL(btbcm_patchram); | ||
| 169 | |||
| 98 | static int btbcm_reset(struct hci_dev *hdev) | 170 | static int btbcm_reset(struct hci_dev *hdev) |
| 99 | { | 171 | { |
| 100 | struct sk_buff *skb; | 172 | struct sk_buff *skb; |
| @@ -198,12 +270,8 @@ static const struct { | |||
| 198 | 270 | ||
| 199 | int btbcm_setup_patchram(struct hci_dev *hdev) | 271 | int btbcm_setup_patchram(struct hci_dev *hdev) |
| 200 | { | 272 | { |
| 201 | const struct hci_command_hdr *cmd; | ||
| 202 | const struct firmware *fw; | ||
| 203 | const u8 *fw_ptr; | ||
| 204 | size_t fw_size; | ||
| 205 | char fw_name[64]; | 273 | char fw_name[64]; |
| 206 | u16 opcode, subver, rev, pid, vid; | 274 | u16 subver, rev, pid, vid; |
| 207 | const char *hw_name = NULL; | 275 | const char *hw_name = NULL; |
| 208 | struct sk_buff *skb; | 276 | struct sk_buff *skb; |
| 209 | struct hci_rp_read_local_version *ver; | 277 | struct hci_rp_read_local_version *ver; |
| @@ -273,74 +341,19 @@ int btbcm_setup_patchram(struct hci_dev *hdev) | |||
| 273 | hw_name ? : "BCM", (subver & 0x7000) >> 13, | 341 | hw_name ? : "BCM", (subver & 0x7000) >> 13, |
| 274 | (subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff); | 342 | (subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff); |
| 275 | 343 | ||
| 276 | err = request_firmware(&fw, fw_name, &hdev->dev); | 344 | err = btbcm_patchram(hdev, fw_name); |
| 277 | if (err < 0) { | 345 | if (err == -ENOENT) |
| 278 | BT_INFO("%s: BCM: patch %s not found", hdev->name, fw_name); | ||
| 279 | return 0; | 346 | return 0; |
| 280 | } | ||
| 281 | |||
| 282 | /* Start Download */ | ||
| 283 | skb = __hci_cmd_sync(hdev, 0xfc2e, 0, NULL, HCI_INIT_TIMEOUT); | ||
| 284 | if (IS_ERR(skb)) { | ||
| 285 | err = PTR_ERR(skb); | ||
| 286 | BT_ERR("%s: BCM: Download Minidrv command failed (%d)", | ||
| 287 | hdev->name, err); | ||
| 288 | goto reset; | ||
| 289 | } | ||
| 290 | kfree_skb(skb); | ||
| 291 | |||
| 292 | /* 50 msec delay after Download Minidrv completes */ | ||
| 293 | msleep(50); | ||
| 294 | |||
| 295 | fw_ptr = fw->data; | ||
| 296 | fw_size = fw->size; | ||
| 297 | |||
| 298 | while (fw_size >= sizeof(*cmd)) { | ||
| 299 | const u8 *cmd_param; | ||
| 300 | |||
| 301 | cmd = (struct hci_command_hdr *)fw_ptr; | ||
| 302 | fw_ptr += sizeof(*cmd); | ||
| 303 | fw_size -= sizeof(*cmd); | ||
| 304 | |||
| 305 | if (fw_size < cmd->plen) { | ||
| 306 | BT_ERR("%s: BCM: patch %s is corrupted", hdev->name, | ||
| 307 | fw_name); | ||
| 308 | err = -EINVAL; | ||
| 309 | goto reset; | ||
| 310 | } | ||
| 311 | 347 | ||
| 312 | cmd_param = fw_ptr; | ||
| 313 | fw_ptr += cmd->plen; | ||
| 314 | fw_size -= cmd->plen; | ||
| 315 | |||
| 316 | opcode = le16_to_cpu(cmd->opcode); | ||
| 317 | |||
| 318 | skb = __hci_cmd_sync(hdev, opcode, cmd->plen, cmd_param, | ||
| 319 | HCI_INIT_TIMEOUT); | ||
| 320 | if (IS_ERR(skb)) { | ||
| 321 | err = PTR_ERR(skb); | ||
| 322 | BT_ERR("%s: BCM: patch command %04x failed (%d)", | ||
| 323 | hdev->name, opcode, err); | ||
| 324 | goto reset; | ||
| 325 | } | ||
| 326 | kfree_skb(skb); | ||
| 327 | } | ||
| 328 | |||
| 329 | /* 250 msec delay after Launch Ram completes */ | ||
| 330 | msleep(250); | ||
| 331 | |||
| 332 | reset: | ||
| 333 | /* Reset */ | 348 | /* Reset */ |
| 334 | err = btbcm_reset(hdev); | 349 | err = btbcm_reset(hdev); |
| 335 | if (err) | 350 | if (err) |
| 336 | goto done; | 351 | return err; |
| 337 | 352 | ||
| 338 | /* Read Local Version Info */ | 353 | /* Read Local Version Info */ |
| 339 | skb = btbcm_read_local_version(hdev); | 354 | skb = btbcm_read_local_version(hdev); |
| 340 | if (IS_ERR(skb)) { | 355 | if (IS_ERR(skb)) |
| 341 | err = PTR_ERR(skb); | 356 | return PTR_ERR(skb); |
| 342 | goto done; | ||
| 343 | } | ||
| 344 | 357 | ||
| 345 | ver = (struct hci_rp_read_local_version *)skb->data; | 358 | ver = (struct hci_rp_read_local_version *)skb->data; |
| 346 | rev = le16_to_cpu(ver->hci_rev); | 359 | rev = le16_to_cpu(ver->hci_rev); |
| @@ -355,10 +368,7 @@ reset: | |||
| 355 | 368 | ||
| 356 | set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); | 369 | set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); |
| 357 | 370 | ||
| 358 | done: | 371 | return 0; |
| 359 | release_firmware(fw); | ||
| 360 | |||
| 361 | return err; | ||
| 362 | } | 372 | } |
| 363 | EXPORT_SYMBOL_GPL(btbcm_setup_patchram); | 373 | EXPORT_SYMBOL_GPL(btbcm_setup_patchram); |
| 364 | 374 | ||
