M7350/external/compat-wireless/drivers/net/wireless/ath/ath6kl/softmac.c
2024-09-09 08:57:42 +00:00

206 lines
4.8 KiB
C

/*
* Copyright (c) 2011 Atheros Communications Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "core.h"
#include "debug.h"
#include <linux/vmalloc.h>
#define MAC_FILE "ath6k/AR6003/hw2.1.1/softmac"
typedef char A_CHAR;
extern int android_readwrite_file(const A_CHAR *filename, A_CHAR *rbuf, const A_CHAR *wbuf, size_t length);
/* Bleh, same offsets. */
#define AR6003_MAC_ADDRESS_OFFSET 0x16
#define AR6004_MAC_ADDRESS_OFFSET 0x16
/* Global variables, sane coding be damned. */
u8 *ath6kl_softmac;
size_t ath6kl_softmac_len;
static void ath6kl_calculate_crc(u32 target_type, u8 *data, size_t len)
{
u16 *crc, *data_idx;
u16 checksum;
int i;
if (target_type == TARGET_TYPE_AR6003) {
crc = (u16 *)(data + 0x04);
} else if (target_type == TARGET_TYPE_AR6004) {
len = 1024;
crc = (u16 *)(data + 0x04);
} else {
ath6kl_err("Invalid target type\n");
return;
}
ath6kl_dbg(ATH6KL_DBG_BOOT, "Old Checksum: %u\n", *crc);
*crc = 0;
checksum = 0;
data_idx = (u16 *)data;
for (i = 0; i < len; i += 2) {
checksum = checksum ^ (*data_idx);
data_idx++;
}
*crc = cpu_to_le16(checksum);
ath6kl_dbg(ATH6KL_DBG_BOOT, "New Checksum: %u\n", checksum);
}
#ifdef CONFIG_MACH_PX
static int ath6kl_fetch_nvmac_info(struct ath6kl *ar)
{
char softmac_filename[256];
int ret = 0;
do {
snprintf(softmac_filename, sizeof(softmac_filename),
"/data/.nvmac.info");
if ( (ret = android_readwrite_file(
softmac_filename, NULL, NULL, 0)) < 0) {
break;
} else {
ath6kl_softmac_len = ret;
}
ath6kl_softmac = vmalloc(ath6kl_softmac_len);
if (!ath6kl_softmac) {
ath6kl_dbg(ATH6KL_DBG_BOOT,
"%s: Cannot allocate buffer for nvmac.info"
"(%d)\n", __func__,ath6kl_softmac_len);
ret = -ENOMEM;
break;
}
if ( (ret = android_readwrite_file(softmac_filename,
(char*)ath6kl_softmac, NULL, ath6kl_softmac_len)) !=
ath6kl_softmac_len) {
ath6kl_dbg(ATH6KL_DBG_BOOT,"%s: file read error, length %d\n",
__func__, ath6kl_softmac_len);
vfree(ath6kl_softmac);
ret = -1;
break;
}
if (!strncmp(ath6kl_softmac,"00:00:00:00:00:00",17)) {
ath6kl_dbg(ATH6KL_DBG_BOOT,"%s: mac address is zero\n",
__func__);
vfree(ath6kl_softmac);
ret = -1;
break;
}
ret = 0;
} while (0);
return ret;
}
#else
static int ath6kl_fetch_mac_file(struct ath6kl *ar)
{
const struct firmware *fw_entry;
int ret = 0;
ret = request_firmware(&fw_entry, MAC_FILE, ar->dev);
if (ret)
return ret;
ath6kl_softmac_len = fw_entry->size;
ath6kl_softmac = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL);
if (ath6kl_softmac == NULL)
ret = -ENOMEM;
release_firmware(fw_entry);
return ret;
}
#endif
void ath6kl_mangle_mac_address(struct ath6kl *ar, u8 locally_administered_bit)
{
u8 *ptr_mac;
int i, ret;
#ifdef CONFIG_MACH_PX
unsigned int softmac[6];
#endif
switch (ar->target_type) {
case TARGET_TYPE_AR6003:
ptr_mac = ar->fw_board + AR6003_MAC_ADDRESS_OFFSET;
break;
case TARGET_TYPE_AR6004:
ptr_mac = ar->fw_board + AR6004_MAC_ADDRESS_OFFSET;
break;
default:
ath6kl_err("Invalid Target Type\n");
return;
}
ath6kl_dbg(ATH6KL_DBG_BOOT,
"MAC from EEPROM %02X:%02X:%02X:%02X:%02X:%02X\n",
ptr_mac[0], ptr_mac[1], ptr_mac[2],
ptr_mac[3], ptr_mac[4], ptr_mac[5]);
#ifdef CONFIG_MACH_PX
ret = ath6kl_fetch_nvmac_info(ar);
if (ret) {
ath6kl_err("MAC address file not found\n");
return;
}
if (sscanf(ath6kl_softmac, "%02x:%02x:%02x:%02x:%02x:%02x",
&softmac[0], &softmac[1], &softmac[2],
&softmac[3], &softmac[4], &softmac[5])==6) {
for (i=0; i<6; ++i) {
ptr_mac[i] = softmac[i] & 0xff;
}
}
ath6kl_dbg(ATH6KL_DBG_BOOT,
"MAC from SoftMAC %02X:%02X:%02X:%02X:%02X:%02X\n",
ptr_mac[0], ptr_mac[1], ptr_mac[2],
ptr_mac[3], ptr_mac[4], ptr_mac[5]);
vfree(ath6kl_softmac);
#else
ret = ath6kl_fetch_mac_file(ar);
if (ret) {
ath6kl_err("MAC address file not found\n");
return;
}
for (i = 0; i < ETH_ALEN; ++i) {
ptr_mac[i] = ath6kl_softmac[i] & 0xff;
}
kfree(ath6kl_softmac);
#endif
if (locally_administered_bit)
ptr_mac[0] |= 0x02;
if (locally_administered_bit)
ptr_mac[0] |= 0x02;
ath6kl_calculate_crc(ar->target_type, ar->fw_board, ar->fw_board_len);
}