diff options
Diffstat (limited to 'contrib/smc9462tx-flash/dp83820flash.c')
-rw-r--r-- | contrib/smc9462tx-flash/dp83820flash.c | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/contrib/smc9462tx-flash/dp83820flash.c b/contrib/smc9462tx-flash/dp83820flash.c new file mode 100644 index 00000000..661c4291 --- /dev/null +++ b/contrib/smc9462tx-flash/dp83820flash.c @@ -0,0 +1,152 @@ +/* + Kernel module for the dp83820 flash write utility. This code was written + by Dave Ashley for NXTV, Inc. + Copyright 2004 by NXTV, Inc. + Written 20040219 by Dave Ashley. + + This code is released under the terms of the GPL. No warranty. + + THEORY: The dp83820 bootrom interface is flawed in that you can't + read or write a single byte at a time, and this is required in order + to write to flash devices like the AT29C512. So the workaround is + to use the chips ability to map into memory the bootrom, then the cpu + can directly do byte accesses. + + The problem is that a "feature" of the dp83820 is that when you map + in the bootrom, you conveniently lose access to the PCI registers. + So we need to do this in kernel space and wrap every access to the + bootrom within interrupt_disable/restore, in case a network interrupt + were to come in. + + This kernel module is very simple, it just creates a proc file + /proc/dp83820 + If you write 3 bytes to this file you are doing a write to the flashrom: + +Byte 1 2 3 + ALOW AHIGH DATA + + If you write 2 bytes to this file you are doing a read from the flashrom: +Byte 1 2 + ALOW AHIGH + Then the next read from the file will return a single byte of what + was at that location. + + You only get one shot at accessing the proc file, you need to then + close/open if you want to do another access. This could probably be + cleaned up pretty easily so more accesses can be done without having + to close/open the file. + +*/ + + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/spinlock.h> +#include <linux/proc_fs.h> +#include <linux/module.h> + + +#define PROCNAME "dp83820" + +struct pci_dev *mydev=0; +unsigned long loc; +unsigned char *addr=0; + +unsigned char lastread; + + +int my_read_proc(char *buf, char **start,off_t offset,int count, int *eof,void *data) +{ +int retval=0; + + if(count>0) + { + buf[0]=lastread; + retval=1; + } + + *eof=1; + + return retval; +} + +int my_write_proc(struct file *file, const char *buffer, unsigned long count, + void *data) +{ +unsigned char *msg; + +unsigned long flags; + + msg=(void *)buffer; + save_flags(flags); + cli(); + pci_write_config_dword(mydev, 0x30, loc | 1); + + switch(count) + { + case 2: + lastread=addr[msg[0] | (msg[1]<<8)]; + break; + case 3: + addr[msg[0] | (msg[1]<<8)] = msg[2]; + break; + } + pci_write_config_dword(mydev, 0x30, loc); + restore_flags(flags); + return count; +} + + +struct proc_dir_entry *de=0; + +int __init init_module(void) +{ +int found=0; + mydev=0; + pci_for_each_dev(mydev) + { + if(mydev->vendor==0x100b && mydev->device==0x0022) + { + found=1; + break; + } + } + if(!found) + { + printk("Could not find DP83820 network device\n"); + return ENODEV; + } + + de=create_proc_entry(PROCNAME,0,0); + if(!de) + return -1; + de->data=0; + de->read_proc=my_read_proc; + de->write_proc=my_write_proc; + + loc=mydev->resource[PCI_ROM_RESOURCE].start; + addr=ioremap_nocache(loc,0x10000); + + + return 0; +} + +void cleanup_module(void) +{ + if(de) + { + remove_proc_entry(PROCNAME,0); + de=0; + } + if(addr) + { + iounmap(addr); + addr=0; + } +} + |