⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 programming.c

📁 Linux下操作Bios的驱动
💻 C
字号:
/* * BIOS/Flashrom driver for Linux * * Copyright (C) 1998-2002 Stefan Reinauer <stepan@suse.de> * */// <-- C++ style comments are for experimental comments only.// They will disappear as soon as I fixed all the stuff.#include <linux/config.h>#include <linux/pci.h>#include <linux/errno.h>#include <linux/types.h>#include <linux/vmalloc.h>#include <linux/delay.h>#include <linux/spinlock.h>#include <asm/io.h>#include <asm/delay.h>#include <asm/uaccess.h>#include "bios.h"#include "pcisets.h"#include "flashchips.h"#include "programming.h"#define OLD_ACTIVATEstruct flashdevice flashdevices[BIOS_MAXDEV];int flashcount;/* * ****************************************** * *	flashchip handling * * ******************************************  */void flash_command (unsigned char command)#if 1{	flash_writeb(0x5555, 0xaa);	flash_writeb(0x2AAA, 0x55);	flash_writeb(0x5555, command);}void fwh_flash_command(unsigned char command)#endif{	flash_writeb(0x75555, 0xaa);	flash_writeb(0x72aaa, 0x55);	flash_writeb(0x75555, command);}int system_activate(int cmd, void *data){	switch (cmd) {	    case 0: /* deactivate */#if defined(__i386__) || defined(__ia64__) || defined(__alpha__)		pci_functions[chipset].deactivate();#endif		break;#if defined(__i386__) || defined(__ia64__) || defined(__alpha__)	    case 1: /* activate */		pci_functions[chipset].activate();#endif		break;	}	return 0;}int pci_activate(int cmd, void *data){#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,99)	struct pci_dev *dev=(struct pci_dev *)data;	static u32 status=0;		// This function does not allow parallel access	// to the flash chips. must use 'atomic' operations.		switch (cmd) {	    case 0:		pci_write_config_dword (dev, dev->rom_base_reg, status);		break;	    case 1:		pci_read_config_dword(dev, dev->rom_base_reg, &status);		if (status)			pci_write_config_dword (dev, dev->rom_base_reg, 	    			           status|PCI_ROM_ADDRESS_ENABLE);		else			return 1;	}#endif	return 0;}int flash_probe_address(void *address, int (*activate)(int, void *),    				void *data){	int flashnum=0, manufnum=0, sectors=0;	unsigned short flash_id, testflash;	unsigned long flags;#ifdef DEBUG_PROBING	printk( KERN_DEBUG "BIOS: Probing for flash chip @0x%08lx\n", (unsigned long) address);#endif#if defined(__alpha__)	outb(0x00, 0x800);#endif	// currently all flash chip functions rely on bios pointing to the	// current flash chip.		bios=address;	// We should get rid of this! 	save_flags(flags);	spin_lock_irqsave(&bios_lock, flags);#ifdef OLD_ACTIVATE		if (activate(1,data)) {		spin_unlock_irqrestore(&bios_lock, flags);	  	return 0;	}#endif	testflash= (flash_readb(0))+(flash_readb(1)<<8);	/* 1st method: Intel, Atmel listen to this.. */	flash_command(0x90);	udelay(20);	flash_id = (flash_readb(0))+(flash_readb(1)<<8);#ifdef DEBUG_PROBING	printk (KERN_DEBUG "BIOS: testflash[%04x] flash_id[%04x]\n",		testflash, flash_id); #endif			/* 2nd method: Winbond (I think this is Jedec standard) */	if (flash_id==testflash) {#ifdef DEBUG_PROBING		printk (KERN_DEBUG "BIOS: Trying 2nd ID method.\n"); #endif		flash_command(0xf0); /* Reset */		udelay(20);		flash_command(0x80);		flash_command(0x60);		udelay(20);		flash_id = (flash_readb(0))+(flash_readb(1)<<8);#ifdef DEBUG_PROBING	printk (KERN_DEBUG "BIOS: testflash[%04x] flash_id[%04x]\n",		testflash, flash_id); #endif	}	/* 3rd Method: Some Winbonds seem to want this */	if (flash_id==testflash) {#ifdef DEBUG_PROBING		printk (KERN_DEBUG "BIOS: Trying 3rd ID method.\n"); #endif		flash_command(0xf0); /* Reset again */		udelay(20);		flash_command(0x80);		flash_command(0x20);		udelay(20);		flash_id = (flash_readb(0))+(flash_readb(1)<<8);#ifdef DEBUG_PROBING	printk (KERN_DEBUG "BIOS: testflash[%04x] flash_id[%04x]\n",		testflash, flash_id); #endif	}	flash_command(0xf0);	udelay(20);#ifdef OLD_ACTIVATE	activate(0,data);#endif	spin_unlock_irqrestore(&bios_lock, flags);	if (flash_id==testflash) return 0; /* Nothing found :-( */	while (flashchips[flashnum].id!=0) {		if (flash_id==flashchips[flashnum].id) break;		flashnum++;	}	while (manufacturers[manufnum++].id!=0)		if ((flash_id&0xff)==manufacturers[manufnum].id) break;		if (flashchips[flashnum].id) {		while (flashchips[flashnum].sectors[sectors]<flashchips[flashnum].size)			sectors++;	}	if (flashcount >= BIOS_MAXDEV) /* Too many flashchips. Wow! */		return -1;	flashdevices[flashcount] = (struct flashdevice){		flashnum:	flashnum,		manufnum:	manufnum,		id:		flash_id,		size:		(flashchips[flashnum].size<<10),		sectors:	sectors,		open_mode:	0,		open_cnt:	0,		activate:	activate,		data:		data	};	flashcount++;	return 1;}void flash_probe(void){#ifdef CONFIG_PCI	struct pci_dev *dev;#endif	unsigned char *mapped;	unsigned long romaddr, romsize;	unsigned long probeaddr;#if defined (__i386__) || defined(__ia64__) || defined(__alpha__)#ifndef __alpha__        romaddr=0xffe00000;        romsize=2048*1024;#else	romaddr=0xfffffffffffc0000;	//romaddr=0xfffc0000;	romsize=512*1024;#endif		/* ioremap the whole bios area. Same on some alphas. */	mapped=ioremap(romaddr,romsize);	/* probe system bios area in steps of 4k. 	 * When a flash chip is found, the probing	 * skips the chip's address space to prevent	 * multiple detection.	 * Stop probing after romsize - 0x5555 bytes, as	 * probing for the chip itself requires at least	 * a flash chip size of 0x5555 bytes.	 */		probeaddr=(unsigned long)mapped;	do {		if ( flash_probe_address ((void *)probeaddr, 		      &(system_activate), NULL) == 1 ) {			flashdevices[flashcount-1].offset = 				(unsigned long)probeaddr-(unsigned long)mapped;			flashdevices[flashcount-1].mapped = mapped;			flashdevices[flashcount-1].physical = (unsigned char *)				romaddr+flashdevices[flashcount-1].offset;						printk ( KERN_INFO "BIOS: %dk flashchip (ID 0x%04x) found at "				"physical address 0x%08lx (va=0x%08lx+0x%lx).\n", 				flashdevices[flashcount-1].size>>10, 				flashdevices[flashcount-1].id,				(unsigned long)flashdevices[flashcount-1].physical,				(unsigned long)mapped, 				flashdevices[flashcount-1].offset				);			if (flashchips[flashdevices[flashcount-1].flashnum].flags&f_fwh_compl) {				unsigned long t_lk;				unsigned int i=7;				printk(KERN_INFO "BIOS: FWH compliant chip detected.\n");				for (t_lk=0xffb80002; t_lk<=0xffbf0002; t_lk+=0x10000) {					printk(KERN_INFO "Lock register %d (0x%08lx): 0x%x\n",						i, t_lk, (unsigned int)						(readb(phys_to_virt(t_lk))));					i--;				}			}#if MULTIPLE_SYSTEM_FLASH			/* we probably only have one system flash			 * chip, so we rather bail out here than			 * doing weird stuff.			 */			probeaddr += flashdevices[flashcount-1].size;#else			break;#endif		} else			probeaddr += 4*1024;	} while ( probeaddr < (unsigned long)mapped + romsize - 0x5555 );	// #elif defined (__alpha__)// Alpha uses normal pc stile mapping right now#if 0	flash_probe_address((void *)0xFFF80000,	    			&(system_activate), NULL);#endif#endif#ifdef CONFIG_PCI#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,99)	for(dev=pci_devices; dev; dev=dev->next) {		if (dev->rom_address)			flash_probe_address((void *)(dev->rom_address&(~1)),						&(pci_activate), (void *)dev);	}#else	pci_for_each_dev(dev) {		romaddr=dev->resource[PCI_ROM_RESOURCE].start;		romsize=dev->resource[PCI_ROM_RESOURCE].end - romaddr + 1;		if (romaddr) {		  	printk (KERN_DEBUG "BIOS: Probing PCI device "			    	  "with %ldk rom\n", (romsize>>10));			mapped=ioremap(romaddr,romsize);					probeaddr=(unsigned long)mapped;						do {				if ( flash_probe_address ((void *)probeaddr,					&(pci_activate), (void *)dev) == 1 ) {				  flashdevices[flashcount-1].mapped = mapped;				  flashdevices[flashcount-1].offset =					(unsigned long)probeaddr-(unsigned long)mapped;				  flashdevices[flashcount-1].physical =					  (unsigned char *)romaddr +					  flashdevices[flashcount-1].offset;#if MULTIPLE_SYSTEM_FLASH				  probeaddr += flashdevices[flashcount-1].size;#else				  break;#endif				} else				  probeaddr += 4*1024;			} while (probeaddr < (unsigned long) mapped + romsize - 0x5555);						/* If we did not find a single flash chip in the PCI			 * cards rom area, we unmap again 			 */			if (flashdevices[flashcount-1].mapped!=mapped)				iounmap(mapped);		}	}#endif#endif}void flash_program (void){	flash_command(0xa0);}void flash_program_atmel (void){	flash_command(0x80);	flash_command(0x20);}int flash_erase (unsigned int flashnum) {// Should we drop this function? I hope no one would build a flashchip // that has to be erased completely before programming.     /* but if data matches size of chip, whole chip erase is faster than     sector erase, so might as well make it available */	flash_command(0x80);	flash_command(0x10);	udelay(80);	return flash_ready_poll(0,0xff);}int flash_erase_sectors (unsigned int flashnum, unsigned int startsec, unsigned int endsec) {	unsigned int sector;  	if (!(flashchips[flashnum].flags & f_slow_sector_erase)) {		flash_command(0x80);		if (!flashchips[flashnum].flags&f_fwh_compl) {			flash_writeb(0x5555,0xaa);			flash_writeb(0x2aaa,0x55);		} else {			flash_writeb(0x75555,0xaa);			flash_writeb(0x72aaa,0x55);		}    		for (sector=startsec; sector <= endsec; sector++) {			flash_writeb (flashchips[flashnum].sectors[sector]*1024, 0x30);		}    		udelay(150); // 80 max normally, wait 150usec to be sure		// Why do we use sector-1 here?  		if (!flashchips[flashnum].flags&f_fwh_compl)			return flash_ready_poll(flashchips[flashnum].sectors[sector-1]*1024, 0xff);		else			return flash_ready_toggle(flashchips[flashnum].sectors[sector]*1024);	}  	/* sectors must be sent the sector erase command for every sector */	for (sector=startsec; sector <= endsec; sector++) {		flash_command(0x80);		if (!flashchips[flashnum].flags&f_fwh_compl) {			flash_writeb(0x5555,0xaa);			flash_writeb(0x2aaa,0x55);		} else {			flash_writeb(0x75555,0xaa);			flash_writeb(0x72aaa,0x55);		}    		flash_writeb(flashchips[flashnum].sectors[sector]*1024, 0x30);		udelay(150);		if (!flashchips[flashnum].flags&f_fwh_compl)			flash_ready_poll(flashchips[flashnum].sectors[sector]*1024, 0xff);		else			 flash_ready_toggle(flashchips[flashnum].sectors[sector]*1024);	}	return 0;}/* waiting for the end of programming/erasure by using the toggle method. * As long as there is a programming procedure going on, bit 6 of the last * written byte is toggling it's state with each consecutive read.  * The toggling stops as soon as the procedure is completed. * This function returns 0 if everything is ok, 1 if an error occured * while programming was in progress. */ int flash_ready_toggle (unsigned int offset){	unsigned long int timeout=0;	unsigned char oldflag, flag;	int loop=1;	oldflag=flash_readb(offset) & 0x40;	while (loop && (timeout<0x7fffffff)) {		flag=flash_readb(offset) & 0x40;		if (flag == oldflag)			loop=0;				oldflag=flag;		timeout++;	}	if (loop) {		printk(KERN_DEBUG "BIOS: operation timed out (Toggle)\n");		return 1;	}		return 0;}/* This functions is similar to the above one. While a programming * procedure is going on, bit 7 of the last written data byte is * inverted. When the procedure is completed, bit 7 contains the * correct data value */int flash_ready_poll (unsigned int offset, unsigned char data){	unsigned long int timeout=0;	unsigned char flag;	flag=flash_readb(offset);	while ( ( flag & 0x80) != ( data & 0x80)) {		if ( ( flag & 0x80 ) == ( data & 0x80 ) ) {#ifdef DBGTIMEOUT			printk(KERN_DEBUG "BIOS: Timeout value (EOT Polling) %ld\n",timeout);#endif			return 0;		}					flag=flash_readb(offset);		if (timeout++>12800) {	// 10 times more than usual.			printk(KERN_ERR "BIOS: EOT Polling timed out at 0x%08x."				" Try again or increase max. timeout.\n",offset);			return 1;		}		if ((flag & 0x80) == ( data & 0x80)) {		  flag=flash_readb(offset);		}	}#ifdef DBGTIMEOUT	printk(KERN_DEBUG "BIOS: Timeout value (EOT Polling) %ld\n",timeout);#endif	flag=flash_readb(offset);	if ( ( flag & 0x80 ) == ( data & 0x80 ) ) return 0; else return 1;}void iflash_program_byte  (unsigned int offset, unsigned char data){	unsigned long int timeout=0;	unsigned char flag;	flash_writeb (offset, 0x40);	flash_writeb (offset, data);	flash_writeb (offset, 0x70);	/* Read Status */	do {		flag=flash_readb (offset);		if (timeout++>100) { // usually 2 or 3 :-)			printk(KERN_ERR "BIOS: Intel programming timed out at"				"0x%08x. Try again or increase max. timeout.\n",offset);			return;		}	} while ((flag&0x80) != 0x80);#ifdef DBGTIMEOUT	printk (KERN_DEBUG"BIOS: Timeout value (Intel byte program) %ld\n",timeout);#endif	if (flag&0x18) {		flash_writeb (offset, 0x50);	/* Reset Status Register */		printk (KERN_ERR "BIOS: Error occured, please repeat write operation. (intel)\n");	}	flash_writeb (offset, 0xff);}int  iflash_erase_sectors (unsigned int flashnum, unsigned int startsec, unsigned int endsec){	unsigned long int timeout;	unsigned int sector, offset=0;	unsigned char flag;	for (sector=startsec; sector<=endsec; sector++) {		offset=(flashchips[flashnum].sectors[sector]*1024);		flash_writeb (offset, 0x20);		flash_writeb (offset, 0xd0);		flash_writeb (offset, 0x70);	/* Read Status */		timeout=0;		do {			flag=flash_readb (offset);			if (timeout++>1440000) { // usually 144000				printk(KERN_ERR "BIOS: Intel sector erase timed out at 0x%08x. Try again or increase max. timeout.\n",offset);				return 1;			}		} while ((flag&0x80) != 0x80);#ifdef DBGTIMEOUT		printk (KERN_DEBUG "BIOS: Timeout value (Intel sector erase) %ld\n",timeout);#endif		if (flag&0x28) {			flash_writeb (offset, 0x50);			flash_writeb (offset, 0xff);			return 1; /* Error! */		}	}	flash_writeb (offset, 0xff);	return 0;	}unsigned char flash_readb(unsigned int offset){#if defined(__alpha__)	if (offset<0x80000)		outb(0x00,0x800);	else {		outb(0x01, 0x800);		offset-=0x80000;	}#endif		return readb(bios+offset);}void flash_writeb(unsigned int offset, unsigned char data) {#if defined(__alpha__)	if (offset<0x80000)		outb(0x00,0x800);	else {		outb(0x01, 0x800);		offset-=0x80000;	}#endif		writeb(data,bios+offset);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -