Skip to content

Instantly share code, notes, and snippets.

@hex128
Last active July 30, 2016 17:29
Show Gist options
  • Save hex128/0cd6ecf5cda6ccca18eb to your computer and use it in GitHub Desktop.
Save hex128/0cd6ecf5cda6ccca18eb to your computer and use it in GitHub Desktop.
0000000: 405a 5000 0060 0000 0100 3500 8002 8680 @ZP..`....5.....
0000010: 2b42 8680 0111 010d 8b03 0005 f000 4000 /B............@.
0000020: c9de 5014 0e24 3101 4b88 0024 d7a6 4d0c ..P..$1.K..$..M.
0000030: 1669 1679 1689 1699 ffff 1000 feff 0000 .i.y............
0000040: 7419 0c03 0000 0460 fdec 1003 0418 44e2 t......`......D.
0000050: cc77 2201 1469 9224 1a00 9831 6bcc 8f1f .w"..i.$...1k...
0000060: e0cf 8007 e0c1 b83f 3fff 0000 0000 2000 .......??..... .
0000070: 280a 810e 0000 0000 0000 0000 0000 0000 (...............
0000080: 0000 0000 0000 ebdb 3604 f001 4611 0000 ........6...F...
0000090: 1c77 0024 d7a6 4d0d 0400 0000 0000 5000 .w.$..M.......P.
00000a0: 4136 3444 3043 3131 3143 5645 3637 3136 A64D0C111CVE6716
00000b0: 3230 3037 0000 c430 663e 0000 0000 0000 2007...0f>......
00000c0: 0000 0000 0000 0000 6e00 9000 a400 8401 ........n.......
00000d0: fe03 ff03 f800 7f00 0000 0000 00c6 0000 ................
00000e0: 3842 0000 0000 0000 0000 0000 0000 0000 8B..............
00000f0: 0000 0000 0000 01c0 1100 0110 0100 8c00 ................
0000100: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000110: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000120: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000130: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000140: 0000 0000 0000 0000 0e00 4d6f 5700 0000 ..........MoW...
0000150: 6f00 6f00 6f00 6f00 6f00 6f00 6f00 6f00 o.o.o.o.o.o.o.o.
0000160: 6f00 6f00 6f00 6100 6100 0000 0000 0000 o.o.o.a.a.......
0000170: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000180: 0000 0000 0000 0000 0000 0000 e100 0000 ................
0000190: e100 0000 e100 0000 e100 3100 3100 3100 ..........1.1.1.
00001a0: 3100 0000 3100 3100 3100 3100 3100 3100 1...1.1.1.1.1.1.
00001b0: 3100 3100 3100 3100 3100 0000 0000 e100 1.1.1.1.1.......
00001c0: e100 e100 e100 e100 6f00 6f00 6f00 6f00 ........o.o.o.o.
00001d0: 6f00 6f00 6f00 6100 6100 e100 e100 3100 o.o.o.a.a.....1.
00001e0: 3100 3100 3100 3100 3100 3100 6100 6100 1.1.1.1.1.1.a.a.
00001f0: 0100 1d1d 1d00 0000 0500 1e1e 1e00 0000 ................
0000200: 1500 1e1e 1e00 1814 1d00 1c1c 1c00 1814 ................
0000210: 0700 1e1e 1e00 0000 1700 1e1e 1e00 1814 ................
0000220: 1f00 1e1e 1e00 1814 0501 1a1a 1a00 0000 ................
0000230: 1501 191a 1a00 1712 0502 1e1e 1e00 0000 ................
0000240: 1502 1e1e 1e00 1814 050a 1e1e 1e00 0000 ................
0000250: 150a 1e1e 1e00 1814 050b 1a1a 1a00 0000 ................
0000260: 150b 1a1a 1a00 1711 1d03 1312 1200 100f ................
0000270: 1d04 1616 1600 1211 1d08 1616 1700 1211 ................
0000280: 1d09 1313 1400 100f 1d0b 1b1b 1b00 1614 ................
0000290: 0724 1e1b 1b00 0000 0740 1e1e 1e00 0000 .$.......@......
00002a0: 0764 1e1e 1e00 0000 1724 1e1b 1a00 1814 .d.......$......
00002b0: 1740 1e1d 1e00 1814 1764 1e1e 1d00 1814 [email protected]......
00002c0: 1f26 1a14 1300 1212 1f3e 1c16 1600 1412 .&.......>......
00002d0: 1f66 1d19 1a00 1712 050d 1a1a 1a00 0000 .f..............
00002e0: 150d 1a1a 1a00 1614 078c 1e1d 1d00 0000 ................
00002f0: 178c 1e1e 1e00 1814 1f86 1e1d 1d00 1812 ................
0000300: 1f2e 1c1c 1c00 1612 0600 170d 2d22 c82f ............-"./
0000310: 2929 c22e 2432 b52f 1e3d 9c2e 1a44 862e ))..$2./.=...D..
0000320: 2027 c42e 2806 00f5 4222 c82e 3e2a c02e '..(...B"..>*..
0000330: 3935 b22e 3340 9e2e 2f48 882e 372a bc2e 95..3@../H..7*..
0000340: 2824 00f2 4322 c72e 3f2a c02f 3a34 b22e ($..C"..?*./:4..
0000350: 353e 9f2e 3145 8d2d 382a bc2d 2840 00f3 5>..1E.-8*.-(@..
0000360: 4223 c52d 3e2b bd2d 3a33 b32d 343f 9c2d B#.->+.-:3.-4?.-
0000370: 3046 882d 372b b82d 2864 00f2 4322 c62e 0F.-7+.-(d..C"..
0000380: 3f2a bf2e 3a35 b22d 3440 9a2d 3048 882e ?*..:[email protected]..
0000390: 372b b92e 2888 00f3 4121 c92d 3d29 c22e 7+..(...A!.-=)..
00003a0: 3833 b72d 333d a72d 2f46 972e 352a bc2e 83.-3=.-/F..5*..
00003b0: 289d 00f1 0000 0000 0000 0000 0000 0000 (...............
00003c0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00003d0: 2a22 c830 262a c32e 2133 ba30 1b3d a42e *".0&*..!3.0.=..
00003e0: 1744 9030 1c2b c130 2806 00f5 3421 c831 .D.0.+.0(...4!.1
00003f0: 3028 c02e 2935 a831 233e 882e 1f44 6731 0(..)5.1#>...Dg1
0000400: 242a bd31 2824 00f2 3522 ce32 3129 c832 $*.1($..5".21).2
0000410: 2a35 b631 253e 9e31 2144 8b32 2628 c632 *5.1%>.1!D.2&(.2
0000420: 2840 00f3 3422 cf31 3029 c832 2a34 bb31 (@..4".10).2*4.1
0000430: 243e a031 2044 8931 242b c432 2864 00f2 $>.1 D.1$+.2(d..
0000440: 3124 cc32 2d2c c431 2835 ba31 223f a231 1$.2-,.1(5.1"?.1
0000450: 1e45 8c32 2329 c732 2888 00f3 2e25 c932 .E.2#).2(....%.2
0000460: 2a2c c032 2535 b332 1e40 9232 1a45 6e32 *,.2%[email protected]
0000470: 202a c232 289d 00f1 0000 0000 0000 0000 *.2(...........
0000480: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000490: 0000 0000 2a21 c831 2629 c132 2033 b131 ....*!.1&).2 3.1
00004a0: 1a3e 9032 1644 7431 1d29 c130 2806 00f5 .>.2.Dt1.).0(...
00004b0: 3722 c831 3329 bf30 2d35 a831 273e 8530 7".13).0-5.1'>.0
00004c0: 2344 6931 272a bd31 2824 00f2 3623 c931 #Di1'*.1($..6#.1
00004d0: 322a c231 2c35 b032 273d 9932 2344 7f31 2*.1,5.2'=.2#D.1
00004e0: 2729 c331 2840 00f3 3524 c831 312b c031 ').1(@..5$.11+.1
00004f0: 2c34 ad31 263f 9231 2245 7731 262a c031 ,4.1&?.1"Ew1&*.1
0000500: 2864 00f2 3225 c631 2e2c bc32 2935 a831 (d..2%.1.,.2)5.1
0000510: 233f 8731 1f45 6f31 242a bf32 2888 00f3 #?.1.Eo1$*.2(...
0000520: 3124 ca31 2d2c c132 2834 b131 2140 9331 1$.1-,.2([email protected]
0000530: 1d46 7531 2328 c631 289d 00f1 0000 0000 .Fu1#(.1(.......
0000540: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000550: 0000 0000 0000 0000 7600 7600 0000 0000 ........v.v.....
0000560: 0000 ff00 0300 ff00 0300 0001 0700 ff00 ................
0000570: 0300 fe00 0200 ff00 0200 0001 0700 ff00 ................
0000580: 0300 0001 0700 ff00 0300 ff00 0300 0001 ................
0000590: 0700 fe00 0400 fd00 0400 fe00 0700 fe00 ................
00005a0: 0400 fd00 0400 fd00 0400 fe00 0700 fe00 ................
00005b0: 0400 fe00 0800 fe00 0400 fd00 0400 fe00 ................
00005c0: 0700 fd00 0400 fd00 0500 fe00 0700 fd00 ................
00005d0: 0400 fd00 0400 fd00 0400 fe00 0700 fd00 ................
00005e0: 0500 fe00 0700 fd00 0400 fd00 0400 fe00 ................
00005f0: 0700 fd00 0500 fc00 0400 fe00 0700 fc00 ................
0000600: 0500 fc00 0400 fc00 0400 fe00 0700 fc00 ................
0000610: 0500 fd00 0700 fc00 0500 fc00 0400 fd00 ................
0000620: 0700 fc00 0500 fc00 0400 fd00 0700 fc00 ................
0000630: 0500 fc00 0500 fc00 0500 fd00 0700 fc00 ................
0000640: 0400 fd00 0700 fc00 0500 fc00 0400 fd00 ................
0000650: 0700 fc00 0500 fb00 0400 fd00 0700 fc00 ................
0000660: 0500 fb00 0500 fb00 0400 fd00 0700 fc00 ................
0000670: 0500 fd00 0700 fc00 0500 fb00 0400 fd00 ................
0000680: 0700 0201 fdff 0001 fdff 0101 fbff 0101 ................
0000690: fdff 0001 fdff 0001 fdff 0101 fbff 0101 ................
00006a0: fdff 0101 fbff 0101 fdff 0001 fdff 0101 ................
00006b0: faff 5baf 4e63 3847 0000 0000 0000 0000 ..[.Nc8G........
00006c0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00006d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00006e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00006f0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000700: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000710: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000720: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000730: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000740: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000750: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000760: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000770: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000780: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000790: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00007a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00007b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00007c0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00007d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00007e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00007f0: 0000 0000 0000 0000 0000 0000 0000 32a5 ..............2.
gcc -o iwleeprom iwleeprom.c
xxd -r 6300.hex 6300.bin
./iwleeprom -i 6300.bin
/*
****************************************************************************
*
* iwleeprom - EEPROM reader/writer for intel wifi cards.
* Copyright (C) 2010, Alexander "ittrium" Kalinichenko <[email protected]>
* ICQ: 152322, Skype: ittr1um
* Copyright (C) 2010, Gennady "ShultZ" Kozlov <[email protected]>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
****************************************************************************
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdint.h>
#include <string.h>
#include <dirent.h>
#include <getopt.h>
#include <endian.h>
//#define DEBUG
#define MMAP_LENGTH 4096
#define EEPROM_SIZE_4965 1024
#define EEPROM_SIZE_5K 2048
#define EEPROM_SIZE_MAX 2048
#define IWL_SIGNATURE 0x5a40
uint16_t buf[EEPROM_SIZE_MAX/2];
static struct option long_options[] = {
{"device", 1, NULL, 'd'},
{"nodev", 0, NULL, 'n'},
{"preserve-mac", 0, NULL, 'm'},
{"preserve-calib", 0, NULL, 'c'},
{"read", 0, NULL, 'r'},
{"write", 0, NULL, 'w'},
{"ifile", 1, NULL, 'i'},
{"ofile", 1, NULL, 'o'},
{"bigendian", 0, NULL, 'b'},
{"help", 0, NULL, 'h'},
{"list", 0, NULL, 'l'},
{"debug", 1, NULL, 'D'},
{"init", 0, NULL, 'I'},
{"patch11n", 0, NULL, 'p'},
{"all-channels", 0, NULL, 'a'},
{"show-regulatory", 0, NULL, 's'}
};
struct pcidev_id
{
unsigned int class,
ven, dev,
sven, sdev;
int idx;
size_t eeprom_size;
char *device;
};
struct pci_id
{
unsigned int ven, dev;
bool writable;
size_t eeprom_size;
char name[64];
};
enum byte_order
{
order_unknown = 0,
order_be,
order_le
};
int mem_fd;
char *mappedAddress;
unsigned int offset;
unsigned char eeprom_locked;
enum byte_order dump_order;
uid_t ruid,euid,suid;
void die( const char* format, ... );
char *ifname = NULL,
*ofname = NULL;
bool patch11n = false,
all_channels = false,
show_regulatory = false,
init_device = false,
nodev = false,
preserve_mac = false,
preserve_calib = false;
unsigned int debug = 0;
struct pcidev_id dev;
#define DEVICES_PATH "/sys/bus/pci/devices"
struct pci_id valid_ids[] = {
{ 0x8086, 0x0082, 1, EEPROM_SIZE_5K, "6000 Series Gen2"},
{ 0x8086, 0x0083, 1, EEPROM_SIZE_5K, "Centrino Wireless-N 1000"},
{ 0x8086, 0x0084, 1, EEPROM_SIZE_5K, "Centrino Wireless-N 1000"},
{ 0x8086, 0x0085, 1, EEPROM_SIZE_5K, "6000 Series Gen2"},
{ 0x8086, 0x0087, 1, EEPROM_SIZE_5K, "Centrino Advanced-N + WiMAX 6250"},
{ 0x8086, 0x0089, 1, EEPROM_SIZE_5K, "Centrino Advanced-N + WiMAX 6250"},
{ 0x8086, 0x0885, 1, EEPROM_SIZE_5K, "WiFi+WiMAX 6050 Series Gen2"},
{ 0x8086, 0x0886, 1, EEPROM_SIZE_5K, "WiFi+WiMAX 6050 Series Gen2"},
{ 0x8086, 0x4229, 1, EEPROM_SIZE_4965, "PRO/Wireless 4965 AG or AGN [Kedron] Network Connection"},
{ 0x8086, 0x422b, 1, EEPROM_SIZE_5K, "Centrino Ultimate-N 6300"},
{ 0x8086, 0x422c, 1, EEPROM_SIZE_5K, "Centrino Advanced-N 6200"},
{ 0x8086, 0x4230, 1, EEPROM_SIZE_4965, "PRO/Wireless 4965 AG or AGN [Kedron] Network Connection"},
{ 0x8086, 0x4232, 1, EEPROM_SIZE_5K, "WiFi Link 5100"},
{ 0x8086, 0x4235, 1, EEPROM_SIZE_5K, "Ultimate N WiFi Link 5300"},
{ 0x8086, 0x4236, 1, EEPROM_SIZE_5K, "Ultimate N WiFi Link 5300"},
{ 0x8086, 0x4237, 1, EEPROM_SIZE_5K, "PRO/Wireless 5100 AGN [Shiloh] Network Connection"},
{ 0x8086, 0x4238, 1, EEPROM_SIZE_5K, "Centrino Ultimate-N 6300"},
{ 0x8086, 0x4239, 1, EEPROM_SIZE_5K, "Centrino Advanced-N 6200"},
{ 0x8086, 0x423a, 1, EEPROM_SIZE_5K, "PRO/Wireless 5350 AGN [Echo Peak] Network Connection"},
{ 0x8086, 0x423b, 1, EEPROM_SIZE_5K, "PRO/Wireless 5350 AGN [Echo Peak] Network Connection"},
{ 0x8086, 0x423c, 1, EEPROM_SIZE_5K, "WiMAX/WiFi Link 5150"},
{ 0x8086, 0x423d, 1, EEPROM_SIZE_5K, "WiMAX/WiFi Link 5150"},
{ 0, 0, 0, 0, "" }
};
#if BYTE_ORDER == BIG_ENDIAN
#define cpu2le16(x) __bswap_16(x)
#define cpu2be16(x) x
#define le2cpu16(x) __bswap_16(x)
#define be2cpu16(x) x
#elif BYTE_ORDER == LITTLE_ENDIAN
#define cpu2le16(x) x
#define cpu2be16(x) __bswap_16(x)
#define le2cpu16(x) x
#define be2cpu16(x) __bswap_16(x)
#else
#error Unsupported BYTE_ORDER!
#endif
void eeprom_lock()
{
unsigned long data;
if (nodev) return;
memcpy(&data, mappedAddress, 4);
data |= 0x00200000;
memcpy(mappedAddress, &data, 4);
usleep(5);
memcpy(&data, mappedAddress, 4);
if ((data & 0x00200000) != 0x00200000)
die("err! ucode is using eeprom!\n");
eeprom_locked = 1;
}
void eeprom_unlock()
{
unsigned long data;
if (nodev) return;
memcpy(&data, mappedAddress, 4);
data &= ~0x00200000;
memcpy(mappedAddress, &data, 4);
usleep(5);
memcpy(&data, mappedAddress, 4);
if ((data & 0x00200000) == 0x00200000)
die("err! software is still using eeprom!\n");
eeprom_locked = 0;
}
void init_card()
{
if ((mem_fd = open("/dev/mem", O_RDWR | O_SYNC)) < 0) {
printf("cannot open /dev/mem\n");
exit(1);
}
mappedAddress = (char *)mmap(NULL, MMAP_LENGTH, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_LOCKED, mem_fd, offset);
if (mappedAddress == MAP_FAILED) {
perror("mmap failed");
exit(1);
}
}
void initpower()
{
unsigned int data;
memcpy(&data, mappedAddress + 0x100, 4);
data |= 0x20000000;
memcpy(mappedAddress + 0x100, &data, 4);
usleep(20);
memcpy(&data, mappedAddress + 0x100, 4);
data |= 0x00800000;
memcpy(mappedAddress + 0x100, &data, 4);
usleep(20);
memcpy(&data, mappedAddress + 0x240, 4);
data |= 0xFFFF0000;
memcpy(mappedAddress + 0x240, &data, 4);
usleep(20);
memcpy(&data, mappedAddress + 0x00, 4);
data |= 0x00080000;
memcpy(mappedAddress + 0x00, &data, 4);
usleep(20);
memcpy(&data, mappedAddress + 0x20c, 4);
data |= 0x00880300;
memcpy(mappedAddress + 0x20c, &data, 4);
usleep(20);
memcpy(&data, mappedAddress + 0x24, 4);
data |= 0x00000004;
memcpy(mappedAddress + 0x24, &data, 4);
usleep(20);
if (debug)
printf("Device has been inited.\n");
}
void release_card()
{
if (mappedAddress != NULL)
munmap(mappedAddress, MMAP_LENGTH);
}
void init_dump(char *filename)
{
FILE *fd;
seteuid(ruid);
if (!(fd = fopen(filename, "rb")))
die("Can't read file %s\n", filename);
dev.eeprom_size = 2 * fread(buf, 2, EEPROM_SIZE_MAX/2, fd);
fclose(fd);
seteuid(suid);
printf("Dump file: %s (read %Ld bytes)\n", filename, (uint64_t) dev.eeprom_size);
if(dev.eeprom_size < EEPROM_SIZE_4965)
die("Too small file!\n");
if ( IWL_SIGNATURE == le2cpu16(buf[0])) {
dump_order = order_le;
} else if ( IWL_SIGNATURE == be2cpu16(buf[0])) {
dump_order = order_be;
} else {
die("Invalid EEPROM signature!\n");
}
printf(" byte order: %s ENDIAN\n", (dump_order == order_le) ? "LITTLE":"BIG");
}
void fixate_dump(char *filename)
{
FILE *fd;
seteuid(ruid);
if (!(fd = fopen(filename, "wb")))
die("Can't create file %s\n", filename);
fwrite(buf, dev.eeprom_size, 1, fd);
printf("Dump file written: %s\n", filename);
fclose(fd);
seteuid(suid);
}
const uint16_t eeprom_read16(unsigned int addr)
{
uint16_t value;
if (nodev) goto _nodev;
unsigned int data = 0x0000FFFC & (addr << 1);
memcpy(mappedAddress + 0x2c, &data, 4);
usleep(50);
memcpy(&data, mappedAddress + 0x2c, 4);
if ((data & 1) != 1)
die("Read not complete! Timeout at %.4dx\n", addr);
value = (data & 0xFFFF0000) >> 16;
return value;
_nodev:
if (addr >= EEPROM_SIZE_MAX) return 0;
if (dump_order == order_le)
return (le2cpu16(buf[addr/2]));
else
return (be2cpu16(buf[addr/2]));
}
void eeprom_write16(unsigned int addr, uint16_t value)
{
if (nodev) goto _nodev;
unsigned int data = value;
if (preserve_mac && ((addr>=0x2A && addr<0x30) || (addr>=0x92 && addr<0x97)))
return;
if (preserve_calib && (addr >= 0x200))
return;
data <<= 16;
data |= 0x0000FFFC & (addr << 1);
data |= 0x2;
memcpy(mappedAddress + 0x2c, &data, 4);
usleep(5000);
data = 0x0000FFC & (addr << 1);
memcpy(mappedAddress + 0x2c, &data, 4);
usleep(50);
memcpy(&data, mappedAddress + 0x2c, 4);
if ((data & 1) != 1)
die("Read not complete! Timeout at %.4dx\n", addr);
if (value != (data >> 16))
die("Verification error at %.4x\n", addr);
return;
_nodev:
if (addr >= EEPROM_SIZE_MAX) return;
if (dump_order == order_le)
buf[addr/2] = cpu2le16(value);
else
buf[addr/2] = cpu2be16(value);
}
void eeprom_read(char *filename)
{
unsigned int addr = 0;
FILE *fd;
dev.eeprom_size = valid_ids[dev.idx].eeprom_size;
seteuid(ruid);
if (!(fd = fopen(filename, "wb")))
die("Can't create file %s\n", filename);
seteuid(suid);
eeprom_lock();
printf("Saving dump with byte order: %s ENDIAN\n", (dump_order == order_le) ? "LITTLE":"BIG");
for (addr = 0; addr < dev.eeprom_size; addr += 2)
{
if (dump_order == order_le)
buf[addr/2] = cpu2le16( eeprom_read16(addr) );
else
buf[addr/2] = cpu2be16( eeprom_read16(addr) );
if (0 ==(addr & 0x7F)) printf("%04x [", addr);
printf(".");
if (0x7E ==(addr & 0x7F)) printf("]\n");
fflush(stdout);
}
seteuid(ruid);
fwrite(buf, dev.eeprom_size, 1, fd);
fclose(fd);
seteuid(suid);
eeprom_unlock();
printf("\nEEPROM has been dumped to %s\n", filename);
}
void eeprom_write(char *filename)
{
unsigned int addr = 0;
enum byte_order order = order_unknown;
uint16_t value;
size_t size;
FILE *fd;
dev.eeprom_size = valid_ids[dev.idx].eeprom_size;
seteuid(ruid);
if (!(fd = fopen(filename, "rb")))
die("Can't read file %s\n", filename);
size = 2 * fread(buf, 2, dev.eeprom_size/2, fd);
fclose(fd);
seteuid(suid);
eeprom_lock();
for(addr=0; addr<size;addr+=2)
{
if (order == order_unknown) {
if ( IWL_SIGNATURE == le2cpu16(buf[addr/2])) {
order = order_le;
} else if ( IWL_SIGNATURE == be2cpu16(buf[addr/2])) {
order = order_be;
} else {
die("Invalid EEPROM signature!\n");
}
printf("Dump file byte order: %s ENDIAN\n", (order == order_le) ? "LITTLE":"BIG");
}
if (order == order_be)
value = be2cpu16( buf[addr/2] );
else
value = le2cpu16( buf[addr/2] );
if (0 ==(addr & 0x7F)) printf("%04x [", addr);
if (eeprom_read16(addr) != value) {
eeprom_write16(addr, value);
printf(".");
} else {
printf("=");
}
if (0x7E ==(addr & 0x7F)) printf("]\n");
fflush(stdout);
}
eeprom_unlock();
printf("\nEEPROM has been written from %s\n", filename);
}
struct regulatory_item
{
unsigned int addr;
uint16_t data;
uint16_t chn;
};
#define HT40 0x100
struct regulatory_item regulatory[] =
{
/*
BAND 2.4GHz (@15e-179 with regulatory base @156)
*/
// enabling channels 12-14 (1-11 should be enabled on all cards)
{ 0x1E, 0x0f21, 12 },
{ 0x20, 0x0f21, 13 },
{ 0x22, 0x0f21, 14 },
/*
BAND 5GHz
*/
// subband 5170-5320 MHz (@198-1af)
// { 0x42, 0x0fe1, 34 },
{ 0x44, 0x0fe1, 36 },
// { 0x46, 0x0fe1, 38 },
{ 0x48, 0x0fe1, 40 },
// { 0x4a, 0x0fe1, 42 },
{ 0x4c, 0x0fe1, 44 },
// { 0x4e, 0x0fe1, 46 },
{ 0x50, 0x0fe1, 48 },
{ 0x52, 0x0f31, 52 },
{ 0x54, 0x0f31, 56 },
{ 0x56, 0x0f31, 60 },
{ 0x58, 0x0f31, 64 },
// subband 5500-5700 MHz (@1b2-1c7)
{ 0x5c, 0x0f31, 100 },
{ 0x5e, 0x0f31, 104 },
{ 0x60, 0x0f31, 108 },
{ 0x62, 0x0f31, 112 },
{ 0x64, 0x0f31, 116 },
{ 0x66, 0x0f31, 120 },
{ 0x68, 0x0f31, 124 },
{ 0x6a, 0x0f31, 128 },
{ 0x6c, 0x0f31, 132 },
{ 0x6e, 0x0f31, 136 },
{ 0x70, 0x0f31, 140 },
// subband 5725-5825 MHz (@1ca-1d5)
// { 0x74, 0x0fa1, 145 },
{ 0x76, 0x0fa1, 149 },
{ 0x78, 0x0fa1, 153 },
{ 0x7a, 0x0fa1, 157 },
{ 0x7c, 0x0fa1, 161 },
{ 0x7e, 0x0fa1, 165 },
/*
BAND 2.4GHz, HT40 channels (@1d8-1e5)
*/
{ 0x82, 0x0e6f, HT40 + 1 },
{ 0x84, 0x0f6f, HT40 + 2 },
{ 0x86, 0x0f6f, HT40 + 3 },
{ 0x88, 0x0f6f, HT40 + 4 },
{ 0x8a, 0x0f6f, HT40 + 5 },
{ 0x8c, 0x0f6f, HT40 + 6 },
{ 0x8e, 0x0f6f, HT40 + 7 },
/*
BAND 5GHz, HT40 channels (@1e8-1fd)
*/
{ 0x92, 0x0fe1, HT40 + 36 },
{ 0x94, 0x0fe1, HT40 + 44 },
{ 0x96, 0x0f31, HT40 + 52 },
{ 0x98, 0x0f31, HT40 + 60 },
{ 0x9a, 0x0f31, HT40 + 100 },
{ 0x9c, 0x0f31, HT40 + 108 },
{ 0x9e, 0x0f31, HT40 + 116 },
{ 0xa0, 0x0f31, HT40 + 124 },
{ 0xa2, 0x0f31, HT40 + 132 },
{ 0xa4, 0x0f61, HT40 + 149 },
{ 0xa6, 0x0f61, HT40 + 157 },
{ 0, 0}
};
struct regulatory_item regulatory_all[] =
{
/*
BAND 1
*/
{ 0x08, 0x0f6f, 1 },
{ 0x0A, 0x0f6f, 2 },
{ 0x0C, 0x0f6f, 3 },
{ 0x0E, 0x0f6f, 4 },
{ 0x10, 0x0f6f, 5 },
{ 0x12, 0x0f6f, 6 },
{ 0x14, 0x0f6f, 7 },
{ 0x16, 0x0f6f, 8 },
{ 0x18, 0x0f6f, 9 },
{ 0x1A, 0x0f6f, 10 },
{ 0x1C, 0x0f6f, 11 },
{ 0x1E, 0x0f61, 12 },
{ 0x20, 0x0f61, 13 },
{ 0x22, 0x0f61, 14 }, //not orig
/*
BAND 2 (all values not orig)
*/
/*
{ 0x26, 0x0, 183 },
{ 0x28, 0x0, 184 },
{ 0x2A, 0x0, 185 },
{ 0x2C, 0x0, 187 },
{ 0x2E, 0x0, 188 },
{ 0x30, 0x0, 189 },
{ 0x32, 0x0, 192 },
{ 0x34, 0x0, 196 },
{ 0x36, 0x0, 7 },
{ 0x38, 0x0, 8 },
{ 0x3A, 0x0, 11 },
{ 0x3C, 0x0, 12 },
{ 0x3E, 0x0, 16 },
*/
/*
BAND 3
*/
{ 0x42, 0x0fe1, 34 }, //not orig
{ 0x44, 0x0fe1, 36 },
{ 0x46, 0x0fe1, 38 }, //not orig
{ 0x48, 0x0fe1, 40 },
{ 0x4A, 0x0fe1, 42 }, //not orig
{ 0x4C, 0x0fe1, 44 },
{ 0x4E, 0x0fe1, 46 }, //not orig
{ 0x50, 0x0fe1, 48 },
{ 0x52, 0x0f31, 52 },
{ 0x54, 0x0f31, 56 },
{ 0x56, 0x0f31, 60 },
{ 0x58, 0x0f31, 64 },
/*
BAND 4
*/
{ 0x5C, 0x0f31, 100 },
{ 0x5E, 0x0f31, 104 },
{ 0x60, 0x0f31, 108 },
{ 0x62, 0x0f31, 112 },
{ 0x64, 0x0f31, 116 },
{ 0x66, 0x0f31, 120 },
{ 0x68, 0x0f31, 124 },
{ 0x6A, 0x0f31, 128 },
{ 0x6C, 0x0f31, 132 },
{ 0x6E, 0x0f31, 136 },
{ 0x70, 0x0f31, 140 },
/*
BAND 5
*/
{ 0x74, 0x0fe1, 145 }, //not orig
{ 0x76, 0x0fe1, 149 },
{ 0x78, 0x0fe1, 153 },
{ 0x7A, 0x0fe1, 157 },
{ 0x7C, 0x0fe1, 161 },
{ 0x7E, 0x0fe1, 165 },
/*
BAND 6
*/
{ 0x82, 0x0f6f, HT40 + 1 },
{ 0x84, 0x0f6f, HT40 + 2 },
{ 0x86, 0x0f6f, HT40 + 3 },
{ 0x88, 0x0f6f, HT40 + 4 },
{ 0x8A, 0x0f6f, HT40 + 5 },
{ 0x8C, 0x0f6f, HT40 + 6 },
{ 0x8E, 0x0f6f, HT40 + 7 },
/*
BAND 7
*/
{ 0x92, 0x0fe1, HT40 + 36 },
{ 0x94, 0x0fe1, HT40 + 44 },
{ 0x96, 0x0f31, HT40 + 52 },
{ 0x98, 0x0f31, HT40 + 60 },
{ 0x9A, 0x0f31, HT40 + 100 },
{ 0x9C, 0x0f31, HT40 + 108 },
{ 0x9E, 0x0f31, HT40 + 116 },
{ 0xA0, 0x0f31, HT40 + 124 },
{ 0xA2, 0x0f31, HT40 + 132 },
{ 0xA4, 0x0f61, HT40 + 149 },
{ 0xA6, 0x0f61, HT40 + 157 },
{ 0, 0}
};
void eeprom_show_regulatory()
{
uint16_t value;
unsigned int reg_offs;
int idx;
printf("Regulatory data from card EEPROM...\n");
eeprom_lock();
reg_offs = 2 * eeprom_read16(0xCC);
printf("Regulatory base: %04x\n", reg_offs);
for (idx=0; regulatory_all[idx].addr; idx++) {
value = eeprom_read16(reg_offs + regulatory_all[idx].addr);
printf("Channel %d%s:\t%04x\n", regulatory_all[idx].chn & ~HT40, (regulatory_all[idx].chn & HT40) ? " (HT40)" : "", value);
}
eeprom_unlock();
}
void eeprom_all_channels()
{
uint16_t value;
unsigned int reg_offs;
int idx;
printf("Write regulatory data for all channels unlock...\n");
eeprom_lock();
printf("-> Checking and adding channels...\n");
reg_offs = 2 * eeprom_read16(0xCC);
printf("Regulatory base: %04x\n", reg_offs);
for (idx=0; regulatory_all[idx].addr; idx++) {
value = eeprom_read16(reg_offs + regulatory_all[idx].addr);
if (value != regulatory_all[idx].data) {
printf(" %d%s\n", regulatory_all[idx].chn & ~HT40, (regulatory_all[idx].chn & HT40) ? " (HT40)" : "");
eeprom_write16(reg_offs + regulatory_all[idx].addr, regulatory_all[idx].data);
}
}
eeprom_unlock();
printf("\nCard EEPROM patched successfully\n");
}
void eeprom_patch11n()
{
uint16_t value;
unsigned int reg_offs;
int idx;
printf("Patching card EEPROM...\n");
eeprom_lock();
printf("-> Changing subdev ID\n");
value = eeprom_read16(0x14);
if ((value & 0x000F) == 0x0006) {
eeprom_write16(0x14, (value & 0xFFF0) | 0x0001);
}
/*
enabling .11n
W @8A << 00F0 (00B0) <- xxxx xxxx x1xx xxxx
W @8C << 103E (603F) <- x001 xxxx xxxx xxx0
*/
printf("-> Enabling 11n mode\n");
// SKU_CAP
value = eeprom_read16(0x8A);
if ((value & 0x0040) != 0x0040) {
printf(" SKU CAP\n");
eeprom_write16(0x8A, value | 0x0040);
}
// OEM_MODE
value = eeprom_read16(0x8C);
if ((value & 0x7001) != 0x1000) {
printf(" OEM MODE\n");
eeprom_write16(0x8C, (value & 0x9FFE) | 0x1000);
}
/*
writing SKU ID - 'MoW' signature
*/
if (eeprom_read16(0x158) != 0x6f4d) eeprom_write16(0x158, 0x6f4d);
if (eeprom_read16(0x15A) != 0x0057) eeprom_write16(0x15A, 0x0057);
printf("-> Checking and adding channels...\n");
// reading regulatory offset
reg_offs = 2 * eeprom_read16(0xCC);
printf("Regulatory base: %04x\n", reg_offs);
/*
writing channels regulatory...
*/
for (idx=0; regulatory[idx].addr; idx++) {
if (eeprom_read16(reg_offs + regulatory[idx].addr) != regulatory[idx].data) {
printf(" %d%s\n", regulatory[idx].chn & ~HT40, (regulatory[idx].chn & HT40) ? " (HT40)" : "");
eeprom_write16(reg_offs + regulatory[idx].addr, regulatory[idx].data);
}
}
eeprom_unlock();
printf("\nCard EEPROM patched successfully\n");
}
void die( const char* format, ... ) {
va_list args;
fprintf(stderr, "\n\E[31;60m");
va_start( args, format );
vfprintf( stderr, format, args );
va_end( args );
fprintf(stderr, "\E[0m");
release_card();
exit(1);
}
unsigned int read_id(const char *device, const char* param)
{
FILE *f;
unsigned int id;
char path[512];
sprintf(path, DEVICES_PATH "/%s/%s", device, param);
if (!(f = fopen(path, "r")))
return 0;
fscanf(f,"%x", &id);
fclose(f);
return id;
}
void check_device(struct pcidev_id *id)
{
int i;
id->idx = -1;
id->class = (read_id(id->device,"class") >> 8);
if (!id->class) {
printf("No such PCI device: %s\n", id->device);
}
id->ven = read_id(id->device,"vendor");
id->dev = read_id(id->device,"device");
id->sven = read_id(id->device,"subsystem_vendor");
id->sdev = read_id(id->device,"subsystem_device");
for(i=0; id->idx<0 && valid_ids[i].ven; i++)
if(id->ven==valid_ids[i].ven && id->dev==valid_ids[i].dev)
id->idx = i;
}
void list_supported()
{
int i;
printf("Known devices:\n");
for(i=0; valid_ids[i].ven; i++)
printf(" %04x:%04x [%s] %s \n",
valid_ids[i].ven,
valid_ids[i].dev,
valid_ids[i].writable ? "RW" : "RO",
valid_ids[i].name);
}
void map_device()
{
FILE *f;
char path[512];
unsigned char data[64];
int i;
unsigned int addr;
sprintf(path, DEVICES_PATH "/%s/%s", dev.device, "config");
if (!(f = fopen(path, "r")))
return;
fread(data, 64, 1, f);
fclose(f);
for (i=0x10; !offset && i<0x28;i+=4) {
addr = ((unsigned int*)data)[i/4];
if ((addr & 0xF) == 4)
offset = addr & 0xFFFFFFF0;
}
}
void search_card()
{
DIR *dir;
struct dirent *dentry;
struct pcidev_id id;
struct pcidev_id *ids = NULL;
int i,cnt=0;
dir = opendir(DEVICES_PATH);
if (!dir)
die("Can't list PCI devices\n");
if (debug)
printf("PCI devices:\n");
id.device = (char*) malloc(256 * sizeof(char));
do {
dentry = readdir(dir);
if (!dentry || !strncmp(dentry->d_name, ".", 1))
continue;
strcpy(id.device, dentry->d_name);
check_device(&id);
if (debug) {
printf(" %s: class %04x id %04x:%04x subid %04x:%04x",
id.device,
id.class,
id.ven, id.dev,
id.sven, id.sdev
);
if (id.idx < 0)
printf("\n");
else
printf(" [%s] %s \n",
valid_ids[id.idx].writable ? "RW" : "RO",
valid_ids[id.idx].name);
}
if (id.idx >=0 ) {
if(!cnt)
ids = (struct pcidev_id*) malloc(sizeof(id));
else
ids = (struct pcidev_id*) realloc(ids, (cnt+1)*sizeof(id));
ids[cnt].device = (char*) malloc(256 * sizeof(char));
ids[cnt].class = id.class;
ids[cnt].ven = id.ven; ids[cnt].sven = id.sven;
ids[cnt].dev = id.dev; ids[cnt].sdev = id.sdev;
ids[cnt].idx = id.idx;
memcpy(ids[cnt].device, id.device, 256);
cnt++;
}
}
while (dentry);
printf("Supported devices detected: %s\n", cnt ? "" : "\n NONE");
if (!cnt) goto nodev;
for (i=0; i<cnt; i++) {
printf(" [%d] %s [%s] %s (%04x:%04x, %04x:%04x)\n", i+1,
ids[i].device,
valid_ids[ids[i].idx].writable ? "RW" : "RO",
valid_ids[ids[i].idx].name,
ids[i].ven, ids[i].dev,
ids[i].sven, ids[i].sdev);
}
i++;
while(i<=0 || i>cnt) {
if (!i) goto out;
printf("Select device [1-%d] (or 0 to quit): ", cnt);
scanf("%d", &i);
}
i--;
dev.device = (char*) malloc(256 * sizeof(char));
memcpy(dev.device, ids[i].device, 256);
out:
free(id.device);
for (i=0; i<cnt; i++) free(ids[i].device);
free(ids);
return;
nodev:
free(id.device);
exit(1);
}
int main(int argc, char** argv)
{
char c;
dev.device = NULL;
dump_order = order_le;
getresuid(&ruid, &euid, &suid);
while (1) {
c = getopt_long(argc, argv, "rwld:mcni:o:bhpasID:", long_options, NULL);
if (c == -1)
break;
switch(c) {
case 'l':
list_supported();
exit(0);
case 'd':
dev.device = optarg;
break;
case 'n':
nodev = true;
break;
case 'm':
preserve_mac = true;
break;
case 'c':
preserve_calib = true;
break;
case 'r':
die("option -r deprecated. use -o instead\n");
break;
case 'o':
ofname = optarg;
break;
case 'w':
die("option -w deprecated. use -i instead\n");
break;
case 'i':
ifname = optarg;
break;
case 'b':
dump_order = order_be;
break;
case 'p':
patch11n = true;
break;
case 'a':
all_channels = true;
break;
case 's':
show_regulatory = true;
break;
case 'I':
init_device = true;
break;
case 'D':
debug = atoi(optarg);
if (debug)
printf("debug level: %s\n", optarg);
break;
case 'h':
die("EEPROM reader/writer for intel wifi cards\n\n"
"Usage:\n"
"\t%s [-d device] [-r filename [-b]] [-w filename] [-p] [-D debug_level]\n"
"\t%s -l\n\n"
"Options:\n"
"\t-d <device> | --device <device>\t\t"
"device in format 0000:00:00.0 (domain:bus:dev.func)\n"
"\t-n | --nodev\t"
"don't touch any device, file-only operations\n"
"\t-m | --preserve-mac\t"
"don't change card's MAC while writing full eeprom dump\n"
"\t-c | --preserve-calib\t"
"don't change calibration data while writing full eeprom dump\n"
"\t-o <filename> | --ofile <filename>\t"
"dump eeprom to binary file\n"
"\t-i <filename> | --ifile <filename>\t"
"write eeprom from binary file\n"
"\t-b | --bigendian\t\t\t"
"save dump in big-endian byteorder (default: little-endian)\n"
"\t-p | --patch11n\t\t\t\t"
"patch device eeprom to enable 802.11n\n"
"\t-a | --all-channels\t\t\t\t"
"patch device eeprom to enable all channels\n"
"\t-s | --show-regulatory\t\t\t\t"
"show regulatory eeprom data\n"
"\t-I | --init\t\t\t\t"
"init device (useful if driver didn't it)\n"
"\t-l | --list\t\t\t\t"
"list known cards\n"
"\t-D <level> | --debug <level>\t\t"
"set debug level (0-1, default 0)\n"
"\t-h | --help\t\t\t\t"
"show this info\n", argv[0], argv[0]);
default:
return 1;
}
}
if (nodev) goto _nodev;
if (!dev.device) search_card();
if (!dev.device) exit(1);
check_device(&dev);
if (!dev.class) exit(2);
if (dev.idx < 0)
die("Selected device not supported\n");
printf("Using device %s [%s] %s \n",
dev.device,
valid_ids[dev.idx].writable ? "RW" : "RO",
valid_ids[dev.idx].name);
map_device();
if (!offset)
die("Can't obtain memory address\n");
if (debug)
printf("address: %08x\n", offset);
if(!ifname && !ofname && !patch11n)
printf("No file names given or patch option selected!\nNo EEPROM actions will be performed, just write-enable test\n");
if(init_device)
initpower();
init_card();
if (show_regulatory)
eeprom_show_regulatory();
if (ofname)
eeprom_read(ofname);
if (ifname && valid_ids[dev.idx].writable)
eeprom_write(ifname);
if (patch11n && valid_ids[dev.idx].writable)
eeprom_patch11n();
if (all_channels)
eeprom_all_channels();
release_card();
return 0;
_nodev:
if (dev.device)
die("Don't use '-d' and '-n' options simultaneously\n");
printf("Device-less operation...\n");
if (!ifname || !ofname)
die("Have to specify both input and output files!\n");
init_dump(ifname);
if (patch11n)
eeprom_patch11n();
fixate_dump(ofname);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment