[GDB] Zero-extend 16-bit segment registers
[people/balajirrao/gpxe.git] / contrib / smc9462tx-flash / dp83820flash.c
1 /*
2    Kernel module for the dp83820 flash write utility. This code was written
3    by Dave Ashley for NXTV, Inc.
4    Copyright 2004 by NXTV, Inc.
5    Written 20040219 by Dave Ashley.
6
7    This code is released under the terms of the GPL. No warranty.
8
9    THEORY: The dp83820 bootrom interface is flawed in that you can't
10    read or write a single byte at a time, and this is required in order
11    to write to flash devices like the AT29C512. So the workaround is
12    to use the chips ability to map into memory the bootrom, then the cpu
13    can directly do byte accesses.
14
15    The problem is that a "feature" of the dp83820 is that when you map
16    in the bootrom, you conveniently lose access to the PCI registers.
17    So we need to do this in kernel space and wrap every access to the
18    bootrom within interrupt_disable/restore, in case a network interrupt
19    were to come in.
20
21    This kernel module is very simple, it just creates a proc file
22    /proc/dp83820
23    If you write 3 bytes to this file you are doing a write to the flashrom:
24
25 Byte 1   2    3
26    ALOW AHIGH DATA
27
28    If you write 2 bytes to this file you are doing a read from the flashrom:
29 Byte 1   2
30    ALOW AHIGH
31    Then the next read from the file will return a single byte of what
32    was at that location.
33
34    You only get one shot at accessing the proc file, you need to then
35    close/open if you want to do another access. This could probably be
36    cleaned up pretty easily so more accesses can be done without having
37    to close/open the file.     
38
39 */
40
41
42 #include <linux/config.h>
43 #include <linux/kernel.h>
44 #include <linux/sched.h>
45 #include <linux/errno.h>
46 #include <linux/ioport.h>
47 #include <linux/interrupt.h>
48 #include <linux/pci.h>
49 #include <linux/spinlock.h>
50 #include <linux/proc_fs.h>
51 #include <linux/module.h>
52
53
54 #define PROCNAME "dp83820"
55
56 struct pci_dev *mydev=0;
57 unsigned long loc;
58 unsigned char *addr=0;
59
60 unsigned char lastread;
61
62
63 int my_read_proc(char *buf, char **start,off_t offset,int count, int *eof,void *data)
64 {
65 int retval=0;
66
67         if(count>0)
68         {
69                 buf[0]=lastread;
70                 retval=1;
71         }
72
73         *eof=1;
74
75         return retval;
76 }
77
78 int my_write_proc(struct file *file, const char *buffer, unsigned long count,
79                 void *data)
80 {
81 unsigned char *msg;
82
83 unsigned long flags;
84
85         msg=(void *)buffer;
86         save_flags(flags);
87         cli();
88         pci_write_config_dword(mydev, 0x30, loc | 1);
89
90         switch(count)
91         {
92                 case 2:
93                         lastread=addr[msg[0] | (msg[1]<<8)];
94                         break;
95                 case 3:
96                         addr[msg[0] | (msg[1]<<8)] = msg[2];
97                         break;
98         }
99         pci_write_config_dword(mydev, 0x30, loc);
100         restore_flags(flags);
101         return count;
102 }
103
104
105 struct proc_dir_entry *de=0;
106
107 int __init init_module(void)
108 {
109 int found=0;
110         mydev=0;
111         pci_for_each_dev(mydev)
112         {
113                 if(mydev->vendor==0x100b && mydev->device==0x0022)
114                 {
115                         found=1;
116                         break;
117                 }
118         }
119         if(!found)
120         {
121                 printk("Could not find DP83820 network device\n");
122                 return ENODEV;
123         }
124
125         de=create_proc_entry(PROCNAME,0,0);
126         if(!de)
127                 return -1;
128         de->data=0;
129         de->read_proc=my_read_proc;
130         de->write_proc=my_write_proc;
131
132         loc=mydev->resource[PCI_ROM_RESOURCE].start;
133         addr=ioremap_nocache(loc,0x10000);
134
135
136         return 0;
137 }
138
139 void cleanup_module(void)
140 {
141         if(de)
142         {
143                 remove_proc_entry(PROCNAME,0);
144                 de=0;
145         }
146         if(addr)
147         {
148                 iounmap(addr);
149                 addr=0;
150         }
151 }
152