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_intel.c
Views: 3959
/*1*2* BlueZ - Bluetooth protocol stack for Linux3*4* Copyright (C) 2012 Intel Corporation. All rights reserved.5*6*7* This program is free software; you can redistribute it and/or modify8* it under the terms of the GNU General Public License as published by9* the Free Software Foundation; either version 2 of the License, or10* (at your option) any later version.11*12* This program is distributed in the hope that it will be useful,13* but WITHOUT ANY WARRANTY; without even the implied warranty of14* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the15* GNU General Public License for more details.16*17* You should have received a copy of the GNU General Public License18* along with this program; if not, write to the Free Software19* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA20*21*/2223#ifdef HAVE_CONFIG_H24#include <config.h>25#endif2627#include <stdio.h>28#include <stdlib.h>29#include <unistd.h>30#include <string.h>31#include <errno.h>32#include <fcntl.h>33#include <sys/param.h>34#include <sys/ioctl.h>35#include <time.h>3637#include <bluetooth/bluetooth.h>38#include <bluetooth/hci.h>39#include <bluetooth/hci_lib.h>4041#include "hciattach.h"4243#ifdef INTEL_DEBUG44#define DBGPRINT(fmt, args...) printf("DBG: " fmt "\n", ## args)45#define PRINT_PACKET(buf, len, msg) { \46int i; \47printf("%s\n", msg); \48for (i = 0; i < len; i++) \49printf("%02X ", buf[i]); \50printf("\n"); \51}52#else53#define DBGPRINT(fmt, args...)54#define PRINT_PACKET(buf, len, msg)55#endif5657#define PATCH_SEQ_EXT ".bseq"58#define PATCH_FILE_PATH "/lib/firmware/intel/"59#define PATCH_MAX_LEN 26060#define PATCH_TYPE_CMD 161#define PATCH_TYPE_EVT 26263#define INTEL_VER_PARAM_LEN 964#define INTEL_MFG_PARAM_LEN 26566/**67* A data structure for a patch entry.68*/69struct patch_entry {70int type;71int len;72unsigned char data[PATCH_MAX_LEN];73};7475/**76* A structure for patch context77*/78struct patch_ctx {79int dev;80int fd;81int patch_error;82int reset_enable_patch;83};8485/**86* Send HCI command to the controller87*/88static int intel_write_cmd(int dev, unsigned char *buf, int len)89{90int ret;9192PRINT_PACKET(buf, len, "<----- SEND CMD: ");9394ret = write(dev, buf, len);95if (ret < 0)96return -errno;9798if (ret != len)99return -1;100101return ret;102}103104/**105* Read the event from the controller106*/107static int intel_read_evt(int dev, unsigned char *buf, int len)108{109int ret;110111ret = read_hci_event(dev, buf, len);112if (ret < 0)113return -1;114115PRINT_PACKET(buf, ret, "-----> READ EVT: ");116117return ret;118}119120/**121* Validate HCI events122*/123static int validate_events(struct patch_entry *event,124struct patch_entry *entry)125{126if (event == NULL || entry == NULL) {127DBGPRINT("invalid patch entry parameters");128return -1;129}130131if (event->len != entry->len) {132DBGPRINT("lengths are mismatched:[%d|%d]",133event->len, entry->len);134return -1;135}136137if (memcmp(event->data, entry->data, event->len)) {138DBGPRINT("data is mismatched");139return -1;140}141142return 0;143}144145/**146* Read the next patch entry one line at a time147*/148static int get_next_patch_entry(int fd, struct patch_entry *entry)149{150int size;151char rb;152153if (read(fd, &rb, 1) <= 0)154return 0;155156entry->type = rb;157158switch (entry->type) {159case PATCH_TYPE_CMD:160entry->data[0] = HCI_COMMAND_PKT;161162if (read(fd, &entry->data[1], 3) < 0)163return -1;164165size = (int)entry->data[3];166167if (read(fd, &entry->data[4], size) < 0)168return -1;169170entry->len = HCI_TYPE_LEN + HCI_COMMAND_HDR_SIZE + size;171172break;173174case PATCH_TYPE_EVT:175entry->data[0] = HCI_EVENT_PKT;176177if (read(fd, &entry->data[1], 2) < 0)178return -1;179180size = (int)entry->data[2];181182if (read(fd, &entry->data[3], size) < 0)183return -1;184185entry->len = HCI_TYPE_LEN + HCI_EVENT_HDR_SIZE + size;186187break;188189default:190fprintf(stderr, "invalid patch entry(%d)\n", entry->type);191return -1;192}193194return entry->len;195}196197/**198* Download the patch set to the controller and verify the event199*/200static int intel_download_patch(struct patch_ctx *ctx)201{202int ret;203struct patch_entry entry;204struct patch_entry event;205206DBGPRINT("start patch downloading");207208do {209ret = get_next_patch_entry(ctx->fd, &entry);210if (ret <= 0) {211ctx->patch_error = 1;212break;213}214215switch (entry.type) {216case PATCH_TYPE_CMD:217ret = intel_write_cmd(ctx->dev,218entry.data,219entry.len);220if (ret <= 0) {221fprintf(stderr, "failed to send cmd(%d)\n",222ret);223return ret;224}225break;226227case PATCH_TYPE_EVT:228ret = intel_read_evt(ctx->dev, event.data,229sizeof(event.data));230if (ret <= 0) {231fprintf(stderr, "failed to read evt(%d)\n",232ret);233return ret;234}235event.len = ret;236237if (validate_events(&event, &entry) < 0) {238DBGPRINT("events are mismatched");239ctx->patch_error = 1;240return -1;241}242break;243244default:245fprintf(stderr, "unknown patch type(%d)\n",246entry.type);247return -1;248}249} while (1);250251return ret;252}253254static int open_patch_file(struct patch_ctx *ctx, char *fw_ver)255{256char patch_file[PATH_MAX];257258snprintf(patch_file, PATH_MAX, "%s%s%s", PATCH_FILE_PATH,259fw_ver, PATCH_SEQ_EXT);260DBGPRINT("PATCH_FILE: %s", patch_file);261262ctx->fd = open(patch_file, O_RDONLY);263if (ctx->fd < 0) {264DBGPRINT("cannot open patch file. go to post patch");265return -1;266}267268return 0;269}270271/**272* Prepare the controller for patching.273*/274static int pre_patch(struct patch_ctx *ctx)275{276int ret, i;277struct patch_entry entry;278char fw_ver[INTEL_VER_PARAM_LEN * 2];279280DBGPRINT("start pre_patch");281282entry.data[0] = HCI_COMMAND_PKT;283entry.data[1] = 0x11;284entry.data[2] = 0xFC;285entry.data[3] = 0x02;286entry.data[4] = 0x01;287entry.data[5] = 0x00;288entry.len = HCI_TYPE_LEN + HCI_COMMAND_HDR_SIZE + INTEL_MFG_PARAM_LEN;289290ret = intel_write_cmd(ctx->dev, entry.data, entry.len);291if (ret < 0) {292fprintf(stderr, "failed to send cmd(%d)\n", ret);293return ret;294}295296ret = intel_read_evt(ctx->dev, entry.data, sizeof(entry.data));297if (ret < 0) {298fprintf(stderr, "failed to read evt(%d)\n", ret);299return ret;300}301entry.len = ret;302303if (entry.data[6] != 0x00) {304DBGPRINT("command failed. status=%02x", entry.data[6]);305ctx->patch_error = 1;306return -1;307}308309entry.data[0] = HCI_COMMAND_PKT;310entry.data[1] = 0x05;311entry.data[2] = 0xFC;312entry.data[3] = 0x00;313entry.len = HCI_TYPE_LEN + HCI_COMMAND_HDR_SIZE;314315ret = intel_write_cmd(ctx->dev, entry.data, entry.len);316if (ret < 0) {317fprintf(stderr, "failed to send cmd(%d)\n", ret);318return ret;319}320321ret = intel_read_evt(ctx->dev, entry.data, sizeof(entry.data));322if (ret < 0) {323fprintf(stderr, "failed to read evt(%d)\n", ret);324return ret;325}326entry.len = ret;327328if (entry.data[6] != 0x00) {329DBGPRINT("command failed. status=%02x", entry.data[6]);330ctx->patch_error = 1;331return -1;332}333334for (i = 0; i < INTEL_VER_PARAM_LEN; i++)335sprintf(&fw_ver[i*2], "%02x", entry.data[7+i]);336337if (open_patch_file(ctx, fw_ver) < 0) {338ctx->patch_error = 1;339return -1;340}341342return ret;343}344345/*346* check the event is startup event347*/348static int is_startup_evt(unsigned char *buf)349{350if (buf[1] == 0xFF && buf[2] == 0x01 && buf[3] == 0x00)351return 1;352353return 0;354}355356/**357* Finalize the patch process and reset the controller358*/359static int post_patch(struct patch_ctx *ctx)360{361int ret;362struct patch_entry entry;363364DBGPRINT("start post_patch");365366entry.data[0] = HCI_COMMAND_PKT;367entry.data[1] = 0x11;368entry.data[2] = 0xFC;369entry.data[3] = 0x02;370entry.data[4] = 0x00;371if (ctx->reset_enable_patch)372entry.data[5] = 0x02;373else374entry.data[5] = 0x01;375376entry.len = HCI_TYPE_LEN + HCI_COMMAND_HDR_SIZE + INTEL_MFG_PARAM_LEN;377378ret = intel_write_cmd(ctx->dev, entry.data, entry.len);379if (ret < 0) {380fprintf(stderr, "failed to send cmd(%d)\n", ret);381return ret;382}383384ret = intel_read_evt(ctx->dev, entry.data, sizeof(entry.data));385if (ret < 0) {386fprintf(stderr, "failed to read evt(%d)\n", ret);387return ret;388}389entry.len = ret;390391if (entry.data[6] != 0x00) {392fprintf(stderr, "cmd failed. st=%02x\n", entry.data[6]);393return -1;394}395396do {397ret = intel_read_evt(ctx->dev, entry.data,398sizeof(entry.data));399if (ret < 0) {400fprintf(stderr, "failed to read cmd(%d)\n", ret);401return ret;402}403entry.len = ret;404} while (!is_startup_evt(entry.data));405406return ret;407}408409/**410* Main routine that handles the device patching process.411*/412static int intel_patch_device(struct patch_ctx *ctx)413{414int ret;415416ret = pre_patch(ctx);417if (ret < 0) {418if (!ctx->patch_error) {419fprintf(stderr, "I/O error: pre_patch failed\n");420return ret;421}422423DBGPRINT("patch failed. proceed to post patch");424goto post_patch;425}426427ret = intel_download_patch(ctx);428if (ret < 0) {429if (!ctx->patch_error) {430fprintf(stderr, "I/O error: download_patch failed\n");431close(ctx->fd);432return ret;433}434} else {435DBGPRINT("patch done");436ctx->reset_enable_patch = 1;437}438439close(ctx->fd);440441post_patch:442ret = post_patch(ctx);443if (ret < 0) {444fprintf(stderr, "post_patch failed(%d)\n", ret);445return ret;446}447448return 0;449}450451static int set_rts(int dev, int rtsval)452{453int arg;454455if (ioctl(dev, TIOCMGET, &arg) < 0) {456perror("cannot get TIOCMGET");457return -errno;458}459if (rtsval)460arg |= TIOCM_RTS;461else462arg &= ~TIOCM_RTS;463464if (ioctl(dev, TIOCMSET, &arg) == -1) {465perror("cannot set TIOCMGET");466return -errno;467}468469return 0;470}471472static unsigned char get_intel_speed(int speed)473{474switch (speed) {475case 9600:476return 0x00;477case 19200:478return 0x01;479case 38400:480return 0x02;481case 57600:482return 0x03;483case 115200:484return 0x04;485case 230400:486return 0x05;487case 460800:488return 0x06;489case 921600:490return 0x07;491case 1843200:492return 0x08;493case 3250000:494return 0x09;495case 2000000:496return 0x0A;497case 3000000:498return 0x0B;499default:500return 0xFF;501}502}503504/**505* if it failed to change to new baudrate, it will rollback506* to initial baudrate507*/508static int change_baudrate(int dev, int init_speed, int *speed,509struct termios *ti)510{511int ret;512unsigned char br;513unsigned char cmd[5];514unsigned char evt[7];515516DBGPRINT("start baudrate change");517518ret = set_rts(dev, 0);519if (ret < 0) {520fprintf(stderr, "failed to clear RTS\n");521return ret;522}523524cmd[0] = HCI_COMMAND_PKT;525cmd[1] = 0x06;526cmd[2] = 0xFC;527cmd[3] = 0x01;528529br = get_intel_speed(*speed);530if (br == 0xFF) {531fprintf(stderr, "speed %d is not supported\n", *speed);532return -1;533}534cmd[4] = br;535536ret = intel_write_cmd(dev, cmd, sizeof(cmd));537if (ret < 0) {538fprintf(stderr, "failed to send cmd(%d)\n", ret);539return ret;540}541542/*543* wait for buffer to be consumed by the controller544*/545usleep(300000);546547if (set_speed(dev, ti, *speed) < 0) {548fprintf(stderr, "can't set to new baud rate\n");549return -1;550}551552ret = set_rts(dev, 1);553if (ret < 0) {554fprintf(stderr, "failed to set RTS\n");555return ret;556}557558ret = intel_read_evt(dev, evt, sizeof(evt));559if (ret < 0) {560fprintf(stderr, "failed to read evt(%d)\n", ret);561return ret;562}563564if (evt[4] != 0x00) {565fprintf(stderr,566"failed to change speed. use default speed %d\n",567init_speed);568*speed = init_speed;569}570571return 0;572}573574/**575* An entry point for Intel specific initialization576*/577int intel_init(int dev, int init_speed, int *speed, struct termios *ti)578{579int ret = 0;580struct patch_ctx ctx;581582if (change_baudrate(dev, init_speed, speed, ti) < 0)583return -1;584585ctx.dev = dev;586ctx.patch_error = 0;587ctx.reset_enable_patch = 0;588589ret = intel_patch_device(&ctx);590if (ret < 0)591fprintf(stderr, "failed to initialize the device");592593return ret;594}595596597