📄 sym_nvram.c
字号:
/* this is to set NVRAM into a known state with GPIO0/1 both low */ gpreg = old_gpreg; S24C16_set_bit(np, 0, &gpreg, CLR_CLK); S24C16_set_bit(np, 0, &gpreg, CLR_BIT); /* now set NVRAM inactive with GPIO0/1 both high */ S24C16_stop(np, &gpreg); /* NVRAM has to be written in segments of 16 bytes */ for (x = 0; x < len ; x += 16) { do { S24C16_start(np, &gpreg); S24C16_write_byte(np, &ack_data, 0xa0 | (((offset+x) >> 7) & 0x0e), &gpreg, &gpcntl); } while (ack_data & 0x01); S24C16_write_byte(np, &ack_data, (offset+x) & 0xff, &gpreg, &gpcntl); for (y = 0; y < 16; y++) S24C16_write_byte(np, &ack_data, data[x+y], &gpreg, &gpcntl); S24C16_stop(np, &gpreg); } /* return GPIO0/1 to original states after having accessed NVRAM */ OUTB(np, nc_gpcntl, old_gpcntl); OUTB(np, nc_gpreg, old_gpreg); return 0;}#endif /* SYM_CONF_NVRAM_WRITE_SUPPORT *//* * Read 'len' bytes starting at 'offset'. */static int sym_read_S24C16_nvram(struct sym_device *np, int offset, u_char *data, int len){ u_char gpcntl, gpreg; u_char old_gpcntl, old_gpreg; u_char ack_data; int retv = 1; int x; /* save current state of GPCNTL and GPREG */ old_gpreg = INB(np, nc_gpreg); old_gpcntl = INB(np, nc_gpcntl); gpcntl = old_gpcntl & 0x1c; /* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */ OUTB(np, nc_gpreg, old_gpreg); OUTB(np, nc_gpcntl, gpcntl); /* this is to set NVRAM into a known state with GPIO0/1 both low */ gpreg = old_gpreg; S24C16_set_bit(np, 0, &gpreg, CLR_CLK); S24C16_set_bit(np, 0, &gpreg, CLR_BIT); /* now set NVRAM inactive with GPIO0/1 both high */ S24C16_stop(np, &gpreg); /* activate NVRAM */ S24C16_start(np, &gpreg); /* write device code and random address MSB */ S24C16_write_byte(np, &ack_data, 0xa0 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl); if (ack_data & 0x01) goto out; /* write random address LSB */ S24C16_write_byte(np, &ack_data, offset & 0xff, &gpreg, &gpcntl); if (ack_data & 0x01) goto out; /* regenerate START state to set up for reading */ S24C16_start(np, &gpreg); /* rewrite device code and address MSB with read bit set (lsb = 0x01) */ S24C16_write_byte(np, &ack_data, 0xa1 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl); if (ack_data & 0x01) goto out; /* now set up GPIO0 for inputting data */ gpcntl |= 0x01; OUTB(np, nc_gpcntl, gpcntl); /* input all requested data - only part of total NVRAM */ for (x = 0; x < len; x++) S24C16_read_byte(np, &data[x], (x == (len-1)), &gpreg, &gpcntl); /* finally put NVRAM back in inactive mode */ gpcntl &= 0xfe; OUTB(np, nc_gpcntl, gpcntl); S24C16_stop(np, &gpreg); retv = 0;out: /* return GPIO0/1 to original states after having accessed NVRAM */ OUTB(np, nc_gpcntl, old_gpcntl); OUTB(np, nc_gpreg, old_gpreg); return retv;}#undef SET_BIT#undef CLR_BIT#undef SET_CLK#undef CLR_CLK/* * Try reading Symbios NVRAM. * Return 0 if OK. */static int sym_read_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram){ static u_char Symbios_trailer[6] = {0xfe, 0xfe, 0, 0, 0, 0}; u_char *data = (u_char *) nvram; int len = sizeof(*nvram); u_short csum; int x; /* probe the 24c16 and read the SYMBIOS 24c16 area */ if (sym_read_S24C16_nvram (np, SYMBIOS_NVRAM_ADDRESS, data, len)) return 1; /* check valid NVRAM signature, verify byte count and checksum */ if (nvram->type != 0 || memcmp(nvram->trailer, Symbios_trailer, 6) || nvram->byte_count != len - 12) return 1; /* verify checksum */ for (x = 6, csum = 0; x < len - 6; x++) csum += data[x]; if (csum != nvram->checksum) return 1; return 0;}/* * 93C46 EEPROM reading. * * GPOI0 - data in * GPIO1 - data out * GPIO2 - clock * GPIO4 - chip select * * Used by Tekram. *//* * Pulse clock bit in GPIO0 */static void T93C46_Clk(struct sym_device *np, u_char *gpreg){ OUTB(np, nc_gpreg, *gpreg | 0x04); INB(np, nc_mbox1); udelay(2); OUTB(np, nc_gpreg, *gpreg);}/* * Read bit from NVRAM */static void T93C46_Read_Bit(struct sym_device *np, u_char *read_bit, u_char *gpreg){ udelay(2); T93C46_Clk(np, gpreg); *read_bit = INB(np, nc_gpreg);}/* * Write bit to GPIO0 */static void T93C46_Write_Bit(struct sym_device *np, u_char write_bit, u_char *gpreg){ if (write_bit & 0x01) *gpreg |= 0x02; else *gpreg &= 0xfd; *gpreg |= 0x10; OUTB(np, nc_gpreg, *gpreg); INB(np, nc_mbox1); udelay(2); T93C46_Clk(np, gpreg);}/* * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZZzzz!! */static void T93C46_Stop(struct sym_device *np, u_char *gpreg){ *gpreg &= 0xef; OUTB(np, nc_gpreg, *gpreg); INB(np, nc_mbox1); udelay(2); T93C46_Clk(np, gpreg);}/* * Send read command and address to NVRAM */static void T93C46_Send_Command(struct sym_device *np, u_short write_data, u_char *read_bit, u_char *gpreg){ int x; /* send 9 bits, start bit (1), command (2), address (6) */ for (x = 0; x < 9; x++) T93C46_Write_Bit(np, (u_char) (write_data >> (8 - x)), gpreg); *read_bit = INB(np, nc_gpreg);}/* * READ 2 bytes from the NVRAM */static void T93C46_Read_Word(struct sym_device *np, unsigned short *nvram_data, unsigned char *gpreg){ int x; u_char read_bit; *nvram_data = 0; for (x = 0; x < 16; x++) { T93C46_Read_Bit(np, &read_bit, gpreg); if (read_bit & 0x01) *nvram_data |= (0x01 << (15 - x)); else *nvram_data &= ~(0x01 << (15 - x)); }}/* * Read Tekram NvRAM data. */static int T93C46_Read_Data(struct sym_device *np, unsigned short *data, int len, unsigned char *gpreg){ int x; for (x = 0; x < len; x++) { unsigned char read_bit; /* output read command and address */ T93C46_Send_Command(np, 0x180 | x, &read_bit, gpreg); if (read_bit & 0x01) return 1; /* Bad */ T93C46_Read_Word(np, &data[x], gpreg); T93C46_Stop(np, gpreg); } return 0;}/* * Try reading 93C46 Tekram NVRAM. */static int sym_read_T93C46_nvram(struct sym_device *np, Tekram_nvram *nvram){ u_char gpcntl, gpreg; u_char old_gpcntl, old_gpreg; int retv = 1; /* save current state of GPCNTL and GPREG */ old_gpreg = INB(np, nc_gpreg); old_gpcntl = INB(np, nc_gpcntl); /* set up GPREG & GPCNTL to set GPIO0/1/2/4 in to known state, 0 in, 1/2/4 out */ gpreg = old_gpreg & 0xe9; OUTB(np, nc_gpreg, gpreg); gpcntl = (old_gpcntl & 0xe9) | 0x09; OUTB(np, nc_gpcntl, gpcntl); /* input all of NVRAM, 64 words */ retv = T93C46_Read_Data(np, (u_short *) nvram, sizeof(*nvram) / sizeof(short), &gpreg); /* return GPIO0/1/2/4 to original states after having accessed NVRAM */ OUTB(np, nc_gpcntl, old_gpcntl); OUTB(np, nc_gpreg, old_gpreg); return retv;}/* * Try reading Tekram NVRAM. * Return 0 if OK. */static int sym_read_Tekram_nvram (struct sym_device *np, Tekram_nvram *nvram){ u_char *data = (u_char *) nvram; int len = sizeof(*nvram); u_short csum; int x; switch (np->device_id) { case PCI_DEVICE_ID_NCR_53C885: case PCI_DEVICE_ID_NCR_53C895: case PCI_DEVICE_ID_NCR_53C896: x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS, data, len); break; case PCI_DEVICE_ID_NCR_53C875: x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS, data, len); if (!x) break; default: x = sym_read_T93C46_nvram(np, nvram); break; } if (x) return 1; /* verify checksum */ for (x = 0, csum = 0; x < len - 1; x += 2) csum += data[x] + (data[x+1] << 8); if (csum != 0x1234) return 1; return 0;}#ifdef CONFIG_PARISC/* * Host firmware (PDC) keeps a table for altering SCSI capabilities. * Many newer machines export one channel of 53c896 chip as SE, 50-pin HD. * Also used for Multi-initiator SCSI clusters to set the SCSI Initiator ID. */static int sym_read_parisc_pdc(struct sym_device *np, struct pdc_initiator *pdc){ struct hardware_path hwpath; get_pci_node_path(np->pdev, &hwpath); if (!pdc_get_initiator(&hwpath, pdc)) return 0; return SYM_PARISC_PDC;}#elsestatic inline int sym_read_parisc_pdc(struct sym_device *np, struct pdc_initiator *x){ return 0;}#endif/* * Try reading Symbios or Tekram NVRAM */int sym_read_nvram(struct sym_device *np, struct sym_nvram *nvp){ if (!sym_read_Symbios_nvram(np, &nvp->data.Symbios)) { nvp->type = SYM_SYMBIOS_NVRAM; sym_display_Symbios_nvram(np, &nvp->data.Symbios); } else if (!sym_read_Tekram_nvram(np, &nvp->data.Tekram)) { nvp->type = SYM_TEKRAM_NVRAM; sym_display_Tekram_nvram(np, &nvp->data.Tekram); } else { nvp->type = sym_read_parisc_pdc(np, &nvp->data.parisc); } return nvp->type;}char *sym_nvram_type(struct sym_nvram *nvp){ switch (nvp->type) { case SYM_SYMBIOS_NVRAM: return "Symbios NVRAM"; case SYM_TEKRAM_NVRAM: return "Tekram NVRAM"; case SYM_PARISC_PDC: return "PA-RISC Firmware"; default: return "No NVRAM"; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -