1 /* $Id: flash.c,v 1.9 1998/05/17 06:33:39 ecd Exp $
2 * flash.c: Allow mmap access to the OBP Flash, for OBP updates.
4 * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
7 #include <linux/config.h>
8 #include <linux/module.h>
9 #include <linux/types.h>
10 #include <linux/errno.h>
11 #include <linux/miscdevice.h>
12 #include <linux/malloc.h>
13 #include <linux/fcntl.h>
14 #include <linux/poll.h>
15 #include <linux/init.h>
17 #include <asm/system.h>
18 #include <asm/uaccess.h>
19 #include <asm/pgtable.h>
25 unsigned long read_base
;
26 unsigned long write_base
;
27 unsigned long read_size
;
28 unsigned long write_size
;
32 #define FLASH_MINOR 152
35 flash_mmap(struct file
*file
, struct vm_area_struct
*vma
)
40 if (vma
->vm_offset
& ~(PAGE_MASK
))
43 if (flash
.read_base
== flash
.write_base
) {
44 addr
= __pa(flash
.read_base
);
45 size
= flash
.read_size
;
47 if ((vma
->vm_flags
& VM_READ
) &&
48 (vma
->vm_flags
& VM_WRITE
))
51 if (vma
->vm_flags
& VM_READ
) {
52 addr
= __pa(flash
.read_base
);
53 size
= flash
.read_size
;
54 } else if (vma
->vm_flags
& VM_WRITE
) {
55 addr
= __pa(flash
.write_base
);
56 size
= flash
.write_size
;
61 if (vma
->vm_offset
> size
)
63 addr
+= vma
->vm_offset
;
65 if (vma
->vm_end
- (vma
->vm_start
+ vma
->vm_offset
) > size
)
66 size
= vma
->vm_end
- (vma
->vm_start
+ vma
->vm_offset
);
68 pgprot_val(vma
->vm_page_prot
) &= ~(_PAGE_CACHE
);
69 pgprot_val(vma
->vm_page_prot
) |= _PAGE_E
;
70 vma
->vm_flags
|= (VM_SHM
| VM_LOCKED
);
72 if (remap_page_range(vma
->vm_start
, addr
, size
, vma
->vm_page_prot
))
81 flash_llseek(struct file
*file
, long long offset
, int origin
)
88 file
->f_pos
+= offset
;
89 if (file
->f_pos
> flash
.read_size
)
90 file
->f_pos
= flash
.read_size
;
93 file
->f_pos
= flash
.read_size
;
102 flash_read(struct file
* file
, char * buf
,
103 size_t count
, loff_t
*ppos
)
105 unsigned long p
= file
->f_pos
;
107 if (count
> flash
.read_size
- p
)
108 count
= flash
.read_size
- p
;
110 if (copy_to_user(buf
, flash
.read_base
+ p
, count
) < 0)
113 file
->f_pos
+= count
;
118 flash_open(struct inode
*inode
, struct file
*file
)
120 if (test_and_set_bit(0, (void *)&flash
.busy
) != 0)
128 flash_release(struct inode
*inode
, struct file
*file
)
135 static struct file_operations flash_fops
= {
138 NULL
, /* no write to the Flash, use mmap
139 * and play flash dependent tricks.
150 static struct miscdevice flash_dev
= { FLASH_MINOR
, "flash", &flash_fops
};
155 int init_module(void)
157 __initfunc(int flash_init(void))
160 struct linux_sbus
*sbus
;
161 struct linux_sbus_device
*sdev
= 0;
162 struct linux_ebus
*ebus
;
163 struct linux_ebus_device
*edev
= 0;
164 struct linux_prom_registers regs
[2];
167 for_all_sbusdev(sdev
, sbus
) {
168 if (!strcmp(sdev
->prom_name
, "flashprom")) {
169 prom_apply_sbus_ranges(sdev
->my_bus
, &sdev
->reg_addrs
[0],
170 sdev
->num_registers
, sdev
);
171 if (sdev
->reg_addrs
[0].phys_addr
== sdev
->reg_addrs
[1].phys_addr
) {
172 flash
.read_base
= (unsigned long)sparc_alloc_io(sdev
->reg_addrs
[0].phys_addr
, 0,
173 sdev
->reg_addrs
[0].reg_size
, "flashprom",
174 sdev
->reg_addrs
[0].which_io
, 0);
175 flash
.read_size
= sdev
->reg_addrs
[0].reg_size
;
176 flash
.write_base
= flash
.read_base
;
177 flash
.write_size
= flash
.read_size
;
179 flash
.read_base
= (unsigned long)sparc_alloc_io(sdev
->reg_addrs
[0].phys_addr
, 0,
180 sdev
->reg_addrs
[0].reg_size
, "flashprom",
181 sdev
->reg_addrs
[0].which_io
, 0);
182 flash
.read_size
= sdev
->reg_addrs
[0].reg_size
;
183 flash
.write_base
= (unsigned long)sparc_alloc_io(sdev
->reg_addrs
[1].phys_addr
, 0,
184 sdev
->reg_addrs
[1].reg_size
, "flashprom",
185 sdev
->reg_addrs
[1].which_io
, 0);
186 flash
.write_size
= sdev
->reg_addrs
[1].reg_size
;
194 for_each_ebus(ebus
) {
195 for_each_ebusdev(edev
, ebus
) {
196 if (!strcmp(edev
->prom_name
, "flashprom"))
204 len
= prom_getproperty(edev
->prom_node
, "reg", (void *)regs
, sizeof(regs
));
205 if ((len
% sizeof(regs
[0])) != 0) {
206 printk("flash: Strange reg property size %d\n", len
);
210 nregs
= len
/ sizeof(regs
[0]);
212 flash
.read_base
= edev
->base_address
[0];
213 flash
.read_size
= regs
[0].reg_size
;
216 flash
.write_base
= edev
->base_address
[0];
217 flash
.write_size
= regs
[0].reg_size
;
218 } else if (nregs
== 2) {
219 flash
.write_base
= edev
->base_address
[1];
220 flash
.write_size
= regs
[1].reg_size
;
222 printk("flash: Strange number of regs %d\n", nregs
);
233 printk("OBP Flash: RD %lx[%lx] WR %lx[%lx]\n",
234 __pa(flash
.read_base
), flash
.read_size
,
235 __pa(flash
.write_base
), flash
.write_size
);
237 err
= misc_register(&flash_dev
);
239 printk(KERN_ERR
"flash: unable to get misc minor\n");
247 void cleanup_module(void)
249 misc_deregister(&flash_dev
);