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_ti.c
Views: 3959
/*1*2* BlueZ - Bluetooth protocol stack for Linux3*4* Copyright (C) 2007-2008 Texas Instruments, Inc.5* Copyright (C) 2005-2010 Marcel Holtmann <[email protected]>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 <unistd.h>31#include <stdlib.h>32#include <termios.h>33#include <time.h>34#include <sys/time.h>35#include <sys/types.h>36#include <sys/param.h>37#include <sys/ioctl.h>3839#include <bluetooth/bluetooth.h>40#include <bluetooth/hci.h>41#include <bluetooth/hci_lib.h>4243#include "hciattach.h"4445#ifdef HCIATTACH_DEBUG46#define DPRINTF(x...) printf(x)47#else48#define DPRINTF(x...)49#endif5051#define HCIUARTGETDEVICE _IOR('U', 202, int)5253#define MAKEWORD(a, b) ((uint16_t)(((uint8_t)(a)) | ((uint16_t)((uint8_t)(b))) << 8))5455#define TI_MANUFACTURER_ID 135657#define FIRMWARE_DIRECTORY "/lib/firmware/ti-connectivity/"5859#define ACTION_SEND_COMMAND 160#define ACTION_WAIT_EVENT 261#define ACTION_SERIAL 362#define ACTION_DELAY 463#define ACTION_RUN_SCRIPT 564#define ACTION_REMARKS 66566#define BRF_DEEP_SLEEP_OPCODE_BYTE_1 0x0c67#define BRF_DEEP_SLEEP_OPCODE_BYTE_2 0xfd68#define BRF_DEEP_SLEEP_OPCODE \69(BRF_DEEP_SLEEP_OPCODE_BYTE_1 | (BRF_DEEP_SLEEP_OPCODE_BYTE_2 << 8))7071#define FILE_HEADER_MAGIC 0x425354427273/*74* BRF Firmware header75*/76struct bts_header {77uint32_t magic;78uint32_t version;79uint8_t future[24];80uint8_t actions[0];81}__attribute__ ((packed));8283/*84* BRF Actions structure85*/86struct bts_action {87uint16_t type;88uint16_t size;89uint8_t data[0];90} __attribute__ ((packed));9192struct bts_action_send {93uint8_t data[0];94} __attribute__ ((packed));9596struct bts_action_wait {97uint32_t msec;98uint32_t size;99uint8_t data[0];100}__attribute__ ((packed));101102struct bts_action_delay {103uint32_t msec;104}__attribute__ ((packed));105106struct bts_action_serial {107uint32_t baud;108uint32_t flow_control;109}__attribute__ ((packed));110111static FILE *bts_load_script(const char *file_name, uint32_t *version)112{113struct bts_header header;114FILE *fp;115116fp = fopen(file_name, "rb");117if (!fp) {118perror("can't open firmware file");119return NULL;120}121122if (1 != fread(&header, sizeof(struct bts_header), 1, fp)) {123perror("can't read firmware file");124goto errclose;125}126127if (header.magic != FILE_HEADER_MAGIC) {128fprintf(stderr, "%s not a legal TI firmware file\n", file_name);129goto errclose;130}131132if (NULL != version)133*version = header.version;134135return fp;136137errclose:138fclose(fp);139140return NULL;141}142143static unsigned long bts_fetch_action(FILE *fp, unsigned char *action_buf,144unsigned long buf_size, uint16_t *action_type)145{146struct bts_action action_hdr;147unsigned long nread;148149if (!fp)150return 0;151152if (1 != fread(&action_hdr, sizeof(struct bts_action), 1, fp))153return 0;154155if (action_hdr.size > buf_size) {156fprintf(stderr, "bts_next_action: not enough space to read next action\n");157return 0;158}159160nread = fread(action_buf, sizeof(uint8_t), action_hdr.size, fp);161if (nread != (action_hdr.size)) {162fprintf(stderr, "bts_next_action: fread failed to read next action\n");163return 0;164}165166*action_type = action_hdr.type;167168return nread * sizeof(uint8_t);169}170171static void bts_unload_script(FILE *fp)172{173if (fp)174fclose(fp);175}176177static int is_it_texas(const uint8_t *respond)178{179uint16_t manufacturer_id;180181manufacturer_id = MAKEWORD(respond[11], respond[12]);182183return TI_MANUFACTURER_ID == manufacturer_id ? 1 : 0;184}185186static const char *get_firmware_name(const uint8_t *respond)187{188static char firmware_file_name[PATH_MAX] = {0};189uint16_t version = 0, chip = 0, min_ver = 0, maj_ver = 0;190191version = MAKEWORD(respond[13], respond[14]);192chip = (version & 0x7C00) >> 10;193min_ver = (version & 0x007F);194maj_ver = (version & 0x0380) >> 7;195196if (version & 0x8000)197maj_ver |= 0x0008;198199sprintf(firmware_file_name, FIRMWARE_DIRECTORY "TIInit_%d.%d.%d.bts", chip, maj_ver, min_ver);200201return firmware_file_name;202}203204static void brf_delay(struct bts_action_delay *delay)205{206usleep(1000 * delay->msec);207}208209static int brf_set_serial_params(struct bts_action_serial *serial_action,210int fd, int *speed, struct termios *ti)211{212fprintf(stderr, "texas: changing baud rate to %u, flow control to %u\n",213serial_action->baud, serial_action->flow_control );214tcflush(fd, TCIOFLUSH);215216if (serial_action->flow_control)217ti->c_cflag |= CRTSCTS;218else219ti->c_cflag &= ~CRTSCTS;220221if (tcsetattr(fd, TCSANOW, ti) < 0) {222perror("Can't set port settings");223return -1;224}225226tcflush(fd, TCIOFLUSH);227228if (set_speed(fd, ti, serial_action->baud) < 0) {229perror("Can't set baud rate");230return -1;231}232233if (speed)234*speed = serial_action->baud;235236return 0;237}238239static int brf_send_command_socket(int fd, struct bts_action_send *send_action)240{241char response[1024] = {0};242hci_command_hdr *cmd = (hci_command_hdr *) send_action->data;243uint16_t opcode = cmd->opcode;244245struct hci_request rq;246memset(&rq, 0, sizeof(rq));247rq.ogf = cmd_opcode_ogf(opcode);248rq.ocf = cmd_opcode_ocf(opcode);249rq.event = EVT_CMD_COMPLETE;250rq.cparam = &send_action->data[3];251rq.clen = send_action->data[2];252rq.rparam = response;253rq.rlen = sizeof(response);254255if (hci_send_req(fd, &rq, 15) < 0) {256perror("Cannot send hci command to socket");257return -1;258}259260/* verify success */261if (response[0]) {262errno = EIO;263return -1;264}265266return 0;267}268269static int brf_send_command_file(int fd, struct bts_action_send *send_action,270long size)271{272unsigned char response[1024] = {0};273long ret = 0;274275/* send command */276if (size != write(fd, send_action, size)) {277perror("Texas: Failed to write action command");278return -1;279}280281/* read response */282ret = read_hci_event(fd, response, sizeof(response));283if (ret < 0) {284perror("texas: failed to read command response");285return -1;286}287288/* verify success */289if (ret < 7 || 0 != response[6]) {290fprintf( stderr, "TI init command failed.\n" );291errno = EIO;292return -1;293}294295return 0;296}297298299static int brf_send_command(int fd, struct bts_action_send *send_action,300long size, int hcill_installed)301{302int ret = 0;303char *fixed_action;304305/* remove packet type when giving to socket API */306if (hcill_installed) {307fixed_action = ((char *) send_action) + 1;308ret = brf_send_command_socket(fd, (struct bts_action_send *) fixed_action);309} else {310ret = brf_send_command_file(fd, send_action, size);311}312313return ret;314}315316static int brf_do_action(uint16_t brf_type, uint8_t *brf_action, long brf_size,317int fd, int *speed, struct termios *ti, int hcill_installed)318{319int ret = 0;320321switch (brf_type) {322case ACTION_SEND_COMMAND:323DPRINTF("W");324ret = brf_send_command(fd,325(struct bts_action_send *) brf_action,326brf_size, hcill_installed);327break;328case ACTION_WAIT_EVENT:329DPRINTF("R");330break;331case ACTION_SERIAL:332DPRINTF("S");333ret = brf_set_serial_params((struct bts_action_serial *) brf_action, fd, speed, ti);334break;335case ACTION_DELAY:336DPRINTF("D");337brf_delay((struct bts_action_delay *) brf_action);338break;339case ACTION_REMARKS:340DPRINTF("C");341break;342default:343fprintf(stderr, "brf_init: unknown firmware action type (%d)\n", brf_type);344break;345}346347return ret;348}349350/*351* tests whether a given brf action is a HCI_VS_Sleep_Mode_Configurations cmd352*/353static int brf_action_is_deep_sleep(uint8_t *brf_action, long brf_size,354uint16_t brf_type)355{356uint16_t opcode;357358if (brf_type != ACTION_SEND_COMMAND)359return 0;360361if (brf_size < 3)362return 0;363364if (brf_action[0] != HCI_COMMAND_PKT)365return 0;366367/* HCI data is little endian */368opcode = brf_action[1] | (brf_action[2] << 8);369370if (opcode != BRF_DEEP_SLEEP_OPCODE)371return 0;372373/* action is deep sleep configuration command ! */374return 1;375}376377/*378* This function is called twice.379* The first time it is called, it loads the brf script, and executes its380* commands until it reaches a deep sleep command (or its end).381* The second time it is called, it assumes HCILL protocol is set up,382* and sends rest of brf script via the supplied socket.383*/384static int brf_do_script(int fd, int *speed, struct termios *ti, const char *bts_file)385{386int ret = 0, hcill_installed = bts_file ? 0 : 1;387uint32_t vers;388static FILE *brf_script_file = NULL;389static uint8_t brf_action[512];390static long brf_size;391static uint16_t brf_type;392393/* is it the first time we are called ? */394if (0 == hcill_installed) {395DPRINTF("Sending script to serial device\n");396brf_script_file = bts_load_script(bts_file, &vers );397if (!brf_script_file) {398fprintf(stderr, "Warning: cannot find BTS file: %s\n",399bts_file);400return 0;401}402403fprintf( stderr, "Loaded BTS script version %u\n", vers );404405brf_size = bts_fetch_action(brf_script_file, brf_action,406sizeof(brf_action), &brf_type);407if (brf_size == 0) {408fprintf(stderr, "Warning: BTS file is empty !");409return 0;410}411}412else {413DPRINTF("Sending script to bluetooth socket\n");414}415416/* execute current action and continue to parse brf script file */417while (brf_size != 0) {418ret = brf_do_action(brf_type, brf_action, brf_size,419fd, speed, ti, hcill_installed);420if (ret == -1)421break;422423brf_size = bts_fetch_action(brf_script_file, brf_action,424sizeof(brf_action), &brf_type);425426/* if this is the first time we run (no HCILL yet) */427/* and a deep sleep command is encountered */428/* we exit */429if (!hcill_installed &&430brf_action_is_deep_sleep(brf_action,431brf_size, brf_type))432return 0;433}434435bts_unload_script(brf_script_file);436brf_script_file = NULL;437DPRINTF("\n");438439return ret;440}441442int texas_init(int fd, int *speed, struct termios *ti)443{444struct timespec tm = {0, 50000};445char cmd[4];446unsigned char resp[100]; /* Response */447const char *bts_file;448int n;449450memset(resp,'\0', 100);451452/* It is possible to get software version with manufacturer specific453HCI command HCI_VS_TI_Version_Number. But the only thing you get more454is if this is point-to-point or point-to-multipoint module */455456/* Get Manufacturer and LMP version */457cmd[0] = HCI_COMMAND_PKT;458cmd[1] = 0x01;459cmd[2] = 0x10;460cmd[3] = 0x00;461462do {463n = write(fd, cmd, 4);464if (n < 0) {465perror("Failed to write init command (READ_LOCAL_VERSION_INFORMATION)");466return -1;467}468if (n < 4) {469fprintf(stderr, "Wanted to write 4 bytes, could only write %d. Stop\n", n);470return -1;471}472473/* Read reply. */474if (read_hci_event(fd, resp, 100) < 0) {475perror("Failed to read init response (READ_LOCAL_VERSION_INFORMATION)");476return -1;477}478479/* Wait for command complete event for our Opcode */480} while (resp[4] != cmd[1] && resp[5] != cmd[2]);481482/* Verify manufacturer */483if (! is_it_texas(resp)) {484fprintf(stderr,"ERROR: module's manufacturer is not Texas Instruments\n");485return -1;486}487488fprintf(stderr, "Found a Texas Instruments' chip!\n");489490bts_file = get_firmware_name(resp);491fprintf(stderr, "Firmware file : %s\n", bts_file);492493n = brf_do_script(fd, speed, ti, bts_file);494495nanosleep(&tm, NULL);496497return n;498}499500int texas_post(int fd, struct termios *ti)501{502int dev_id, dd, ret = 0;503504sleep(1);505506dev_id = ioctl(fd, HCIUARTGETDEVICE, 0);507if (dev_id < 0) {508perror("cannot get device id");509return -1;510}511512DPRINTF("\nAdded device hci%d\n", dev_id);513514dd = hci_open_dev(dev_id);515if (dd < 0) {516perror("HCI device open failed");517return -1;518}519520if (ioctl(dd, HCIDEVUP, dev_id) < 0 && errno != EALREADY) {521fprintf(stderr, "Can't init device hci%d: %s (%d)", dev_id,522strerror(errno), errno);523hci_close_dev(dd);524return -1;525}526527ret = brf_do_script(dd, NULL, ti, NULL);528529hci_close_dev(dd);530531return ret;532}533534535