1 /* flash.c: Allow mmap access to the OBP Flash, for OBP updates. 2 * 3 * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) 4 */ 5 6 #include <linux/module.h> 7 #include <linux/types.h> 8 #include <linux/errno.h> 9 #include <linux/miscdevice.h> 10 #include <linux/fcntl.h> 11 #include <linux/poll.h> 12 #include <linux/init.h> 13 #include <linux/smp_lock.h> 14 #include <linux/spinlock.h> 15 #include <linux/mm.h> 16 #include <linux/of.h> 17 #include <linux/of_device.h> 18 19 #include <asm/system.h> 20 #include <asm/uaccess.h> 21 #include <asm/pgtable.h> 22 #include <asm/io.h> 23 #include <asm/upa.h> 24 25 static DEFINE_SPINLOCK(flash_lock); 26 static struct { 27 unsigned long read_base; /* Physical read address */ 28 unsigned long write_base; /* Physical write address */ 29 unsigned long read_size; /* Size of read area */ 30 unsigned long write_size; /* Size of write area */ 31 unsigned long busy; /* In use? */ 32 } flash; 33 34 #define FLASH_MINOR 152 35 36 static int 37 flash_mmap(struct file *file, struct vm_area_struct *vma) 38 { 39 unsigned long addr; 40 unsigned long size; 41 42 spin_lock(&flash_lock); 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 spin_unlock(&flash_lock); 50 return -EINVAL; 51 } 52 if (vma->vm_flags & VM_READ) { 53 addr = flash.read_base; 54 size = flash.read_size; 55 } else if (vma->vm_flags & VM_WRITE) { 56 addr = flash.write_base; 57 size = flash.write_size; 58 } else { 59 spin_unlock(&flash_lock); 60 return -ENXIO; 61 } 62 } 63 spin_unlock(&flash_lock); 64 65 if ((vma->vm_pgoff << PAGE_SHIFT) > size) 66 return -ENXIO; 67 addr = vma->vm_pgoff + (addr >> PAGE_SHIFT); 68 69 if (vma->vm_end - (vma->vm_start + (vma->vm_pgoff << PAGE_SHIFT)) > size) 70 size = vma->vm_end - (vma->vm_start + (vma->vm_pgoff << PAGE_SHIFT)); 71 72 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 73 74 if (io_remap_pfn_range(vma, vma->vm_start, addr, size, vma->vm_page_prot)) 75 return -EAGAIN; 76 77 return 0; 78 } 79 80 static long long 81 flash_llseek(struct file *file, long long offset, int origin) 82 { 83 lock_kernel(); 84 switch (origin) { 85 case 0: 86 file->f_pos = offset; 87 break; 88 case 1: 89 file->f_pos += offset; 90 if (file->f_pos > flash.read_size) 91 file->f_pos = flash.read_size; 92 break; 93 case 2: 94 file->f_pos = flash.read_size; 95 break; 96 default: 97 unlock_kernel(); 98 return -EINVAL; 99 } 100 unlock_kernel(); 101 return file->f_pos; 102 } 103 104 static ssize_t 105 flash_read(struct file * file, char __user * buf, 106 size_t count, loff_t *ppos) 107 { 108 loff_t p = *ppos; 109 int i; 110 111 if (count > flash.read_size - p) 112 count = flash.read_size - p; 113 114 for (i = 0; i < count; i++) { 115 u8 data = upa_readb(flash.read_base + p + i); 116 if (put_user(data, buf)) 117 return -EFAULT; 118 buf++; 119 } 120 121 *ppos += count; 122 return count; 123 } 124 125 static int 126 flash_open(struct inode *inode, struct file *file) 127 { 128 lock_kernel(); 129 if (test_and_set_bit(0, (void *)&flash.busy) != 0) { 130 unlock_kernel(); 131 return -EBUSY; 132 } 133 134 unlock_kernel(); 135 return 0; 136 } 137 138 static int 139 flash_release(struct inode *inode, struct file *file) 140 { 141 spin_lock(&flash_lock); 142 flash.busy = 0; 143 spin_unlock(&flash_lock); 144 145 return 0; 146 } 147 148 static const struct file_operations flash_fops = { 149 /* no write to the Flash, use mmap 150 * and play flash dependent tricks. 151 */ 152 .owner = THIS_MODULE, 153 .llseek = flash_llseek, 154 .read = flash_read, 155 .mmap = flash_mmap, 156 .open = flash_open, 157 .release = flash_release, 158 }; 159 160 static struct miscdevice flash_dev = { FLASH_MINOR, "flash", &flash_fops }; 161 162 static int __devinit flash_probe(struct of_device *op, 163 const struct of_device_id *match) 164 { 165 struct device_node *dp = op->node; 166 struct device_node *parent; 167 168 parent = dp->parent; 169 170 if (strcmp(parent->name, "sbus") && 171 strcmp(parent->name, "sbi") && 172 strcmp(parent->name, "ebus")) 173 return -ENODEV; 174 175 flash.read_base = op->resource[0].start; 176 flash.read_size = resource_size(&op->resource[0]); 177 if (op->resource[1].flags) { 178 flash.write_base = op->resource[1].start; 179 flash.write_size = resource_size(&op->resource[1]); 180 } else { 181 flash.write_base = op->resource[0].start; 182 flash.write_size = resource_size(&op->resource[0]); 183 } 184 flash.busy = 0; 185 186 printk(KERN_INFO "%s: OBP Flash, RD %lx[%lx] WR %lx[%lx]\n", 187 op->node->full_name, 188 flash.read_base, flash.read_size, 189 flash.write_base, flash.write_size); 190 191 return misc_register(&flash_dev); 192 } 193 194 static int __devexit flash_remove(struct of_device *op) 195 { 196 misc_deregister(&flash_dev); 197 198 return 0; 199 } 200 201 static const struct of_device_id flash_match[] = { 202 { 203 .name = "flashprom", 204 }, 205 {}, 206 }; 207 MODULE_DEVICE_TABLE(of, flash_match); 208 209 static struct of_platform_driver flash_driver = { 210 .name = "flash", 211 .match_table = flash_match, 212 .probe = flash_probe, 213 .remove = __devexit_p(flash_remove), 214 }; 215 216 static int __init flash_init(void) 217 { 218 return of_register_driver(&flash_driver, &of_bus_type); 219 } 220 221 static void __exit flash_cleanup(void) 222 { 223 of_unregister_driver(&flash_driver); 224 } 225 226 module_init(flash_init); 227 module_exit(flash_cleanup); 228 MODULE_LICENSE("GPL"); 229