Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/next/external/cache/sources/hcitools/hciattach_qualcomm.c
Views: 3959
/*1*2* BlueZ - Bluetooth protocol stack for Linux3*4* Copyright (C) 2005-2010 Marcel Holtmann <[email protected]>5* Copyright (c) 2010, Code Aurora Forum. All rights reserved.6*7*8* This program is free software; you can redistribute it and/or modify9* it under the terms of the GNU General Public License as published by10* the Free Software Foundation; either version 2 of the License, or11* (at your option) any later version.12*13* This program is distributed in the hope that it will be useful,14* but WITHOUT ANY WARRANTY; without even the implied warranty of15* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the16* GNU General Public License for more details.17*18* You should have received a copy of the GNU General Public License19* along with this program; if not, write to the Free Software20* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA21*22*/2324#ifdef HAVE_CONFIG_H25#include <config.h>26#endif2728#include <stdio.h>29#include <errno.h>30#include <fcntl.h>31#include <unistd.h>32#include <stdlib.h>33#include <string.h>34#include <signal.h>35#include <syslog.h>36#include <termios.h>37#include <time.h>38#include <sys/time.h>39#include <sys/poll.h>40#include <sys/param.h>41#include <sys/ioctl.h>4243#include <bluetooth/bluetooth.h>44#include <bluetooth/hci.h>45#include <bluetooth/hci_lib.h>4647#include "hciattach.h"4849#define FAILIF(x, args...) do { \50if (x) { \51fprintf(stderr, ##args); \52return -1; \53} \54} while (0)5556typedef struct {57uint8_t uart_prefix;58hci_event_hdr hci_hdr;59evt_cmd_complete cmd_complete;60uint8_t status;61uint8_t data[16];62} __attribute__((packed)) command_complete_t;6364static int read_command_complete(int fd,65unsigned short opcode,66unsigned char len)67{68command_complete_t resp;69unsigned char vsevent[512];70int n;7172/* Read reply. */73n = read_hci_event(fd, vsevent, sizeof(vsevent));74FAILIF(n < 0, "Failed to read response");7576FAILIF(vsevent[1] != 0xFF, "Failed to read response");7778n = read_hci_event(fd, (unsigned char *)&resp, sizeof(resp));79FAILIF(n < 0, "Failed to read response");8081/* event must be event-complete */82FAILIF(resp.hci_hdr.evt != EVT_CMD_COMPLETE,83"Error in response: not a cmd-complete event, "84"but 0x%02x!\n", resp.hci_hdr.evt);8586FAILIF(resp.hci_hdr.plen < 4, /* plen >= 4 for EVT_CMD_COMPLETE */87"Error in response: plen is not >= 4, but 0x%02x!\n",88resp.hci_hdr.plen);8990/* cmd-complete event: opcode */91FAILIF(resp.cmd_complete.opcode != 0,92"Error in response: opcode is 0x%04x, not 0!",93resp.cmd_complete.opcode);9495return resp.status == 0 ? 0 : -1;96}9798static int qualcomm_load_firmware(int fd, const char *firmware, const char *bdaddr_s)99{100101int fw = open(firmware, O_RDONLY);102103fprintf(stdout, "Opening firmware file: %s\n", firmware);104105FAILIF(fw < 0,106"Could not open firmware file %s: %s (%d).\n",107firmware, strerror(errno), errno);108109fprintf(stdout, "Uploading firmware...\n");110do {111/* Read each command and wait for a response. */112unsigned char data[1024];113unsigned char cmdp[1 + sizeof(hci_command_hdr)];114hci_command_hdr *cmd = (hci_command_hdr *) (cmdp + 1);115int nr;116117nr = read(fw, cmdp, sizeof(cmdp));118if (!nr)119break;120121FAILIF(nr != sizeof(cmdp),122"Could not read H4 + HCI header!\n");123FAILIF(*cmdp != HCI_COMMAND_PKT,124"Command is not an H4 command packet!\n");125126FAILIF(read(fw, data, cmd->plen) != cmd->plen,127"Could not read %d bytes of data \128for command with opcode %04x!\n",129cmd->plen, cmd->opcode);130131if ((data[0] == 1) && (data[1] == 2) && (data[2] == 6)) {132bdaddr_t bdaddr;133if (bdaddr_s != NULL) {134str2ba(bdaddr_s, &bdaddr);135memcpy(&data[3], &bdaddr, sizeof(bdaddr_t));136}137}138139{140int nw;141struct iovec iov_cmd[2];142iov_cmd[0].iov_base = cmdp;143iov_cmd[0].iov_len = sizeof(cmdp);144iov_cmd[1].iov_base = data;145iov_cmd[1].iov_len = cmd->plen;146nw = writev(fd, iov_cmd, 2);147FAILIF(nw != (int) sizeof(cmdp) + cmd->plen,148"Could not send entire command \149(sent only %d bytes)!\n",150nw);151}152153/* Wait for response */154if (read_command_complete(fd, cmd->opcode, cmd->plen) < 0)155return -1;156} while (1);157fprintf(stdout, "Firmware upload successful.\n");158159close(fw);160161return 0;162}163164int qualcomm_init(int fd, int speed, struct termios *ti, const char *bdaddr)165{166struct timespec tm = {0, 50000};167char cmd[5];168unsigned char resp[100]; /* Response */169char fw[100];170int n;171172memset(resp, 0, 100);173174/* Get Manufacturer and LMP version */175cmd[0] = HCI_COMMAND_PKT;176cmd[1] = 0x01;177cmd[2] = 0x10;178cmd[3] = 0x00;179180do {181n = write(fd, cmd, 4);182if (n < 4) {183perror("Failed to write init command");184return -1;185}186187/* Read reply. */188if (read_hci_event(fd, resp, 100) < 0) {189perror("Failed to read init response");190return -1;191}192193/* Wait for command complete event for our Opcode */194} while (resp[4] != cmd[1] && resp[5] != cmd[2]);195196/* Verify manufacturer */197if ((resp[11] & 0xFF) != 0x1d)198fprintf(stderr,199"WARNING : module's manufacturer is not Qualcomm\n");200201/* Print LMP version */202fprintf(stderr,203"Qualcomm module LMP version : 0x%02x\n", resp[10] & 0xFF);204205/* Print LMP subversion */206{207unsigned short lmp_subv = resp[13] | (resp[14] << 8);208209fprintf(stderr, "Qualcomm module LMP sub-version : 0x%04x\n",210lmp_subv);211}212213/* Get SoC type */214cmd[0] = HCI_COMMAND_PKT;215cmd[1] = 0x00;216cmd[2] = 0xFC;217cmd[3] = 0x01;218cmd[4] = 0x06;219220do {221n = write(fd, cmd, 5);222if (n < 5) {223perror("Failed to write vendor init command");224return -1;225}226227/* Read reply. */228if ((n = read_hci_event(fd, resp, 100)) < 0) {229perror("Failed to read vendor init response");230return -1;231}232233} while (resp[3] != 0 && resp[4] != 2);234235snprintf(fw, sizeof(fw), "/etc/firmware/%c%c%c%c%c%c_%c%c%c%c.bin",236resp[18], resp[19], resp[20], resp[21],237resp[22], resp[23],238resp[32], resp[33], resp[34], resp[35]);239240/* Wait for command complete event for our Opcode */241if (read_hci_event(fd, resp, 100) < 0) {242perror("Failed to read init response");243return -1;244}245246qualcomm_load_firmware(fd, fw, bdaddr);247248/* Reset */249cmd[0] = HCI_COMMAND_PKT;250cmd[1] = 0x03;251cmd[2] = 0x0C;252cmd[3] = 0x00;253254do {255n = write(fd, cmd, 4);256if (n < 4) {257perror("Failed to write reset command");258return -1;259}260261/* Read reply. */262if ((n = read_hci_event(fd, resp, 100)) < 0) {263perror("Failed to read reset response");264return -1;265}266267} while (resp[4] != cmd[1] && resp[5] != cmd[2]);268269nanosleep(&tm, NULL);270271return 0;272}273274275