bt3cfw.c revision 285830
1249259Sdim/* 2249259Sdim * bt3cfw.c 3249259Sdim * 4249259Sdim * Copyright (c) 2001 Maksim Yevmenkin <m_evmenkin@yahoo.com> 5249259Sdim * All rights reserved. 6249259Sdim * 7249259Sdim * Redistribution and use in source and binary forms, with or without 8249259Sdim * modification, are permitted provided that the following conditions 9249259Sdim * are met: 10249259Sdim * 1. Redistributions of source code must retain the above copyright 11249259Sdim * notice, this list of conditions and the following disclaimer. 12249259Sdim * 2. Redistributions in binary form must reproduce the above copyright 13249259Sdim * notice, this list of conditions and the following disclaimer in the 14249259Sdim * documentation and/or other materials provided with the distribution. 15249259Sdim * 16249259Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17249259Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18249259Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19249259Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20249259Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21249259Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22249259Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23249259Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24249259Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25249259Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26249259Sdim * SUCH DAMAGE. 27249259Sdim * 28249259Sdim * $Id: bt3cfw.c,v 1.2 2003/05/21 22:40:29 max Exp $ 29249259Sdim * $FreeBSD: releng/10.2/usr.sbin/bluetooth/bt3cfw/bt3cfw.c 227876 2011-11-23 10:27:18Z kevlo $ 30249259Sdim */ 31249259Sdim 32249259Sdim#include <sys/types.h> 33249259Sdim#include <errno.h> 34249259Sdim#include <netgraph.h> 35249259Sdim#include <netgraph/bluetooth/include/ng_bt3c.h> 36249259Sdim#include <stdarg.h> 37249259Sdim#include <stdio.h> 38249259Sdim#include <stdlib.h> 39249259Sdim#include <string.h> 40249259Sdim#include <syslog.h> 41249259Sdim#include <unistd.h> 42249259Sdim 43249259Sdim#define BT3CFW_IDENT "bt3cfw" 44249259Sdim#define BT3CFW_MAX_FIRMWARE_SIZE 0xffff 45249259Sdim 46249259Sdim/* Convert hex ASCII to int4 */ 47249259Sdimstatic int 48249259Sdimhexa2int4(const char *a) 49249259Sdim{ 50249259Sdim if ('0' <= *a && *a <= '9') 51249259Sdim return (*a - '0'); 52249259Sdim 53249259Sdim if ('A' <= *a && *a <= 'F') 54249259Sdim return (*a - 'A' + 0xa); 55249259Sdim 56249259Sdim if ('a' <= *a && *a <= 'f') 57249259Sdim return (*a - 'a' + 0xa); 58249259Sdim 59249259Sdim syslog(LOG_ERR, "Invalid hex character: '%c' (%#x)", *a, *a); 60249259Sdim exit(255); 61249259Sdim} 62249259Sdim 63249259Sdim/* Convert hex ASCII to int8 */ 64249259Sdimstatic int 65249259Sdimhexa2int8(const char *a) 66249259Sdim{ 67249259Sdim return ((hexa2int4(a) << 4) | hexa2int4(a + 1)); 68249259Sdim} 69249259Sdim 70249259Sdim/* Convert hex ASCII to int16 */ 71249259Sdimstatic int 72249259Sdimhexa2int16(const char *a) 73249259Sdim{ 74249259Sdim return ((hexa2int8(a) << 8) | hexa2int8(a + 2)); 75249259Sdim} 76249259Sdim 77249259Sdim/* Convert hex ASCII to int32 */ 78249259Sdimstatic int 79249259Sdimhexa2int32(const char *a) 80249259Sdim{ 81249259Sdim return ((hexa2int16(a) << 16) | hexa2int16(a + 4)); 82249259Sdim} 83249259Sdim 84249259Sdim/* Display usage() and exit */ 85249259Sdimstatic void 86249259Sdimusage(void) 87249259Sdim{ 88249259Sdim syslog(LOG_ERR, "Usage: %s -f FirmwareFile -n NodeName", BT3CFW_IDENT); 89249259Sdim exit(255); 90249259Sdim} 91249259Sdim 92249259Sdim/* Main */ 93249259Sdimint 94249259Sdimmain(int argc, char *argv[]) 95249259Sdim{ 96249259Sdim FILE *firmware_file = NULL; 97249259Sdim char buffer[80], path[NG_PATHSIZ], 98249259Sdim *firmware_filename = NULL; 99249259Sdim uint8_t *firmware = NULL; 100249259Sdim int firmware_size, opt, cs, ds; 101249259Sdim 102249259Sdim memset(path, 0, sizeof(path)); 103249259Sdim openlog(BT3CFW_IDENT, LOG_NDELAY|LOG_PID|LOG_PERROR, LOG_USER); 104249259Sdim 105249259Sdim while ((opt = getopt(argc, argv, "f:hn:")) != -1) { 106249259Sdim switch (opt) { 107249259Sdim case 'f': 108249259Sdim firmware_filename = optarg; 109249259Sdim break; 110249259Sdim 111249259Sdim case 'n': 112249259Sdim snprintf(path, sizeof(path), "%s:", optarg); 113249259Sdim break; 114249259Sdim 115249259Sdim case 'h': 116249259Sdim default: 117249259Sdim usage(); 118249259Sdim /* NOT REACHED */ 119249259Sdim } 120249259Sdim } 121249259Sdim 122249259Sdim if (firmware_filename == NULL || path[0] == 0) 123249259Sdim usage(); 124249259Sdim /* NOT REACHED */ 125249259Sdim 126249259Sdim firmware = (uint8_t *) calloc(BT3CFW_MAX_FIRMWARE_SIZE, 127249259Sdim sizeof(uint8_t)); 128249259Sdim if (firmware == NULL) { 129249259Sdim syslog(LOG_ERR, "Could not allocate firmware buffer"); 130249259Sdim exit(255); 131249259Sdim } 132249259Sdim 133249259Sdim if ((firmware_file = fopen(firmware_filename, "r")) == NULL) { 134249259Sdim syslog(LOG_ERR, "Could not open BT3C firmware file %s. %s (%d)", 135249259Sdim firmware_filename, strerror(errno), errno); 136249259Sdim exit(255); 137249259Sdim } 138249259Sdim 139249259Sdim firmware_size = 0; 140249259Sdim 141249259Sdim while (fgets(buffer, sizeof(buffer), firmware_file)) { 142249259Sdim int i, size, address, cs, fcs; 143249259Sdim 144249259Sdim size = hexa2int8(buffer + 2); 145249259Sdim address = hexa2int32(buffer + 4); 146249259Sdim fcs = hexa2int8(buffer + 2 + size * 2); 147249259Sdim 148249259Sdim if (buffer[1] == '3') { 149249259Sdim ng_bt3c_firmware_block_ep *block = NULL; 150249259Sdim uint16_t *data = NULL; 151249259Sdim 152249259Sdim block = (ng_bt3c_firmware_block_ep *) 153249259Sdim (firmware + firmware_size); 154249259Sdim 155249259Sdim firmware_size += sizeof(*block); 156249259Sdim if (firmware_size >= BT3CFW_MAX_FIRMWARE_SIZE) { 157249259Sdim syslog(LOG_ERR, "Could not add new firmware " \ 158249259Sdim "block. Firmware file %s is " \ 159249259Sdim "too big, firmware_size=%d", 160249259Sdim firmware_filename, 161249259Sdim firmware_size); 162249259Sdim exit(255); 163249259Sdim } 164249259Sdim 165249259Sdim block->block_address = address; 166249259Sdim block->block_size = (size - 4) / 2; 167249259Sdim block->block_alignment = (block->block_size * 2) % 3; 168249259Sdim if (block->block_alignment != 0) 169249259Sdim block->block_alignment = 3 - block->block_alignment; 170249259Sdim 171249259Sdim firmware_size += (block->block_size * 2); 172249259Sdim firmware_size += block->block_alignment; 173249259Sdim if (firmware_size >= BT3CFW_MAX_FIRMWARE_SIZE) { 174249259Sdim syslog(LOG_ERR, "Could not add new firmware " \ 175249259Sdim "data. Firmware file %s is " \ 176249259Sdim "too big, firmware_size=%d", 177249259Sdim firmware_filename, 178249259Sdim firmware_size); 179249259Sdim exit(255); 180249259Sdim } 181249259Sdim 182249259Sdim /* First part of the cheksum: size and address */ 183249259Sdim cs = 0; 184249259Sdim for (i = 0; i < 5; i++) 185249259Sdim cs += hexa2int8(buffer + 2 + i * 2); 186249259Sdim 187249259Sdim /* Data + second part of the cheksum: data */ 188249259Sdim data = (uint16_t *)(block + 1); 189249259Sdim for (i = 0; i < block->block_size; i++) { 190249259Sdim data[i] = hexa2int16(buffer + (i * 4) + 12); 191249259Sdim cs += (((data[i] & 0xff00) >> 8) & 0xff); 192249259Sdim cs += (data[i] & 0x00ff); 193249259Sdim } 194249259Sdim } else 195249259Sdim for (cs = 0, i = 0; i < size; i++) 196249259Sdim cs += hexa2int8(buffer + 2 + i * 2); 197249259Sdim 198249259Sdim if (((cs + fcs) & 0xff) != 0xff) { 199249259Sdim syslog(LOG_ERR, "Invalid firmware file %s. Checksum " \ 200249259Sdim "error, cs=%#x, fcs=%#x, checksum=%#x", 201249259Sdim firmware_filename, (cs & 0xff), fcs, 202249259Sdim ((cs + fcs) & 0xff)); 203249259Sdim exit(255); 204249259Sdim } 205249259Sdim } 206249259Sdim 207249259Sdim /* Send firmware to the card */ 208249259Sdim if (NgMkSockNode(NULL, &cs, &ds) < 0) { 209249259Sdim syslog(LOG_ERR, "Could not create Netgraph socket. %s (%d)", 210249259Sdim strerror(errno), errno); 211249259Sdim exit(255); 212249259Sdim } 213249259Sdim 214249259Sdim if (NgSendMsg(cs, path, NGM_BT3C_COOKIE, 215249259Sdim NGM_BT3C_NODE_DOWNLOAD_FIRMWARE, 216249259Sdim (void const *) firmware, firmware_size) < 0) { 217249259Sdim syslog(LOG_ERR, "Could not send Netgraph message. %s (%d)", 218249259Sdim strerror(errno), errno); 219249259Sdim exit(255); 220249259Sdim } 221249259Sdim 222249259Sdim free(firmware); 223249259Sdim firmware = NULL; 224249259Sdim fclose(firmware_file); 225249259Sdim 226249259Sdim return (0); 227249259Sdim} 228249259Sdim 229249259Sdim