/* Program to set the CMOS MAC address on the SiS630e chipset. By Steve M. Gehlbach (steve@kesa.com), silly modifications made by David M. Wilson . Based on the work of SiS for the sis900.c driver in the 2.4.19 kernel. 1. Compile this program with "cc -o write_cmos write_cmos.c". 2. Type 'lspci -v' or 'cat /proc/pci' at the shell prompt, and scan for 'ISA bridge' in the list. If using lspci, note the numbers to the left of the line, eg. "04:01.0", these are your bus, device, and function numbers. If using cat, note the bus, device and function numbers given. 3. Run write_cmos, with the bus, device, and function number on the command line, followed by the MAC address bytes you would like to set the motherboard to. For example, if your ISA bridge is at address 04, 01, 0, and you want the motherboard to become 00:0A:E6:54:AB:01, your command line may look something like: root@node$ ./write_cmos 4 1 0 00 0a e6 54 ab 01 4. The program will prompt to confirm the MAC address to write (this is just a safety measure). Press the return key. 5. Verify the MAC address read back matches that which you specified on the command line. If they match, the modification should have been successful. Reboot your machine in order for the ethernet driver to pick up the new MAC address. 6. Grab a fresh cup of coffee. :-) Expected output (successful modification): [root@node13 projects]# ./write_cmos 0 2 0 00 0a e6 54 ab 01 MAC Address to write: 00:0a:e6:54:ab:01 Press to continue. Setting MAC... done. reading back MAC: 00 0a e6 54 ab 01 */ #include #include #include #include #include #include #include #include extern const char *const sys_errlist[]; #define CONFIG_CMD(bus,devfn, where) (0x80000000 | (bus << 16) | (devfn << 8) | (where & ~3)) #define u8 u_char #define u16 u_short #define u32 u_long #define PCI_DEVFN(slot,func) ((((slot) & 0x1f) << 3) | ((func) & 0x07)) #define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f) #define PCI_FUNC(devfn) ((devfn) & 0x07) static int pci_conf1_read_config_word(unsigned char bus, int devfn, int where, u16 * value) { outl(CONFIG_CMD(bus, devfn, where), 0xCF8); *value = inw(0xCFC + (where & 2)); return 0; } static int pci_conf1_write_config_byte(unsigned char bus, int devfn, int where, u8 value) { outl(CONFIG_CMD(bus, devfn, where), 0xCF8); outb(value, 0xCFC + (where & 3)); return 0; } static int pci_conf1_read_config_byte(unsigned char bus, int devfn, int where, u8 * value) { outl(CONFIG_CMD(bus, devfn, where), 0xCF8); *value = inb(0xCFC + (where & 3)); return 0; } static int pci_conf1_write_config_word(unsigned char bus, int devfn, int where, u16 value) { outl(CONFIG_CMD(bus, devfn, where), 0xCF8); outw(value, 0xCFC + (where & 2)); return 0; } int main (int argc, char **argv) { u_char v1,reg; u8 mac_set[6] = {0x00,0x0a,0xe6,0x54,0xac,0xb7}; u8 mac[6]; char junkbuf[2]; u_short port; int i, bus, devfn; if (iopl(3) < 0 ) { perror("iopl"); printf("%s: You must run this program as root!\n",argv[0]); return 1; } if (argc < 10) { fprintf(stderr, "Please specify ISA bridge address and MAC bytes.\n" "eg.: %s 00 0A E6 AA BB CC\n", argv[0] ); return 1; } bus = atoi(argv[1]); devfn = PCI_DEVFN(atoi(argv[2]), atoi(argv[3])); mac_set[0] = strtoul(argv[4], NULL, 16); mac_set[1] = strtoul(argv[5], NULL, 16); mac_set[2] = strtoul(argv[6], NULL, 16); mac_set[3] = strtoul(argv[7], NULL, 16); mac_set[4] = strtoul(argv[8], NULL, 16); mac_set[5] = strtoul(argv[9], NULL, 16); printf( "MAC Address to write: %02x:%02x:%02x:%02x:%02x:%02x\n" "Press to continue.", mac_set[0], mac_set[1], mac_set[2], mac_set[3], mac_set[4], mac_set[5] ); fgets(junkbuf, sizeof junkbuf, stdin); // map the APC registers into cmos pci_conf1_read_config_byte(bus, devfn, 0x48, ®); pci_conf1_write_config_byte(bus, devfn, 0x48, reg | 0x40); // mac address is at offset 0x9 // write it there printf("Setting MAC... "); for (i = 0; i < 6; i++) { outb(0x09 + i, 0x70); outb(mac_set[i],0x71); } printf("done.\n"); // now read it back to confirm printf("reading back MAC: "); for (i = 0; i < 6; i++) { outb(0x09 + i, 0x70); mac[i] = inb(0x71); printf("%02x ",mac[i]); } printf("\n"); // restore the cmos mapping to normal pci_conf1_write_config_byte(bus, devfn, 0x48, reg & ~0x40); }