root/drivers/sbus/char/flash.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. flash_mmap
  2. flash_llseek
  3. flash_read
  4. flash_open
  5. flash_release
  6. flash_probe
  7. flash_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /* flash.c: Allow mmap access to the OBP Flash, for OBP updates.
   3  *
   4  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
   5  */
   6 
   7 #include <linux/module.h>
   8 #include <linux/types.h>
   9 #include <linux/errno.h>
  10 #include <linux/miscdevice.h>
  11 #include <linux/fcntl.h>
  12 #include <linux/poll.h>
  13 #include <linux/mutex.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 <linux/uaccess.h>
  20 #include <asm/pgtable.h>
  21 #include <asm/io.h>
  22 #include <asm/upa.h>
  23 
  24 static DEFINE_MUTEX(flash_mutex);
  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         mutex_lock(&flash_mutex);
  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                         mutex_unlock(&flash_mutex);
  98                         return -EINVAL;
  99         }
 100         mutex_unlock(&flash_mutex);
 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         mutex_lock(&flash_mutex);
 129         if (test_and_set_bit(0, (void *)&flash.busy) != 0) {
 130                 mutex_unlock(&flash_mutex);
 131                 return -EBUSY;
 132         }
 133 
 134         mutex_unlock(&flash_mutex);
 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 flash_probe(struct platform_device *op)
 163 {
 164         struct device_node *dp = op->dev.of_node;
 165         struct device_node *parent;
 166 
 167         parent = dp->parent;
 168 
 169         if (!of_node_name_eq(parent, "sbus") &&
 170             !of_node_name_eq(parent, "sbi") &&
 171             !of_node_name_eq(parent, "ebus"))
 172                 return -ENODEV;
 173 
 174         flash.read_base = op->resource[0].start;
 175         flash.read_size = resource_size(&op->resource[0]);
 176         if (op->resource[1].flags) {
 177                 flash.write_base = op->resource[1].start;
 178                 flash.write_size = resource_size(&op->resource[1]);
 179         } else {
 180                 flash.write_base = op->resource[0].start;
 181                 flash.write_size = resource_size(&op->resource[0]);
 182         }
 183         flash.busy = 0;
 184 
 185         printk(KERN_INFO "%pOF: OBP Flash, RD %lx[%lx] WR %lx[%lx]\n",
 186                op->dev.of_node,
 187                flash.read_base, flash.read_size,
 188                flash.write_base, flash.write_size);
 189 
 190         return misc_register(&flash_dev);
 191 }
 192 
 193 static int flash_remove(struct platform_device *op)
 194 {
 195         misc_deregister(&flash_dev);
 196 
 197         return 0;
 198 }
 199 
 200 static const struct of_device_id flash_match[] = {
 201         {
 202                 .name = "flashprom",
 203         },
 204         {},
 205 };
 206 MODULE_DEVICE_TABLE(of, flash_match);
 207 
 208 static struct platform_driver flash_driver = {
 209         .driver = {
 210                 .name = "flash",
 211                 .of_match_table = flash_match,
 212         },
 213         .probe          = flash_probe,
 214         .remove         = flash_remove,
 215 };
 216 
 217 module_platform_driver(flash_driver);
 218 
 219 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */