~ubuntu-branches/ubuntu/utopic/linux-ti-omap/utopic

« back to all changes in this revision

Viewing changes to drivers/sbus/char/flash.c

  • Committer: Bazaar Package Importer
  • Author(s): Amit Kucheria, Amit Kucheria
  • Date: 2010-03-10 02:28:15 UTC
  • Revision ID: james.westby@ubuntu.com-20100310022815-7sd3gwvn5kenaq33
Tags: 2.6.33-500.1
[ Amit Kucheria ]

* Initial release of a 2.6.33-based OMAP kernel
* UBUNTU: [Upstream] Fix omap 1-wire driver compilation
* UBUNTU: ubuntu: AppArmor -- update to mainline 2010-03-04

Show diffs side-by-side

added added

removed removed

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