📄 gmv1rom.c
字号:
/* $Id: gmv1rom.c,v 1.2 2000/11/15 17:44:54 apc Exp $ *//* Copyright 2000 AG Electronics Ltd. *//* This code is distributed without warranty under the GPL v2 (see COPYING) */#include <stdio.h>#include <io.h>#include <pci.h>#define HW_ROM 0x00 /* IEEE Address PROM */#define HW_RDP 0x10 /* Register data port */#define HW_RAP 0x12 /* Register/ISA address port */#define HW_RESET 0x14 /* Reset register */#define HW_BDP 0x16 /* ISA data register */static ioaddr lance_port; /* I/O port of the card */enum eeprom_consts{ eeprom_sk = 0x0002, eeprom_cs = 0x0004, eeprom_di = 0x0001, eeprom_do = 0x0001, eeprom_een = 0x0010, eeprom_present = 0x2000,};typedef u16 WORD;static WORD read_reg (void){ return in_16 (lance_port + HW_BDP);}/* * pause for at least (delay * 100ns). The implementation depends on the * fact that PCI bus reads take 3 PCI clocks (approx = 100ns). The actual * delay is likely to be much longer than the requested delay, but will be * software independent */static void pause (unsigned delay){ volatile WORD junk; unsigned i; for (i = 0; i < 4*delay; i += 1) { junk = in_16(lance_port + HW_RAP); out_16(lance_port + HW_RAP, junk); }}static void write_bit (u16 mask, u32 data, unsigned delay){ static u16 reg = eeprom_een; if (data) reg |= mask; else reg &= ~mask; out_16 (lance_port + HW_BDP, reg); pause ( delay);}static int read_bit (u16 mask){ u16 reg = read_reg () & mask; if (reg) return 1; else return 0;}static void write_sk (unsigned data, unsigned delay){ write_bit ( eeprom_sk, data, delay);}static void write_cs (unsigned data, unsigned delay){ write_bit ( eeprom_cs, data, delay);}static void write_di ( unsigned data, unsigned delay){ write_bit ( eeprom_di, data, delay);}static unsigned read_do (void){ return read_bit (eeprom_do);}static void write_instruction (u32 data, unsigned nbits){ u32 rd_mask = 0x1 << (nbits - 1); unsigned i; for (i = 0; i < nbits; i += 1) { write_di (data & rd_mask, 1); data <<= 1; write_sk (1, 10); /* ensure max freq < 500KHz */ write_sk (0, 10); }}u16 serprom_read (u16 addr){ u32 instr = 0x180 | (addr & 0x3f); u16 res = 0; unsigned i; write_sk (0, 1); write_cs (1, 1); write_instruction (instr, 9); for (i = 0; i < 16; i += 1) { write_sk (1, 10); /* tPD0/1 = 500ns */ res <<= 1; res |= read_do (); write_sk ( 0, 10); } write_cs ( 0, 5); return res;}static int serprom_write (u16 addr, u16 data){ u32 wr_instr = ((0x140 | (addr & 0x3f)) << 16) | data; unsigned timeout = 0; u16 word; write_sk ( 0, 1); write_cs ( 1, 1); /* prepare */ write_instruction ( 0x130, 9); /* WEN */ write_cs ( 0, 5); /* pulse CS off */ write_cs ( 1, 1); write_instruction ( wr_instr, 25); /* WRITE */ write_cs ( 0, 5); /* pulse CS off */ write_cs ( 1, 5); /* tSV */ if (read_do () == 1) printf ("Suspiciously short EEPROM program time\n"); while (read_do () == 0) /* BUSY */ if (++timeout > 100000) { write_cs ( 0, 5); printf ("Timeout waiting for EEPROM to program\n"); return -1; } else pause ( 10); /* 1 usec */ write_instruction ( 0x100, 9); /* WDS */ write_cs ( 0, 5); /* * // validate */ { word = serprom_read ( addr); if (word != data) printf ("EEPROM write validation: exp:0x%x got:0x%x\n", data, word); } return 0;}static unsigned char pcnet_eeprom[] = { 0x02, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, /* NODE address */ 0, 0, /* ON Now */ 0x00, 0x11, /* Hardware ID */ 0, 0, 0, 0, /* Checksum */ 'W', 'W', 0x02, 0x00, /* BCR2, Misc. Config. */ 0xc0, 0x00, /* BCR4, LED0 */ 0x84, 0x00, /* BCR5, LED1 */ 0x80, 0x10, /* BCR6, LED2 */ 0x90, 0x00, /* BCR7, LED3 */ 0x00, 0x00, /* BCR9, Full-Duplex Ctrl. */ 0x60, 0x28, /* BCR18, Burst and Bus Ctrl. */ 0x06, 0xff, /* BCR22, PCI Latency */ 0xcb, 0x15, /* BCR23, Subsys vendor */ 0x00, 0x00, /* BCR24, Subsys ID */ 0x17, 0x00, /* BCR25, SRAM size */ 0x0c, 0x00, /* BCR26, SRAM boundary */ 0x00, 0x00, /* BCR27, SRAM cntrl */ 0x20, 0x01, /* BCR32, MII cntrl */ 0xc0, 0x03, /* BCR33, MII addr */ 0x22, 0x10, /* BCR35, vendor */ 0x11, 0xc8, /* BCR36, power management */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* BCR37-40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* BCR41-44 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* BCR48-51 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* BCR52-54 */ 0x00, 0x00 /* Checksum */};static void make_pcnet_checksums(void){ int i; unsigned short wsum; unsigned char bsum; wsum = 0; for(i = 0; i < 0xc; i++) wsum += pcnet_eeprom[i]; wsum += pcnet_eeprom[0xe] + pcnet_eeprom[0xf]; pcnet_eeprom[0xc] = wsum & 0xff; pcnet_eeprom[0xd] = wsum >> 8; bsum = 0; for(i = 0; i < 81; i++) bsum += pcnet_eeprom[i]; pcnet_eeprom[0x51] = 0xff - bsum;}#define PCI_AMD_VENDOR_ID 0x1022 /* AMD's vendor ID */#define PCI_LANCE_DEVICE_ID 0x2000 /* Am79C970 device ID */unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base);void gmv1_program (int argc, char **argv){ int i; struct pci_device *dev; char *mac_string; dev = pci_find_device (PCI_AMD_VENDOR_ID, PCI_LANCE_DEVICE_ID, 0); if (! dev) { printf("PCNET32 not found\n"); return -1; } lance_port = dev->region[0]; if (argc != 1) { printf("usage: test gmv1rom xx:xx:xx:xx:xx:xx\n"); return; } mac_string = argv[0]; printf("MAC address: "); for(i = 0; i < 6; i++) { char *next; unsigned long byte; if (*mac_string==':') mac_string++; if (! (*mac_string)) { printf(" MAC address too short\n"); return; } byte = simple_strtoul(mac_string, &next, 16); if (byte > 255) { printf(" Illegal MAC address: \"%s\"\n", mac_string); return; } pcnet_eeprom[i] = byte; if (i != 0) printf(":"); printf("%02x", byte); mac_string = next; } printf("\n"); /* Set up to access BCR19 (EEPROM) */ out_16(lance_port + HW_RAP, 19); if ((read_reg () & eeprom_present) != eeprom_present) { printf ("PCnet32 reports EEPROM not present\n"); return -1; } make_pcnet_checksums(); write_sk(0, 0); for(i = 0; i < 0x52; i += 2) { u16 data = pcnet_eeprom[i] | (pcnet_eeprom[i+1] << 8); if (serprom_read(i / 2) != data) serprom_write(i / 2, data); } out_16 (lance_port + HW_BDP, 0); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -