diff options
Diffstat (limited to 'qemu/roms/openbios/utils/devbios/filesystem.c')
-rw-r--r-- | qemu/roms/openbios/utils/devbios/filesystem.c | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/qemu/roms/openbios/utils/devbios/filesystem.c b/qemu/roms/openbios/utils/devbios/filesystem.c new file mode 100644 index 000000000..0dab71128 --- /dev/null +++ b/qemu/roms/openbios/utils/devbios/filesystem.c @@ -0,0 +1,300 @@ +/* + * OpenBIOS - free your system! + * ( firmware/flash device driver for Linux ) + * + * filesystem.c - vfs character device interface + * + * This program is part of a free implementation of the IEEE 1275-1994 + * Standard for Boot (Initialization Configuration) Firmware. + * + * Copyright (C) 1998-2004 Stefan Reinauer, <stepan@openbios.org> + * + * 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; version 2 of the License. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + * + */ + +#include <linux/config.h> +#include <linux/version.h> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) && defined(MODVERSIONS) +#include <linux/modversions.h> +#endif +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/types.h> +#include <linux/vmalloc.h> +#include <linux/fcntl.h> +#include <linux/delay.h> + +#include <asm/uaccess.h> + +#include "bios.h" +#include "flashchips.h" +#include "pcisets.h" +#include "programming.h" + +#ifdef MODULE +void inc_mod(void); +void dec_mod(void); +#endif + +/* + * ****************************************** + * + * /dev/bios filesystem operations + * + * ****************************************** + */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +#define FDEV (MINOR(file->f_dentry->d_inode->i_rdev)) +#else +#define FDEV (iminor(file->f_dentry->d_inode)) +#endif +#define CFLASH flashdevices[FDEV] +// #define BIOS_SIZE ((flashchips[CFLASH.flashnum].size)*1024) +#define BIOS_SIZE (CFLASH.size) + +static loff_t bios_llseek(struct file *file, loff_t offset, int origin ) +{ + currflash=FDEV; + switch(origin) { + case 0: + break; + case 1: + offset += file->f_pos; + break; + case 2: + offset += BIOS_SIZE; + break; + } + return((offset >= 0)?(file->f_pos = offset):-EINVAL); +} + +static ssize_t bios_read(struct file *file, char *buffer, size_t count, loff_t *ppos) +{ + signed int size=((BIOS_SIZE-*ppos>count) ? count : BIOS_SIZE-*ppos); + unsigned char *addr = (unsigned char*)CFLASH.mapped + CFLASH.offset; + int i; + + currflash = FDEV; + + devices[flashdevices[currflash].idx].activate(); + + for (i=0;i<size;i++) + buffer[i]=flash_readb(addr,*ppos+i); + + devices[flashdevices[currflash].idx].deactivate(); + + *ppos+=size; + return size; +} + +static ssize_t bios_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) +{ + unsigned long flags; + unsigned int offset=0, startsec=0, endsec=0; + unsigned int secnum=0, size=0, writeoffs=0; + unsigned int i, fn; + unsigned char *clipboard; + unsigned char *addr = (unsigned char*)CFLASH.mapped + CFLASH.offset; + + currflash=FDEV; + fn=CFLASH.flashnum; + + /* Some security checks. */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + if (!suser()) + return -EACCES; +#endif + + if (!write) { + printk (KERN_WARNING "Writing is disabled for security reasons. RTFM.\n"); + return -EACCES; + } + + if (!flashchips[fn].supported) { + printk (KERN_ERR "BIOS: Flash device not supported.\n"); + return -EMEDIUMTYPE; + } + + if ( count > BIOS_SIZE-*ppos ) + return -EFBIG; + + /* FIXME: Autoselect(AMD) BC-90 + * -> 00/MID; + * 01/PID; + * 02/Protected (1=yes/0=no) + */ + + /* Determine size of data to be written */ + + if (!(flashchips[fn].flags & f_needs_erase) ) { + offset=(unsigned int)*ppos&~(flashchips[fn].pagesize-1); + size=(((unsigned int)*ppos+count+(flashchips[fn].pagesize-1))& + ~(flashchips[CFLASH.flashnum].pagesize-1))-offset; + } else { + while (flashchips[fn].sectors[secnum] <= flashchips[fn].size ) { + if ((unsigned int)*ppos >= flashchips[fn].sectors[secnum]*1024) { + offset=flashchips[fn].sectors[secnum]*1024; + startsec=secnum; + } + if ((unsigned int)*ppos+count-1 <= flashchips[fn].sectors[secnum]*1024) { + size=(flashchips[fn].sectors[secnum]*1024)-offset; + endsec=secnum-1; + break; + } + secnum++; + } + } + +#ifdef DEBUG + printk (KERN_DEBUG "BIOS: Write [0x%06x..0x%06x] [0x%06x..0x%06x]\n", + (unsigned int)(*ppos),(unsigned int)(*ppos+count-1),offset,offset+size-1); +#endif + + /* prepare data for writing */ + + clipboard=vmalloc(size); + + spin_lock_irqsave(&bios_lock, flags); + + devices[flashdevices[currflash].idx].activate(); + + for (i=0; i < size; i++) + clipboard[i] = flash_readb(addr,offset+i); + + copy_from_user(clipboard+(*ppos-offset), buffer, count); + + /* start write access */ + + if (flashchips[fn].flags & f_intel_compl) { + iflash_erase_sectors(addr,fn,startsec,endsec); + + for (i=0;i<size;i++) + iflash_program_byte(addr, offset+i, clipboard[i]); + + flash_command(addr, 0xff); + + } else { + + if (flashchips[fn].flags & f_needs_erase) { + if (size == flashchips[fn].size*1024) { /* whole chip erase */ + printk (KERN_DEBUG "BIOS: Erasing via whole chip method\n"); + flash_erase(addr, fn); + } else { + printk (KERN_DEBUG "BIOS: Erasing via sector method\n"); + flash_erase_sectors(addr, fn,startsec,endsec); + } + } + + while (size>0) { + if ((flashchips[fn].flags & f_manuf_compl) != f_atmel_compl) { + flash_program(addr); + } else { + flash_program_atmel(addr); + } + for (i=0;i<flashchips[fn].pagesize;i++) { + flash_writeb(addr,offset+writeoffs+i,clipboard[writeoffs+i]); + } + if ((flashchips[fn].flags & f_manuf_compl) == f_atmel_compl) { + udelay(750); + } else { + if (flashchips[fn].pagesize==1) + udelay(30); + else + udelay(300); + } + + if (flash_ready_poll(addr,offset+writeoffs+flashchips[fn].pagesize-1, + clipboard[writeoffs+flashchips[fn].pagesize-1])) { + printk (KERN_ERR "BIOS: Error occured, please repeat write operation.\n"); + } + flash_command(addr, 0xf0); + + writeoffs += flashchips[fn].pagesize; + size -= flashchips[fn].pagesize; + } + } + + devices[flashdevices[currflash].idx].deactivate(); + + spin_unlock_irqrestore(&bios_lock, flags); + + vfree(clipboard); + + *ppos+=count; + return count; +} + +static int bios_open(struct inode *inode, struct file *file) +{ + currflash=FDEV; + + if (flashcount<=FDEV) { + printk (KERN_ERR "BIOS: There is no device (%d).\n",FDEV); + return -ENODEV; + } + +#ifdef DEBUG + printk(KERN_DEBUG "BIOS: Opening device %d\n",FDEV); +#endif + /* Only one shall open for writing */ + + if ((CFLASH.open_cnt && (file->f_flags & O_EXCL)) || + (CFLASH.open_mode & O_EXCL) || + ((file->f_mode & 2) && (CFLASH.open_mode & O_RDWR))) + return -EBUSY; + + if (file->f_flags & O_EXCL) + CFLASH.open_mode |= O_EXCL; + + if (file->f_mode & 2) + CFLASH.open_mode |= O_RDWR; + + CFLASH.open_cnt++; + + +#ifdef MODULE + inc_mod(); +#endif + return 0; +} + +static int bios_release(struct inode *inode, struct file *file) +{ + currflash=FDEV; + if (file->f_flags & O_EXCL) + CFLASH.open_mode &= ~O_EXCL; + + if (file->f_mode & 2) + CFLASH.open_mode &= ~O_RDWR; + + CFLASH.open_cnt--; + +#ifdef MODULE + dec_mod(); +#endif + return 0; +} + +struct file_operations bios_fops = { + .owner = THIS_MODULE, + .llseek = bios_llseek, + .read = bios_read, + .write = bios_write, + .open = bios_open, + .release = bios_release, +}; + |