Import 2.3.16
[davej-history.git] / drivers / sbus / char / flash.c
blob6764486c8175d18a2edb67456180a175dda9a761
1 /* $Id: flash.c,v 1.13 1999/08/31 06:58:06 davem Exp $
2 * flash.c: Allow mmap access to the OBP Flash, for OBP updates.
4 * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
5 */
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>
20 #include <asm/io.h>
21 #include <asm/sbus.h>
22 #include <asm/ebus.h>
24 static struct {
25 unsigned long read_base; /* Physical read address */
26 unsigned long write_base; /* Physical write address */
27 unsigned long read_size; /* Size of read area */
28 unsigned long write_size; /* Size of write area */
29 unsigned long busy; /* In use? */
30 } flash;
32 #define FLASH_MINOR 152
34 static int
35 flash_mmap(struct file *file, struct vm_area_struct *vma)
37 unsigned long addr;
38 unsigned long size;
40 if (vma->vm_offset & ~(PAGE_MASK))
41 return -ENXIO;
43 if (flash.read_base == flash.write_base) {
44 addr = flash.read_base;
45 size = flash.read_size;
46 } else {
47 if ((vma->vm_flags & VM_READ) &&
48 (vma->vm_flags & VM_WRITE))
49 return -EINVAL;
51 if (vma->vm_flags & VM_READ) {
52 addr = flash.read_base;
53 size = flash.read_size;
54 } else if (vma->vm_flags & VM_WRITE) {
55 addr = flash.write_base;
56 size = flash.write_size;
57 } else
58 return -ENXIO;
61 if (vma->vm_offset > size)
62 return -ENXIO;
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))
73 return -EAGAIN;
75 return 0;
78 static long long
79 flash_llseek(struct file *file, long long offset, int origin)
81 switch (origin) {
82 case 0:
83 file->f_pos = offset;
84 break;
85 case 1:
86 file->f_pos += offset;
87 if (file->f_pos > flash.read_size)
88 file->f_pos = flash.read_size;
89 break;
90 case 2:
91 file->f_pos = flash.read_size;
92 break;
93 default:
94 return -EINVAL;
96 return file->f_pos;
99 static ssize_t
100 flash_read(struct file * file, char * buf,
101 size_t count, loff_t *ppos)
103 unsigned long p = file->f_pos;
105 if (count > flash.read_size - p)
106 count = flash.read_size - p;
108 if (copy_to_user(buf, flash.read_base + p, count) < 0)
109 return -EFAULT;
111 file->f_pos += count;
112 return count;
115 static int
116 flash_open(struct inode *inode, struct file *file)
118 if (test_and_set_bit(0, (void *)&flash.busy) != 0)
119 return -EBUSY;
121 MOD_INC_USE_COUNT;
122 return 0;
125 static int
126 flash_release(struct inode *inode, struct file *file)
128 MOD_DEC_USE_COUNT;
129 flash.busy = 0;
130 return 0;
133 static struct file_operations flash_fops = {
134 flash_llseek,
135 flash_read,
136 NULL, /* no write to the Flash, use mmap
137 * and play flash dependent tricks.
139 NULL, /* readdir */
140 NULL, /* poll */
141 NULL, /* ioctl */
142 flash_mmap,
143 flash_open,
144 NULL, /* flush */
145 flash_release
148 static struct miscdevice flash_dev = { FLASH_MINOR, "flash", &flash_fops };
150 EXPORT_NO_SYMBOLS;
152 #ifdef MODULE
153 int init_module(void)
154 #else
155 int __init flash_init(void)
156 #endif
158 struct linux_sbus *sbus;
159 struct linux_sbus_device *sdev = 0;
160 struct linux_ebus *ebus;
161 struct linux_ebus_device *edev = 0;
162 struct linux_prom_registers regs[2];
163 int len, err, nregs;
165 for_all_sbusdev(sdev, sbus) {
166 if (!strcmp(sdev->prom_name, "flashprom")) {
167 prom_apply_sbus_ranges(sdev->my_bus, &sdev->reg_addrs[0],
168 sdev->num_registers, sdev);
169 if (sdev->reg_addrs[0].phys_addr == sdev->reg_addrs[1].phys_addr) {
170 flash.read_base = ((unsigned long)sdev->reg_addrs[0].phys_addr) |
171 (((unsigned long)sdev->reg_addrs[0].which_io)<<32UL);
172 flash.read_size = sdev->reg_addrs[0].reg_size;
173 flash.write_base = flash.read_base;
174 flash.write_size = flash.read_size;
175 } else {
176 flash.read_base = ((unsigned long)sdev->reg_addrs[0].phys_addr) |
177 (((unsigned long)sdev->reg_addrs[0].which_io)<<32UL);
178 flash.read_size = sdev->reg_addrs[0].reg_size;
179 flash.write_base = ((unsigned long)sdev->reg_addrs[1].phys_addr) |
180 (((unsigned long)sdev->reg_addrs[1].which_io)<<32UL);
181 flash.write_size = sdev->reg_addrs[1].reg_size;
183 flash.busy = 0;
184 break;
187 if (!sdev) {
188 #ifdef CONFIG_PCI
189 for_each_ebus(ebus) {
190 for_each_ebusdev(edev, ebus) {
191 if (!strcmp(edev->prom_name, "flashprom"))
192 goto ebus_done;
195 ebus_done:
196 if (!edev)
197 return -ENODEV;
199 len = prom_getproperty(edev->prom_node, "reg", (void *)regs, sizeof(regs));
200 if ((len % sizeof(regs[0])) != 0) {
201 printk("flash: Strange reg property size %d\n", len);
202 return -ENODEV;
205 nregs = len / sizeof(regs[0]);
207 flash.read_base = edev->resource[0].start;
208 flash.read_size = regs[0].reg_size;
210 if (nregs == 1) {
211 flash.write_base = edev->resource[0].start;
212 flash.write_size = regs[0].reg_size;
213 } else if (nregs == 2) {
214 flash.write_base = edev->resource[1].start;
215 flash.write_size = regs[1].reg_size;
216 } else {
217 printk("flash: Strange number of regs %d\n", nregs);
218 return -ENODEV;
221 flash.busy = 0;
223 #else
224 return -ENODEV;
225 #endif
228 printk("OBP Flash: RD %lx[%lx] WR %lx[%lx]\n",
229 flash.read_base, flash.read_size,
230 flash.write_base, flash.write_size);
232 err = misc_register(&flash_dev);
233 if (err) {
234 printk(KERN_ERR "flash: unable to get misc minor\n");
235 return err;
238 return 0;
241 #ifdef MODULE
242 void cleanup_module(void)
244 misc_deregister(&flash_dev);
246 #endif