1// Copyright 2018 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <assert.h> 6#include <ddk/binding.h> 7#include <ddk/debug.h> 8#include <ddk/device.h> 9#include <ddk/driver.h> 10#include <ddk/protocol/bt-hci.h> 11#include <ddk/protocol/platform-defs.h> 12#include <ddk/protocol/serial.h> 13#include <stdio.h> 14#include <stdlib.h> 15#include <string.h> 16#include <threads.h> 17#include <zircon/device/bt-hci.h> 18#include <zircon/status.h> 19#include <zircon/threads.h> 20 21// TODO: how can we parameterize this? 22#define TARGET_BAUD_RATE 2000000 23 24#define FIRMWARE_PATH "/boot/lib/firmware/BCM4345C4.bin" 25 26#define FIRMWARE_DOWNLOAD_DELAY ZX_MSEC(50) 27 28// Hardcoded. Better to paramaterize on chipset. 29// Broadcom chips need a few hundred msec delay 30// after firmware load 31#define BAUD_RATE_SWITCH_DELAY ZX_MSEC(200) 32 33typedef struct { 34 uint16_t opcode; 35 uint8_t parameter_total_size; 36} __PACKED hci_command_header_t; 37 38typedef struct { 39 uint8_t event_code; 40 uint8_t parameter_total_size; 41} __PACKED hci_event_header_t; 42 43typedef struct { 44 hci_event_header_t header; 45 uint8_t num_hci_command_packets; 46 uint16_t command_opcode; 47 uint8_t return_code; 48} __PACKED hci_command_complete_t; 49 50// HCI reset command 51const hci_command_header_t RESET_CMD = { 52 .opcode = 0x0c03, 53 .parameter_total_size = 0, 54}; 55 56// vendor command to begin firmware download 57const hci_command_header_t START_FIRMWARE_DOWNLOAD_CMD = { 58 .opcode = 0xfc2e, 59 .parameter_total_size = 0, 60}; 61 62typedef struct { 63 hci_command_header_t header; 64 uint16_t unused; 65 uint32_t baud_rate; 66} __PACKED bcm_set_baud_rate_cmd_t; 67#define BCM_SET_BAUD_RATE_CMD 0xfc18 68 69#define HCI_EVT_COMMAND_COMPLETE 0x0e 70 71typedef struct { 72 zx_device_t* zxdev; 73 zx_device_t* transport_dev; 74 bt_hci_protocol_t hci; 75 serial_protocol_t serial; 76 zx_handle_t command_channel; 77 bool is_uart; // true if underlying transport is UART 78} bcm_hci_t; 79 80static zx_status_t bcm_hci_get_protocol(void* ctx, uint32_t proto_id, void* out_proto) { 81 if (proto_id != ZX_PROTOCOL_BT_HCI) { 82 return ZX_ERR_NOT_SUPPORTED; 83 } 84 85 bcm_hci_t* hci = ctx; 86 bt_hci_protocol_t* hci_proto = out_proto; 87 88 // Forward the underlying bt-transport ops. 89 hci_proto->ops = hci->hci.ops; 90 hci_proto->ctx = hci->hci.ctx; 91 92 return ZX_OK; 93} 94 95static zx_status_t bcm_hci_ioctl(void* ctx, uint32_t op, const void* in_buf, size_t in_len, 96 void* out_buf, size_t out_len, size_t* out_actual) { 97 bcm_hci_t* hci = ctx; 98 if (out_len < sizeof(zx_handle_t)) { 99 return ZX_ERR_BUFFER_TOO_SMALL; 100 } 101 102 zx_handle_t* reply = out_buf; 103 104 zx_status_t status = ZX_ERR_NOT_SUPPORTED; 105 if (op == IOCTL_BT_HCI_GET_COMMAND_CHANNEL) { 106 status = bt_hci_open_command_channel(&hci->hci, reply); 107 } else if (op == IOCTL_BT_HCI_GET_ACL_DATA_CHANNEL) { 108 status = bt_hci_open_acl_data_channel(&hci->hci, reply); 109 } else if (op == IOCTL_BT_HCI_GET_SNOOP_CHANNEL) { 110 status = bt_hci_open_snoop_channel(&hci->hci, reply); 111 } 112 113 if (status != ZX_OK) { 114 return status; 115 } 116 117 *out_actual = sizeof(*reply); 118 return ZX_OK; 119} 120 121static void bcm_hci_unbind(void* ctx) { 122 bcm_hci_t* hci = ctx; 123 124 device_remove(hci->zxdev); 125} 126 127static void bcm_hci_release(void* ctx) { 128 bcm_hci_t* hci = ctx; 129 130 if (hci->command_channel != ZX_HANDLE_INVALID) { 131 zx_handle_close(hci->command_channel); 132 } 133 134 free(hci); 135} 136 137static zx_protocol_device_t bcm_hci_device_proto = { 138 .version = DEVICE_OPS_VERSION, 139 .get_protocol = bcm_hci_get_protocol, 140 .ioctl = bcm_hci_ioctl, 141 .unbind = bcm_hci_unbind, 142 .release = bcm_hci_release, 143}; 144 145 146static zx_status_t bcm_hci_send_command(bcm_hci_t* hci, const hci_command_header_t* command, 147 size_t length) { 148 // send HCI command 149 zx_status_t status = zx_channel_write(hci->command_channel, 0, command, length, NULL, 0); 150 if (status != ZX_OK) { 151 zxlogf(ERROR, "bcm_hci_send_command zx_channel_write failed %s\n", 152 zx_status_get_string(status)); 153 return status; 154 } 155 156 // wait for command complete 157 uint8_t event_buf[255 + 2]; 158 uint32_t actual; 159 160 do { 161 status = zx_channel_read(hci->command_channel, 0, event_buf, NULL, sizeof(event_buf), 0, 162 &actual, NULL); 163 if (status == ZX_ERR_SHOULD_WAIT) { 164 zx_object_wait_one(hci->command_channel, ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED, 165 zx_deadline_after(ZX_SEC(5)), NULL); 166 } 167 } while (status == ZX_ERR_SHOULD_WAIT); 168 169 if (status != ZX_OK) { 170 zxlogf(ERROR, "bcm_hci_send_command zx_channel_read failed %s\n", 171 zx_status_get_string(status)); 172 return status; 173 } 174 175 hci_event_header_t* header = (hci_event_header_t *)event_buf; 176 if (header->event_code != HCI_EVT_COMMAND_COMPLETE || header->parameter_total_size 177 != sizeof(hci_command_complete_t) - sizeof(hci_event_header_t)) { 178 zxlogf(ERROR, "bcm_hci_send_command did not receive command complete\n"); 179 return ZX_ERR_INTERNAL; 180 } 181 hci_command_complete_t* event = (hci_command_complete_t *)event_buf; 182 if (event->return_code != 0) { 183 zxlogf(ERROR, "bcm_hci_send_command got command complete error %u\n", event->return_code); 184 return ZX_ERR_INTERNAL; 185 } 186 187 return ZX_OK; 188} 189 190static zx_status_t bcm_hci_set_baud_rate(bcm_hci_t* hci, uint32_t baud_rate) { 191 bcm_set_baud_rate_cmd_t command = { 192 .header = { 193 .opcode = BCM_SET_BAUD_RATE_CMD, 194 .parameter_total_size = sizeof(bcm_set_baud_rate_cmd_t) - sizeof(hci_command_header_t), 195 }, 196 .unused = 0, 197 .baud_rate = htole32(baud_rate), 198 }; 199 200 zx_status_t status = bcm_hci_send_command(hci, &command.header, sizeof(command)); 201 if (status != ZX_OK) { 202 return status; 203 } 204 205 return serial_config(&hci->serial, TARGET_BAUD_RATE, SERIAL_SET_BAUD_RATE_ONLY); 206} 207 208 209static int bcm_hci_start_thread(void* arg) { 210 bcm_hci_t* hci = arg; 211 zx_handle_t fw_vmo; 212 213 zx_status_t status = bt_hci_open_command_channel(&hci->hci, &hci->command_channel); 214 if (status != ZX_OK) { 215 goto fail; 216 } 217 218 // Send Reset command 219 status = bcm_hci_send_command(hci, &RESET_CMD, sizeof(RESET_CMD)); 220 if (status != ZX_OK) { 221 goto fail; 222 } 223 224 if (hci->is_uart) { 225 // switch baud rate to TARGET_BAUD_RATE 226 status = bcm_hci_set_baud_rate(hci, TARGET_BAUD_RATE); 227 if (status != ZX_OK) { 228 goto fail; 229 } 230 } 231 232 size_t fw_size; 233 status = load_firmware(hci->zxdev, FIRMWARE_PATH, &fw_vmo, &fw_size); 234 if (status == ZX_OK) { 235 status = bcm_hci_send_command(hci, &START_FIRMWARE_DOWNLOAD_CMD, 236 sizeof(START_FIRMWARE_DOWNLOAD_CMD)); 237 if (status != ZX_OK) { 238 goto fail; 239 } 240 241 // give time for placing firmware in download mode 242 zx_nanosleep(zx_deadline_after(FIRMWARE_DOWNLOAD_DELAY)); 243 244 zx_off_t offset = 0; 245 while (offset < fw_size) { 246 uint8_t buffer[255 + 3]; 247 248 size_t remaining = fw_size - offset; 249 size_t read_amount = (remaining > sizeof(buffer) ? sizeof(buffer) : remaining); 250 251 if (read_amount < 3) { 252 zxlogf(ERROR, "short HCI command in firmware download\n"); 253 status = ZX_ERR_INTERNAL; 254 goto vmo_close_fail; 255 } 256 257 status = zx_vmo_read(fw_vmo, buffer, offset, read_amount); 258 if (status != ZX_OK) { 259 goto vmo_close_fail; 260 } 261 262 hci_command_header_t* header = (hci_command_header_t *)buffer; 263 size_t length = header->parameter_total_size + sizeof(*header); 264 if (read_amount < length) { 265 zxlogf(ERROR, "short HCI command in firmware download\n"); 266 status = ZX_ERR_INTERNAL; 267 goto vmo_close_fail; 268 } 269 status = bcm_hci_send_command(hci, header, length); 270 if (status != ZX_OK) { 271 zxlogf(ERROR, "bcm_hci_send_command failed in firmware download: %s\n", 272 zx_status_get_string(status)); 273 goto vmo_close_fail; 274 } 275 offset += length; 276 } 277 278 zx_handle_close(fw_vmo); 279 280 if (hci->is_uart) { 281 // firmware switched us back to 115200. switch back to TARGET_BAUD_RATE 282 status = serial_config(&hci->serial, 115200, SERIAL_SET_BAUD_RATE_ONLY); 283 if (status != ZX_OK) { 284 goto fail; 285 } 286 287 // switch baud rate to TARGET_BAUD_RATE after DELAY 288 zx_nanosleep(zx_deadline_after(BAUD_RATE_SWITCH_DELAY)); 289 status = bcm_hci_set_baud_rate(hci, TARGET_BAUD_RATE); 290 if (status != ZX_OK) { 291 goto fail; 292 } 293 } 294 } else { 295 zxlogf(INFO, "bcm-hci: no firmware file found\n"); 296 } 297 298 // We're done with the command channel. Close it so that it can be opened by 299 // the host stack after the device becomes visible. 300 zx_handle_close(hci->command_channel); 301 hci->command_channel = ZX_HANDLE_INVALID; 302 303 device_make_visible(hci->zxdev); 304 return 0; 305 306vmo_close_fail: 307 zx_handle_close(fw_vmo); 308fail: 309 zxlogf(ERROR, "bcm_hci_start_thread: device initialization failed: %s\n", 310 zx_status_get_string(status)); 311 312 device_remove(hci->zxdev); 313 return -1; 314} 315 316static zx_status_t bcm_hci_bind(void* ctx, zx_device_t* device) { 317 bcm_hci_t* hci = calloc(1, sizeof(bcm_hci_t)); 318 if (!hci) { 319 return ZX_ERR_NO_MEMORY; 320 } 321 322 zx_status_t status = device_get_protocol(device, ZX_PROTOCOL_BT_HCI, &hci->hci); 323 if (status != ZX_OK) { 324 zxlogf(ERROR, "bcm_hci_bind: get protocol ZX_PROTOCOL_BT_HCI failed\n"); 325 return status; 326 } 327 status = device_get_protocol(device, ZX_PROTOCOL_SERIAL, &hci->serial); 328 if (status == ZX_OK) { 329 hci->is_uart = true; 330 } 331 332 device_add_args_t args = { 333 .version = DEVICE_ADD_ARGS_VERSION, 334 .name = "bcm-hci", 335 .ctx = hci, 336 .ops = &bcm_hci_device_proto, 337 .proto_id = ZX_PROTOCOL_BT_HCI, 338 .flags = DEVICE_ADD_INVISIBLE, 339 }; 340 341 hci->transport_dev = device; 342 343 status = device_add(device, &args, &hci->zxdev); 344 if (status != ZX_OK) { 345 bcm_hci_release(hci); 346 return status; 347 } 348 349 // create thread to continue initialization 350 thrd_t t; 351 int thrd_rc = thrd_create_with_name(&t, bcm_hci_start_thread, hci, "bcm_hci_start_thread"); 352 if (thrd_rc != thrd_success) { 353 device_remove(hci->zxdev); 354 bcm_hci_release(hci); 355 return thrd_status_to_zx_status(thrd_rc); 356 } 357 358 return ZX_OK; 359} 360 361static zx_driver_ops_t bcm_hci_driver_ops = { 362 .version = DRIVER_OPS_VERSION, 363 .bind = bcm_hci_bind, 364}; 365 366// clang-format off 367ZIRCON_DRIVER_BEGIN(bcm_hci, bcm_hci_driver_ops, "zircon", "0.1", 2) 368 BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_BT_TRANSPORT), 369 BI_MATCH_IF(EQ, BIND_SERIAL_VID, PDEV_VID_BROADCOM), 370ZIRCON_DRIVER_END(bcm_hci) 371