Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / utils / devbios / filesystem.c
1 /*
2  *                     OpenBIOS - free your system! 
3  *              ( firmware/flash device driver for Linux )
4  *                          
5  *  filesystem.c - vfs character device interface
6  *  
7  *  This program is part of a free implementation of the IEEE 1275-1994 
8  *  Standard for Boot (Initialization Configuration) Firmware.
9  *
10  *  Copyright (C) 1998-2004  Stefan Reinauer, <stepan@openbios.org>
11  *
12  *  This program is free software; you can redistribute it and/or modify
13  *  it under the terms of the GNU General Public License as published by
14  *  the Free Software Foundation; version 2 of the License.
15  *
16  *  This program is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *  GNU General Public License for more details.
20  *
21  *  You should have received a copy of the GNU General Public License
22  *  along with this program; if not, write to the Free Software
23  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
24  *
25  */
26
27 #include <linux/config.h>
28 #include <linux/version.h>
29 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) && defined(MODVERSIONS)
30 #include <linux/modversions.h>
31 #endif
32 #include <linux/module.h>
33 #include <linux/errno.h>
34 #include <linux/types.h>
35 #include <linux/vmalloc.h>
36 #include <linux/fcntl.h>
37 #include <linux/delay.h>
38
39 #include <asm/uaccess.h>
40
41 #include "bios.h"
42 #include "flashchips.h"
43 #include "pcisets.h"
44 #include "programming.h"
45
46 #ifdef MODULE
47 void inc_mod(void);
48 void dec_mod(void);
49 #endif
50
51 /*
52  * ******************************************
53  *
54  *      /dev/bios filesystem operations
55  *
56  * ****************************************** 
57  */
58
59 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
60 #define FDEV            (MINOR(file->f_dentry->d_inode->i_rdev))
61 #else
62 #define FDEV            (iminor(file->f_dentry->d_inode))
63 #endif
64 #define CFLASH          flashdevices[FDEV]
65 // #define BIOS_SIZE    ((flashchips[CFLASH.flashnum].size)*1024)
66 #define BIOS_SIZE       (CFLASH.size)
67
68 static loff_t bios_llseek(struct file *file, loff_t offset, int origin )
69 {
70         currflash=FDEV;
71         switch(origin) {
72           case 0:
73                 break;
74           case 1:
75                 offset += file->f_pos;
76                 break;
77           case 2:
78                 offset += BIOS_SIZE;
79                 break;
80         }
81         return((offset >= 0)?(file->f_pos = offset):-EINVAL);
82 }
83
84 static ssize_t bios_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
85 {
86         signed int size=((BIOS_SIZE-*ppos>count) ? count : BIOS_SIZE-*ppos);
87         unsigned char *addr = (unsigned char*)CFLASH.mapped + CFLASH.offset;
88         int i;
89
90         currflash = FDEV;
91
92         devices[flashdevices[currflash].idx].activate();
93
94         for (i=0;i<size;i++) 
95                 buffer[i]=flash_readb(addr,*ppos+i);
96
97         devices[flashdevices[currflash].idx].deactivate();
98
99         *ppos+=size;
100         return size;
101 }
102
103 static ssize_t bios_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
104 {
105         unsigned long flags;
106         unsigned int offset=0, startsec=0, endsec=0;
107         unsigned int secnum=0, size=0, writeoffs=0;
108         unsigned int i, fn;
109         unsigned char *clipboard;
110         unsigned char *addr = (unsigned char*)CFLASH.mapped + CFLASH.offset;
111
112         currflash=FDEV;
113         fn=CFLASH.flashnum;
114
115         /* Some security checks. */
116
117 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
118         if (!suser())
119                 return -EACCES;
120 #endif
121
122         if (!write) {
123                 printk (KERN_WARNING "Writing is disabled for security reasons.  RTFM.\n");
124                 return -EACCES;
125         }
126
127         if (!flashchips[fn].supported) {
128                 printk (KERN_ERR "BIOS: Flash device not supported.\n");
129                 return -EMEDIUMTYPE;
130         }
131
132         if ( count > BIOS_SIZE-*ppos )
133                 return -EFBIG;
134
135         /* FIXME: Autoselect(AMD) BC-90 
136          * -> 00/MID; 
137          *    01/PID; 
138          *    02/Protected (1=yes/0=no)
139          */
140
141         /* Determine size of data to be written */
142
143         if (!(flashchips[fn].flags & f_needs_erase) ) {
144                 offset=(unsigned int)*ppos&~(flashchips[fn].pagesize-1);
145                 size=(((unsigned int)*ppos+count+(flashchips[fn].pagesize-1))&
146                                 ~(flashchips[CFLASH.flashnum].pagesize-1))-offset;
147         } else {
148                 while (flashchips[fn].sectors[secnum] <= flashchips[fn].size ) {
149                         if ((unsigned int)*ppos >= flashchips[fn].sectors[secnum]*1024) {
150                                 offset=flashchips[fn].sectors[secnum]*1024;
151                                 startsec=secnum;
152                         }
153                         if ((unsigned int)*ppos+count-1 <= flashchips[fn].sectors[secnum]*1024) {
154                                 size=(flashchips[fn].sectors[secnum]*1024)-offset;
155                                 endsec=secnum-1;
156                                 break;
157                         }
158                         secnum++;
159                 }
160         }
161
162 #ifdef DEBUG
163         printk (KERN_DEBUG "BIOS: Write [0x%06x..0x%06x] [0x%06x..0x%06x]\n",
164                         (unsigned int)(*ppos),(unsigned int)(*ppos+count-1),offset,offset+size-1);
165 #endif
166
167         /* prepare data for writing */
168
169         clipboard=vmalloc(size);
170
171         spin_lock_irqsave(&bios_lock, flags);
172
173         devices[flashdevices[currflash].idx].activate();
174
175         for (i=0; i < size; i++) 
176                 clipboard[i] = flash_readb(addr,offset+i);
177
178         copy_from_user(clipboard+(*ppos-offset), buffer, count);
179
180         /* start write access */
181
182         if (flashchips[fn].flags & f_intel_compl) {
183                 iflash_erase_sectors(addr,fn,startsec,endsec);
184
185                 for (i=0;i<size;i++)
186                         iflash_program_byte(addr, offset+i, clipboard[i]);
187
188                 flash_command(addr, 0xff);
189
190         } else {
191
192           if (flashchips[fn].flags & f_needs_erase) {
193             if (size == flashchips[fn].size*1024) { /* whole chip erase */
194               printk (KERN_DEBUG "BIOS: Erasing via whole chip method\n");
195               flash_erase(addr, fn);
196             } else {
197               printk (KERN_DEBUG "BIOS: Erasing via sector method\n");
198               flash_erase_sectors(addr, fn,startsec,endsec);
199             }
200           } 
201
202           while (size>0) {
203             if ((flashchips[fn].flags & f_manuf_compl) != f_atmel_compl) {
204               flash_program(addr);
205             } else {
206               flash_program_atmel(addr);
207             }
208             for (i=0;i<flashchips[fn].pagesize;i++) {
209               flash_writeb(addr,offset+writeoffs+i,clipboard[writeoffs+i]);
210             }
211             if ((flashchips[fn].flags & f_manuf_compl) == f_atmel_compl) {
212               udelay(750);
213             } else {
214                     if (flashchips[fn].pagesize==1)
215                             udelay(30);
216                     else
217                             udelay(300);
218             }
219
220             if (flash_ready_poll(addr,offset+writeoffs+flashchips[fn].pagesize-1,
221                                  clipboard[writeoffs+flashchips[fn].pagesize-1])) {
222               printk (KERN_ERR "BIOS: Error occured, please repeat write operation.\n");
223             }
224             flash_command(addr, 0xf0);
225             
226             writeoffs += flashchips[fn].pagesize;
227             size          -= flashchips[fn].pagesize;
228           }
229         }
230
231         devices[flashdevices[currflash].idx].deactivate();
232
233         spin_unlock_irqrestore(&bios_lock, flags);
234
235         vfree(clipboard);
236
237         *ppos+=count;
238         return count;
239 }
240
241 static int bios_open(struct inode *inode, struct file *file)
242 {
243         currflash=FDEV;
244         
245         if (flashcount<=FDEV) {
246                 printk (KERN_ERR "BIOS: There is no device (%d).\n",FDEV);
247                 return -ENODEV;
248         }
249
250 #ifdef DEBUG
251         printk(KERN_DEBUG "BIOS: Opening device %d\n",FDEV);
252 #endif
253         /* Only one shall open for writing */
254
255         if ((CFLASH.open_cnt && (file->f_flags & O_EXCL)) ||
256                 (CFLASH.open_mode & O_EXCL) ||
257                 ((file->f_mode & 2) && (CFLASH.open_mode & O_RDWR)))
258                 return -EBUSY;
259
260         if (file->f_flags & O_EXCL)
261                 CFLASH.open_mode |= O_EXCL;
262
263         if (file->f_mode & 2)
264                 CFLASH.open_mode |= O_RDWR;
265
266         CFLASH.open_cnt++;
267
268         
269 #ifdef MODULE
270         inc_mod();
271 #endif
272         return 0;
273 }
274
275 static int bios_release(struct inode *inode, struct file *file)
276 {
277         currflash=FDEV;
278         if (file->f_flags & O_EXCL)
279                 CFLASH.open_mode &= ~O_EXCL;
280
281         if (file->f_mode & 2)
282                 CFLASH.open_mode &= ~O_RDWR;
283
284         CFLASH.open_cnt--;
285         
286 #ifdef MODULE
287         dec_mod();
288 #endif
289         return 0;
290 }
291
292 struct file_operations bios_fops = {
293         .owner          = THIS_MODULE,
294         .llseek         = bios_llseek,
295         .read           = bios_read,
296         .write          = bios_write,
297         .open           = bios_open,
298         .release        = bios_release,
299 };
300