2 * OpenBIOS - free your system!
3 * ( firmware/flash device driver for Linux )
5 * filesystem.c - vfs character device interface
7 * This program is part of a free implementation of the IEEE 1275-1994
8 * Standard for Boot (Initialization Configuration) Firmware.
10 * Copyright (C) 1998-2004 Stefan Reinauer, <stepan@openbios.org>
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.
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.
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
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>
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>
39 #include <asm/uaccess.h>
42 #include "flashchips.h"
44 #include "programming.h"
52 * ******************************************
54 * /dev/bios filesystem operations
56 * ******************************************
59 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
60 #define FDEV (MINOR(file->f_dentry->d_inode->i_rdev))
62 #define FDEV (iminor(file->f_dentry->d_inode))
64 #define CFLASH flashdevices[FDEV]
65 // #define BIOS_SIZE ((flashchips[CFLASH.flashnum].size)*1024)
66 #define BIOS_SIZE (CFLASH.size)
68 static loff_t
bios_llseek(struct file
*file
, loff_t offset
, int origin
)
75 offset
+= file
->f_pos
;
81 return((offset
>= 0)?(file
->f_pos
= offset
):-EINVAL
);
84 static ssize_t
bios_read(struct file
*file
, char *buffer
, size_t count
, loff_t
*ppos
)
86 signed int size
=((BIOS_SIZE
-*ppos
>count
) ? count
: BIOS_SIZE
-*ppos
);
87 unsigned char *addr
= (unsigned char*)CFLASH
.mapped
+ CFLASH
.offset
;
92 devices
[flashdevices
[currflash
].idx
].activate();
95 buffer
[i
]=flash_readb(addr
,*ppos
+i
);
97 devices
[flashdevices
[currflash
].idx
].deactivate();
103 static ssize_t
bios_write(struct file
*file
, const char *buffer
, size_t count
, loff_t
*ppos
)
106 unsigned int offset
=0, startsec
=0, endsec
=0;
107 unsigned int secnum
=0, size
=0, writeoffs
=0;
109 unsigned char *clipboard
;
110 unsigned char *addr
= (unsigned char*)CFLASH
.mapped
+ CFLASH
.offset
;
115 /* Some security checks. */
117 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
123 printk (KERN_WARNING
"Writing is disabled for security reasons. RTFM.\n");
127 if (!flashchips
[fn
].supported
) {
128 printk (KERN_ERR
"BIOS: Flash device not supported.\n");
132 if ( count
> BIOS_SIZE
-*ppos
)
135 /* FIXME: Autoselect(AMD) BC-90
138 * 02/Protected (1=yes/0=no)
141 /* Determine size of data to be written */
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
;
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;
153 if ((unsigned int)*ppos
+count
-1 <= flashchips
[fn
].sectors
[secnum
]*1024) {
154 size
=(flashchips
[fn
].sectors
[secnum
]*1024)-offset
;
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);
167 /* prepare data for writing */
169 clipboard
=vmalloc(size
);
171 spin_lock_irqsave(&bios_lock
, flags
);
173 devices
[flashdevices
[currflash
].idx
].activate();
175 for (i
=0; i
< size
; i
++)
176 clipboard
[i
] = flash_readb(addr
,offset
+i
);
178 copy_from_user(clipboard
+(*ppos
-offset
), buffer
, count
);
180 /* start write access */
182 if (flashchips
[fn
].flags
& f_intel_compl
) {
183 iflash_erase_sectors(addr
,fn
,startsec
,endsec
);
186 iflash_program_byte(addr
, offset
+i
, clipboard
[i
]);
188 flash_command(addr
, 0xff);
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
);
197 printk (KERN_DEBUG
"BIOS: Erasing via sector method\n");
198 flash_erase_sectors(addr
, fn
,startsec
,endsec
);
203 if ((flashchips
[fn
].flags
& f_manuf_compl
) != f_atmel_compl
) {
206 flash_program_atmel(addr
);
208 for (i
=0;i
<flashchips
[fn
].pagesize
;i
++) {
209 flash_writeb(addr
,offset
+writeoffs
+i
,clipboard
[writeoffs
+i
]);
211 if ((flashchips
[fn
].flags
& f_manuf_compl
) == f_atmel_compl
) {
214 if (flashchips
[fn
].pagesize
==1)
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");
224 flash_command(addr
, 0xf0);
226 writeoffs
+= flashchips
[fn
].pagesize
;
227 size
-= flashchips
[fn
].pagesize
;
231 devices
[flashdevices
[currflash
].idx
].deactivate();
233 spin_unlock_irqrestore(&bios_lock
, flags
);
241 static int bios_open(struct inode
*inode
, struct file
*file
)
245 if (flashcount
<=FDEV
) {
246 printk (KERN_ERR
"BIOS: There is no device (%d).\n",FDEV
);
251 printk(KERN_DEBUG
"BIOS: Opening device %d\n",FDEV
);
253 /* Only one shall open for writing */
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
)))
260 if (file
->f_flags
& O_EXCL
)
261 CFLASH
.open_mode
|= O_EXCL
;
263 if (file
->f_mode
& 2)
264 CFLASH
.open_mode
|= O_RDWR
;
275 static int bios_release(struct inode
*inode
, struct file
*file
)
278 if (file
->f_flags
& O_EXCL
)
279 CFLASH
.open_mode
&= ~O_EXCL
;
281 if (file
->f_mode
& 2)
282 CFLASH
.open_mode
&= ~O_RDWR
;
292 struct file_operations bios_fops
= {
293 .owner
= THIS_MODULE
,
294 .llseek
= bios_llseek
,
298 .release
= bios_release
,