| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037 |
- // SPDX-License-Identifier: GPL-2.0-or-later
- /*
- * Copyright (c) 2009-2010 Atheros Communications Inc.
- *
- */
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
- #define _GNU_SOURCE
- #include <stdio.h>
- #include <errno.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <time.h>
- #include <sys/stat.h>
- #include <sys/time.h>
- #include <sys/types.h>
- #include <sys/param.h>
- #include <sys/ioctl.h>
- #include "lib/bluetooth.h"
- #include "lib/hci.h"
- #include "lib/hci_lib.h"
- #include "hciattach.h"
- #define TRUE 1
- #define FALSE 0
- #define FW_PATH "/lib/firmware/ar3k/"
- struct ps_cfg_entry {
- uint32_t id;
- uint32_t len;
- uint8_t *data;
- };
- struct ps_entry_type {
- unsigned char type;
- unsigned char array;
- };
- #define MAX_TAGS 50
- #define PS_HDR_LEN 4
- #define HCI_VENDOR_CMD_OGF 0x3F
- #define HCI_PS_CMD_OCF 0x0B
- struct ps_cfg_entry ps_list[MAX_TAGS];
- static void load_hci_ps_hdr(uint8_t *cmd, uint8_t ps_op, int len, int index)
- {
- hci_command_hdr *ch = (void *)cmd;
- ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
- HCI_PS_CMD_OCF));
- ch->plen = len + PS_HDR_LEN;
- cmd += HCI_COMMAND_HDR_SIZE;
- cmd[0] = ps_op;
- cmd[1] = index;
- cmd[2] = index >> 8;
- cmd[3] = len;
- }
- #define PS_EVENT_LEN 100
- /*
- * Send HCI command and wait for command complete event.
- * The event buffer has to be freed by the caller.
- */
- static int send_hci_cmd_sync(int dev, uint8_t *cmd, int len, uint8_t **event)
- {
- int err;
- uint8_t *hci_event;
- uint8_t pkt_type = HCI_COMMAND_PKT;
- if (len == 0)
- return len;
- if (write(dev, &pkt_type, 1) != 1)
- return -EILSEQ;
- if (write(dev, (unsigned char *)cmd, len) != len)
- return -EILSEQ;
- hci_event = (uint8_t *)malloc(PS_EVENT_LEN);
- if (!hci_event)
- return -ENOMEM;
- err = read_hci_event(dev, (unsigned char *)hci_event, PS_EVENT_LEN);
- if (err > 0) {
- *event = hci_event;
- } else {
- free(hci_event);
- return -EILSEQ;
- }
- return len;
- }
- #define HCI_EV_SUCCESS 0x00
- static int read_ps_event(uint8_t *event, uint16_t ocf)
- {
- hci_event_hdr *eh;
- uint16_t opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF, ocf));
- event++;
- eh = (void *)event;
- event += HCI_EVENT_HDR_SIZE;
- if (eh->evt == EVT_CMD_COMPLETE) {
- evt_cmd_complete *cc = (void *)event;
- event += EVT_CMD_COMPLETE_SIZE;
- if (cc->opcode == opcode && event[0] == HCI_EV_SUCCESS)
- return 0;
- else
- return -EILSEQ;
- }
- return -EILSEQ;
- }
- static int write_cmd(int fd, uint8_t *buffer, int len)
- {
- uint8_t *event;
- int err;
- err = send_hci_cmd_sync(fd, buffer, len, &event);
- if (err < 0)
- return err;
- err = read_ps_event(event, HCI_PS_CMD_OCF);
- free(event);
- return err;
- }
- #define PS_WRITE 1
- #define PS_RESET 2
- #define WRITE_PATCH 8
- #define ENABLE_PATCH 11
- #define HCI_PS_CMD_HDR_LEN 7
- #define PS_RESET_PARAM_LEN 6
- #define HCI_MAX_CMD_SIZE 260
- #define PS_RESET_CMD_LEN (HCI_PS_CMD_HDR_LEN + PS_RESET_PARAM_LEN)
- #define PS_ID_MASK 0xFF
- /* Sends PS commands using vendor specficic HCI commands */
- static int write_ps_cmd(int fd, uint8_t opcode, uint32_t ps_param)
- {
- uint8_t cmd[HCI_MAX_CMD_SIZE];
- uint32_t i;
- switch (opcode) {
- case ENABLE_PATCH:
- load_hci_ps_hdr(cmd, opcode, 0, 0x00);
- if (write_cmd(fd, cmd, HCI_PS_CMD_HDR_LEN) < 0)
- return -EILSEQ;
- break;
- case PS_RESET:
- load_hci_ps_hdr(cmd, opcode, PS_RESET_PARAM_LEN, 0x00);
- cmd[7] = 0x00;
- cmd[PS_RESET_CMD_LEN - 2] = ps_param & PS_ID_MASK;
- cmd[PS_RESET_CMD_LEN - 1] = (ps_param >> 8) & PS_ID_MASK;
- if (write_cmd(fd, cmd, PS_RESET_CMD_LEN) < 0)
- return -EILSEQ;
- break;
- case PS_WRITE:
- for (i = 0; i < ps_param; i++) {
- load_hci_ps_hdr(cmd, opcode, ps_list[i].len,
- ps_list[i].id);
- memcpy(&cmd[HCI_PS_CMD_HDR_LEN], ps_list[i].data,
- ps_list[i].len);
- if (write_cmd(fd, cmd, ps_list[i].len +
- HCI_PS_CMD_HDR_LEN) < 0)
- return -EILSEQ;
- }
- break;
- }
- return 0;
- }
- #define __is_delim(ch) ((ch) == ':')
- #define MAX_PREAMBLE_LEN 4
- /* Parse PS entry preamble of format [X:X] for main type and subtype */
- static int get_ps_type(char *ptr, int index, char *type, char *sub_type)
- {
- int i;
- int delim = FALSE;
- if (index > MAX_PREAMBLE_LEN)
- return -EILSEQ;
- for (i = 1; i < index; i++) {
- if (__is_delim(ptr[i])) {
- delim = TRUE;
- continue;
- }
- if (isalpha(ptr[i])) {
- if (delim == FALSE)
- (*type) = toupper(ptr[i]);
- else
- (*sub_type) = toupper(ptr[i]);
- }
- }
- return 0;
- }
- #define ARRAY 'A'
- #define STRING 'S'
- #define DECIMAL 'D'
- #define BINARY 'B'
- #define PS_HEX 0
- #define PS_DEC 1
- static int get_input_format(char *buf, struct ps_entry_type *format)
- {
- char *ptr = NULL;
- char type = '\0';
- char sub_type = '\0';
- format->type = PS_HEX;
- format->array = TRUE;
- if (strstr(buf, "[") != buf)
- return 0;
- ptr = strstr(buf, "]");
- if (!ptr)
- return -EILSEQ;
- if (get_ps_type(buf, ptr - buf, &type, &sub_type) < 0)
- return -EILSEQ;
- /* Check is data type is of array */
- if (type == ARRAY || sub_type == ARRAY)
- format->array = TRUE;
- if (type == STRING || sub_type == STRING)
- format->array = FALSE;
- if (type == DECIMAL || type == BINARY)
- format->type = PS_DEC;
- else
- format->type = PS_HEX;
- return 0;
- }
- #define UNDEFINED 0xFFFF
- static unsigned int read_data_in_section(char *buf, struct ps_entry_type type)
- {
- char *ptr = buf;
- if (!buf)
- return UNDEFINED;
- if (buf == strstr(buf, "[")) {
- ptr = strstr(buf, "]");
- if (!ptr)
- return UNDEFINED;
- ptr++;
- }
- if (type.type == PS_HEX && type.array != TRUE)
- return strtol(ptr, NULL, 16);
- return UNDEFINED;
- }
- struct tag_info {
- unsigned section;
- unsigned line_count;
- unsigned char_cnt;
- unsigned byte_count;
- };
- static inline int update_char_count(const char *buf)
- {
- char *end_ptr;
- if (strstr(buf, "[") == buf) {
- end_ptr = strstr(buf, "]");
- if (!end_ptr)
- return 0;
- else
- return (end_ptr - buf) + 1;
- }
- return 0;
- }
- /* Read PS entries as string, convert and add to Hex array */
- static void update_tag_data(struct ps_cfg_entry *tag,
- struct tag_info *info, const char *ptr)
- {
- char buf[3];
- buf[2] = '\0';
- strncpy(buf, &ptr[info->char_cnt], 2);
- tag->data[info->byte_count] = strtol(buf, NULL, 16);
- info->char_cnt += 3;
- info->byte_count++;
- strncpy(buf, &ptr[info->char_cnt], 2);
- tag->data[info->byte_count] = strtol(buf, NULL, 16);
- info->char_cnt += 3;
- info->byte_count++;
- }
- #define PS_UNDEF 0
- #define PS_ID 1
- #define PS_LEN 2
- #define PS_DATA 3
- #define PS_MAX_LEN 500
- #define LINE_SIZE_MAX (PS_MAX_LEN * 2)
- #define ENTRY_PER_LINE 16
- #define __check_comment(buf) (((buf)[0] == '/') && ((buf)[1] == '/'))
- #define __skip_space(str) while (*(str) == ' ') ((str)++)
- static int ath_parse_ps(FILE *stream)
- {
- char buf[LINE_SIZE_MAX + 1];
- char *ptr;
- uint8_t tag_cnt = 0;
- int16_t byte_count = 0;
- struct ps_entry_type format;
- struct tag_info status = { 0, 0, 0, 0 };
- do {
- int read_count;
- struct ps_cfg_entry *tag;
- ptr = fgets(buf, LINE_SIZE_MAX, stream);
- if (!ptr)
- break;
- __skip_space(ptr);
- if (__check_comment(ptr))
- continue;
- /* Lines with a '#' will be followed by new PS entry */
- if (ptr == strstr(ptr, "#")) {
- if (status.section != PS_UNDEF) {
- return -EILSEQ;
- } else {
- status.section = PS_ID;
- continue;
- }
- }
- tag = &ps_list[tag_cnt];
- switch (status.section) {
- case PS_ID:
- if (get_input_format(ptr, &format) < 0)
- return -EILSEQ;
- tag->id = read_data_in_section(ptr, format);
- status.section = PS_LEN;
- break;
- case PS_LEN:
- if (get_input_format(ptr, &format) < 0)
- return -EILSEQ;
- byte_count = read_data_in_section(ptr, format);
- if (byte_count > PS_MAX_LEN)
- return -EILSEQ;
- tag->len = byte_count;
- tag->data = (uint8_t *)malloc(byte_count);
- status.section = PS_DATA;
- status.line_count = 0;
- break;
- case PS_DATA:
- if (status.line_count == 0)
- if (get_input_format(ptr, &format) < 0)
- return -EILSEQ;
- __skip_space(ptr);
- status.char_cnt = update_char_count(ptr);
- read_count = (byte_count > ENTRY_PER_LINE) ?
- ENTRY_PER_LINE : byte_count;
- if (format.type == PS_HEX && format.array == TRUE) {
- while (read_count > 0) {
- update_tag_data(tag, &status, ptr);
- read_count -= 2;
- }
- if (byte_count > ENTRY_PER_LINE)
- byte_count -= ENTRY_PER_LINE;
- else
- byte_count = 0;
- }
- status.line_count++;
- if (byte_count == 0)
- memset(&status, 0x00, sizeof(struct tag_info));
- if (status.section == PS_UNDEF)
- tag_cnt++;
- if (tag_cnt == MAX_TAGS)
- return -EILSEQ;
- break;
- }
- } while (ptr);
- return tag_cnt;
- }
- #define MAX_PATCH_CMD 244
- struct patch_entry {
- int16_t len;
- uint8_t data[MAX_PATCH_CMD];
- };
- #define SET_PATCH_RAM_ID 0x0D
- #define SET_PATCH_RAM_CMD_SIZE 11
- #define ADDRESS_LEN 4
- static int set_patch_ram(int dev, char *patch_loc, int len)
- {
- int err;
- uint8_t cmd[20];
- int i, j;
- char loc_byte[3];
- uint8_t *event;
- uint8_t *loc_ptr = &cmd[7];
- if (!patch_loc)
- return -1;
- loc_byte[2] = '\0';
- load_hci_ps_hdr(cmd, SET_PATCH_RAM_ID, ADDRESS_LEN, 0);
- for (i = 0, j = 3; i < 4; i++, j--) {
- loc_byte[0] = patch_loc[0];
- loc_byte[1] = patch_loc[1];
- loc_ptr[j] = strtol(loc_byte, NULL, 16);
- patch_loc += 2;
- }
- err = send_hci_cmd_sync(dev, cmd, SET_PATCH_RAM_CMD_SIZE, &event);
- if (err < 0)
- return err;
- err = read_ps_event(event, HCI_PS_CMD_OCF);
- free(event);
- return err;
- }
- #define PATCH_LOC_KEY "DA:"
- #define PATCH_LOC_STRING_LEN (8 + 237)
- static int ps_patch_download(int fd, FILE *stream)
- {
- char byte[3];
- char ptr[MAX_PATCH_CMD + 1];
- int byte_cnt;
- int patch_count = 0;
- char patch_loc[PATCH_LOC_STRING_LEN + 1];
- byte[2] = '\0';
- while (fgets(ptr, MAX_PATCH_CMD, stream)) {
- if (strlen(ptr) <= 1)
- continue;
- else if (strstr(ptr, PATCH_LOC_KEY) == ptr) {
- strncpy(patch_loc, &ptr[sizeof(PATCH_LOC_KEY) - 1],
- PATCH_LOC_STRING_LEN);
- if (set_patch_ram(fd, patch_loc, sizeof(patch_loc)) < 0)
- return -1;
- } else if (isxdigit(ptr[0]))
- break;
- else
- return -1;
- }
- byte_cnt = strtol(ptr, NULL, 16);
- while (byte_cnt > 0) {
- int i;
- uint8_t cmd[HCI_MAX_CMD_SIZE];
- struct patch_entry patch;
- if (byte_cnt > MAX_PATCH_CMD)
- patch.len = MAX_PATCH_CMD;
- else
- patch.len = byte_cnt;
- for (i = 0; i < patch.len; i++) {
- if (!fgets(byte, 3, stream))
- return -1;
- patch.data[i] = strtoul(byte, NULL, 16);
- }
- load_hci_ps_hdr(cmd, WRITE_PATCH, patch.len, patch_count);
- memcpy(&cmd[HCI_PS_CMD_HDR_LEN], patch.data, patch.len);
- if (write_cmd(fd, cmd, patch.len + HCI_PS_CMD_HDR_LEN) < 0)
- return -1;
- patch_count++;
- byte_cnt = byte_cnt - MAX_PATCH_CMD;
- }
- if (write_ps_cmd(fd, ENABLE_PATCH, 0) < 0)
- return -1;
- return patch_count;
- }
- #define PS_RAM_SIZE 2048
- static int ps_config_download(int fd, int tag_count)
- {
- if (write_ps_cmd(fd, PS_RESET, PS_RAM_SIZE) < 0)
- return -1;
- if (tag_count > 0)
- if (write_ps_cmd(fd, PS_WRITE, tag_count) < 0)
- return -1;
- return 0;
- }
- #define PS_ASIC_FILE_PREFIX "PS_ASIC"
- #define PS_FPGA_FILE_PREFIX "PS_FPGA"
- static void get_ps_file_name(uint32_t devtype, uint32_t rom_version, char *path,
- char *region)
- {
- char *file_prefix;
- struct stat st;
- if (devtype == 0xdeadc0de)
- file_prefix = PS_ASIC_FILE_PREFIX;
- else
- file_prefix = PS_FPGA_FILE_PREFIX;
- if (!region)
- goto default_ps_file;
- snprintf(path, MAXPATHLEN, "%s%x/%s-%s.pst", FW_PATH, rom_version,
- file_prefix, region);
- if (stat(path, &st) == 0)
- return;
- perror("PS file with region code not exist, use default PS file\n");
- default_ps_file:
- snprintf(path, MAXPATHLEN, "%s%x/%s.pst", FW_PATH, rom_version,
- file_prefix);
- }
- #define PATCH_FILE "RamPatch.txt"
- #define FPGA_ROM_VERSION 0x99999999
- #define ROM_DEV_TYPE 0xdeadc0de
- static void get_patch_file_name(uint32_t dev_type, uint32_t rom_version,
- uint32_t build_version, char *path)
- {
- if (rom_version == FPGA_ROM_VERSION && dev_type != ROM_DEV_TYPE &&
- dev_type != 0 && build_version == 1)
- path[0] = '\0';
- else
- snprintf(path, MAXPATHLEN, "%s%x/%s",
- FW_PATH, rom_version, PATCH_FILE);
- }
- #define VERIFY_CRC 9
- #define PS_REGION 1
- #define PATCH_REGION 2
- static int get_ath3k_crc(int dev)
- {
- uint8_t cmd[7];
- uint8_t *event;
- int err;
- load_hci_ps_hdr(cmd, VERIFY_CRC, 0, PS_REGION | PATCH_REGION);
- err = send_hci_cmd_sync(dev, cmd, sizeof(cmd), &event);
- if (err < 0)
- return err;
- /* Send error code if CRC check patched */
- if (read_ps_event(event, HCI_PS_CMD_OCF) >= 0)
- err = -EILSEQ;
- free(event);
- return err;
- }
- #define DEV_REGISTER 0x4FFC
- #define GET_DEV_TYPE_OCF 0x05
- static int get_device_type(int dev, uint32_t *code)
- {
- uint8_t cmd[8];
- uint8_t *event;
- uint32_t reg;
- int err;
- uint8_t *ptr = cmd;
- hci_command_hdr *ch = (void *)cmd;
- ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
- GET_DEV_TYPE_OCF));
- ch->plen = 5;
- ptr += HCI_COMMAND_HDR_SIZE;
- ptr[0] = (uint8_t)DEV_REGISTER;
- ptr[1] = (uint8_t)DEV_REGISTER >> 8;
- ptr[2] = (uint8_t)DEV_REGISTER >> 16;
- ptr[3] = (uint8_t)DEV_REGISTER >> 24;
- ptr[4] = 0x04;
- err = send_hci_cmd_sync(dev, cmd, sizeof(cmd), &event);
- if (err < 0)
- return err;
- err = read_ps_event(event, GET_DEV_TYPE_OCF);
- if (err < 0)
- goto cleanup;
- reg = event[10];
- reg = (reg << 8) | event[9];
- reg = (reg << 8) | event[8];
- reg = (reg << 8) | event[7];
- *code = reg;
- cleanup:
- free(event);
- return err;
- }
- #define GET_VERSION_OCF 0x1E
- static int read_ath3k_version(int pConfig, uint32_t *rom_version,
- uint32_t *build_version)
- {
- uint8_t cmd[3];
- uint8_t *event;
- int err;
- int status;
- hci_command_hdr *ch = (void *)cmd;
- ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
- GET_VERSION_OCF));
- ch->plen = 0;
- err = send_hci_cmd_sync(pConfig, cmd, sizeof(cmd), &event);
- if (err < 0)
- return err;
- err = read_ps_event(event, GET_VERSION_OCF);
- if (err < 0)
- goto cleanup;
- status = event[10];
- status = (status << 8) | event[9];
- status = (status << 8) | event[8];
- status = (status << 8) | event[7];
- *rom_version = status;
- status = event[14];
- status = (status << 8) | event[13];
- status = (status << 8) | event[12];
- status = (status << 8) | event[11];
- *build_version = status;
- cleanup:
- free(event);
- return err;
- }
- static void convert_bdaddr(char *str_bdaddr, char *bdaddr)
- {
- char bdbyte[3];
- char *str_byte = str_bdaddr;
- int i, j;
- int colon_present = 0;
- if (strstr(str_bdaddr, ":"))
- colon_present = 1;
- bdbyte[2] = '\0';
- /* Reverse the BDADDR to LSB first */
- for (i = 0, j = 5; i < 6; i++, j--) {
- bdbyte[0] = str_byte[0];
- bdbyte[1] = str_byte[1];
- bdaddr[j] = strtol(bdbyte, NULL, 16);
- if (colon_present == 1)
- str_byte += 3;
- else
- str_byte += 2;
- }
- }
- static int write_bdaddr(int pConfig, char *bdaddr)
- {
- uint8_t *event;
- int err;
- uint8_t cmd[13];
- uint8_t *ptr = cmd;
- hci_command_hdr *ch = (void *)cmd;
- memset(cmd, 0, sizeof(cmd));
- ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
- HCI_PS_CMD_OCF));
- ch->plen = 10;
- ptr += HCI_COMMAND_HDR_SIZE;
- ptr[0] = 0x01;
- ptr[1] = 0x01;
- ptr[2] = 0x00;
- ptr[3] = 0x06;
- convert_bdaddr(bdaddr, (char *)&ptr[4]);
- err = send_hci_cmd_sync(pConfig, cmd, sizeof(cmd), &event);
- if (err < 0)
- return err;
- err = read_ps_event(event, HCI_PS_CMD_OCF);
- free(event);
- return err;
- }
- #define BDADDR_FILE "ar3kbdaddr.pst"
- static void write_bdaddr_from_file(int rom_version, int fd)
- {
- FILE *stream;
- char bdaddr[PATH_MAX];
- char bdaddr_file[PATH_MAX];
- snprintf(bdaddr_file, MAXPATHLEN, "%s%x/%s",
- FW_PATH, rom_version, BDADDR_FILE);
- stream = fopen(bdaddr_file, "r");
- if (!stream)
- return;
- if (fgets(bdaddr, PATH_MAX - 1, stream))
- write_bdaddr(fd, bdaddr);
- fclose(stream);
- }
- static int ath_ps_download(int fd)
- {
- int err = 0;
- int tag_count;
- int patch_count = 0;
- uint32_t rom_version = 0;
- uint32_t build_version = 0;
- uint32_t dev_type = 0;
- char patch_file[PATH_MAX];
- char ps_file[PATH_MAX];
- FILE *stream;
- /*
- * Verfiy firmware version. depending on it select the PS
- * config file to download.
- */
- if (get_device_type(fd, &dev_type) < 0) {
- err = -EILSEQ;
- goto download_cmplete;
- }
- if (read_ath3k_version(fd, &rom_version, &build_version) < 0) {
- err = -EILSEQ;
- goto download_cmplete;
- }
- /* Do not download configuration if CRC passes */
- if (get_ath3k_crc(fd) < 0) {
- err = 0;
- goto download_cmplete;
- }
- get_ps_file_name(dev_type, rom_version, ps_file, NULL);
- get_patch_file_name(dev_type, rom_version, build_version, patch_file);
- stream = fopen(ps_file, "r");
- if (!stream) {
- perror("firmware file open error\n");
- err = -EILSEQ;
- goto download_cmplete;
- }
- tag_count = ath_parse_ps(stream);
- fclose(stream);
- if (tag_count < 0) {
- err = -EILSEQ;
- goto download_cmplete;
- }
- stream = fopen(patch_file, "r");
- if(stream) {
- patch_count = ps_patch_download(fd, stream);
- fclose(stream);
- if (patch_count < 0) {
- err = -EILSEQ;
- goto download_cmplete;
- }
- }
- err = ps_config_download(fd, tag_count);
- download_cmplete:
- if (!err)
- write_bdaddr_from_file(rom_version, fd);
- return err;
- }
- #define HCI_SLEEP_CMD_OCF 0x04
- /*
- * Atheros AR300x specific initialization post callback
- */
- int ath3k_post(int fd, int pm)
- {
- int dev_id, dd;
- struct timespec tm = { 0, 50000 };
- sleep(1);
- dev_id = ioctl(fd, HCIUARTGETDEVICE, 0);
- if (dev_id < 0) {
- perror("cannot get device id");
- return dev_id;
- }
- dd = hci_open_dev(dev_id);
- if (dd < 0) {
- perror("HCI device open failed");
- return dd;
- }
- if (ioctl(dd, HCIDEVUP, dev_id) < 0 && errno != EALREADY) {
- perror("hci down:Power management Disabled");
- hci_close_dev(dd);
- return -1;
- }
- /* send vendor specific command with Sleep feature Enabled */
- if (hci_send_cmd(dd, OGF_VENDOR_CMD, HCI_SLEEP_CMD_OCF, 1, &pm) < 0)
- perror("PM command failed, power management Disabled");
- nanosleep(&tm, NULL);
- hci_close_dev(dd);
- return 0;
- }
- #define HCI_VENDOR_CMD_OGF 0x3F
- #define HCI_PS_CMD_OCF 0x0B
- #define HCI_CHG_BAUD_CMD_OCF 0x0C
- #define WRITE_BDADDR_CMD_LEN 14
- #define WRITE_BAUD_CMD_LEN 6
- #define MAX_CMD_LEN WRITE_BDADDR_CMD_LEN
- static int set_cntrlr_baud(int fd, int speed)
- {
- int baud;
- struct timespec tm = { 0, 500000 };
- unsigned char cmd[MAX_CMD_LEN], rsp[HCI_MAX_EVENT_SIZE];
- unsigned char *ptr = cmd + 1;
- hci_command_hdr *ch = (void *)ptr;
- cmd[0] = HCI_COMMAND_PKT;
- /* set controller baud rate to user specified value */
- ptr = cmd + 1;
- ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
- HCI_CHG_BAUD_CMD_OCF));
- ch->plen = 2;
- ptr += HCI_COMMAND_HDR_SIZE;
- baud = speed/100;
- ptr[0] = (char)baud;
- ptr[1] = (char)(baud >> 8);
- if (write(fd, cmd, WRITE_BAUD_CMD_LEN) != WRITE_BAUD_CMD_LEN) {
- perror("Failed to write change baud rate command");
- return -ETIMEDOUT;
- }
- nanosleep(&tm, NULL);
- if (read_hci_event(fd, rsp, sizeof(rsp)) < 0)
- return -ETIMEDOUT;
- return 0;
- }
- /*
- * Atheros AR300x specific initialization and configuration file
- * download
- */
- int ath3k_init(int fd, int speed, int init_speed, char *bdaddr,
- struct termios *ti)
- {
- int r;
- int err = 0;
- struct timespec tm = { 0, 500000 };
- unsigned char cmd[MAX_CMD_LEN], rsp[HCI_MAX_EVENT_SIZE];
- unsigned char *ptr = cmd + 1;
- hci_command_hdr *ch = (void *)ptr;
- cmd[0] = HCI_COMMAND_PKT;
- /* set both controller and host baud rate to maximum possible value */
- err = set_cntrlr_baud(fd, speed);
- if (err < 0)
- return err;
- err = set_speed(fd, ti, speed);
- if (err < 0) {
- perror("Can't set required baud rate");
- return err;
- }
- /* Download PS and patch */
- r = ath_ps_download(fd);
- if (r < 0) {
- perror("Failed to Download configuration");
- err = -ETIMEDOUT;
- goto failed;
- }
- /* Write BDADDR */
- if (bdaddr) {
- ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
- HCI_PS_CMD_OCF));
- ch->plen = 10;
- ptr += HCI_COMMAND_HDR_SIZE;
- ptr[0] = 0x01;
- ptr[1] = 0x01;
- ptr[2] = 0x00;
- ptr[3] = 0x06;
- str2ba(bdaddr, (bdaddr_t *)(ptr + 4));
- if (write(fd, cmd, WRITE_BDADDR_CMD_LEN) !=
- WRITE_BDADDR_CMD_LEN) {
- perror("Failed to write BD_ADDR command\n");
- err = -ETIMEDOUT;
- goto failed;
- }
- if (read_hci_event(fd, rsp, sizeof(rsp)) < 0) {
- perror("Failed to set BD_ADDR\n");
- err = -ETIMEDOUT;
- goto failed;
- }
- }
- /* Send HCI Reset */
- cmd[1] = 0x03;
- cmd[2] = 0x0C;
- cmd[3] = 0x00;
- r = write(fd, cmd, 4);
- if (r != 4) {
- err = -ETIMEDOUT;
- goto failed;
- }
- nanosleep(&tm, NULL);
- if (read_hci_event(fd, rsp, sizeof(rsp)) < 0) {
- err = -ETIMEDOUT;
- goto failed;
- }
- err = set_cntrlr_baud(fd, speed);
- if (err < 0)
- return err;
- failed:
- if (err < 0) {
- set_cntrlr_baud(fd, init_speed);
- set_speed(fd, ti, init_speed);
- }
- return err;
- }
|