diff options
Diffstat (limited to 'drivers/char/bsr.c')
-rw-r--r-- | drivers/char/bsr.c | 42 |
1 files changed, 29 insertions, 13 deletions
diff --git a/drivers/char/bsr.c b/drivers/char/bsr.c index 140ea10ecb88..c02db01f736e 100644 --- a/drivers/char/bsr.c +++ b/drivers/char/bsr.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/cdev.h> | 27 | #include <linux/cdev.h> |
28 | #include <linux/list.h> | 28 | #include <linux/list.h> |
29 | #include <linux/mm.h> | 29 | #include <linux/mm.h> |
30 | #include <asm/pgtable.h> | ||
30 | #include <asm/io.h> | 31 | #include <asm/io.h> |
31 | 32 | ||
32 | /* | 33 | /* |
@@ -75,12 +76,13 @@ static struct class *bsr_class; | |||
75 | static int bsr_major; | 76 | static int bsr_major; |
76 | 77 | ||
77 | enum { | 78 | enum { |
78 | BSR_8 = 0, | 79 | BSR_8 = 0, |
79 | BSR_16 = 1, | 80 | BSR_16 = 1, |
80 | BSR_64 = 2, | 81 | BSR_64 = 2, |
81 | BSR_128 = 3, | 82 | BSR_128 = 3, |
82 | BSR_UNKNOWN = 4, | 83 | BSR_4096 = 4, |
83 | BSR_MAX = 5, | 84 | BSR_UNKNOWN = 5, |
85 | BSR_MAX = 6, | ||
84 | }; | 86 | }; |
85 | 87 | ||
86 | static unsigned bsr_types[BSR_MAX]; | 88 | static unsigned bsr_types[BSR_MAX]; |
@@ -117,15 +119,22 @@ static int bsr_mmap(struct file *filp, struct vm_area_struct *vma) | |||
117 | { | 119 | { |
118 | unsigned long size = vma->vm_end - vma->vm_start; | 120 | unsigned long size = vma->vm_end - vma->vm_start; |
119 | struct bsr_dev *dev = filp->private_data; | 121 | struct bsr_dev *dev = filp->private_data; |
122 | int ret; | ||
120 | 123 | ||
121 | if (size > dev->bsr_len || (size & (PAGE_SIZE-1))) | ||
122 | return -EINVAL; | ||
123 | |||
124 | vma->vm_flags |= (VM_IO | VM_DONTEXPAND); | ||
125 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | 124 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); |
126 | 125 | ||
127 | if (io_remap_pfn_range(vma, vma->vm_start, dev->bsr_addr >> PAGE_SHIFT, | 126 | /* check for the case of a small BSR device and map one 4k page for it*/ |
128 | size, vma->vm_page_prot)) | 127 | if (dev->bsr_len < PAGE_SIZE && size == PAGE_SIZE) |
128 | ret = remap_4k_pfn(vma, vma->vm_start, dev->bsr_addr >> 12, | ||
129 | vma->vm_page_prot); | ||
130 | else if (size <= dev->bsr_len) | ||
131 | ret = io_remap_pfn_range(vma, vma->vm_start, | ||
132 | dev->bsr_addr >> PAGE_SHIFT, | ||
133 | size, vma->vm_page_prot); | ||
134 | else | ||
135 | return -EINVAL; | ||
136 | |||
137 | if (ret) | ||
129 | return -EAGAIN; | 138 | return -EAGAIN; |
130 | 139 | ||
131 | return 0; | 140 | return 0; |
@@ -205,6 +214,11 @@ static int bsr_add_node(struct device_node *bn) | |||
205 | cur->bsr_stride = bsr_stride[i]; | 214 | cur->bsr_stride = bsr_stride[i]; |
206 | cur->bsr_dev = MKDEV(bsr_major, i + total_bsr_devs); | 215 | cur->bsr_dev = MKDEV(bsr_major, i + total_bsr_devs); |
207 | 216 | ||
217 | /* if we have a bsr_len of > 4k and less then PAGE_SIZE (64k pages) */ | ||
218 | /* we can only map 4k of it, so only advertise the 4k in sysfs */ | ||
219 | if (cur->bsr_len > 4096 && cur->bsr_len < PAGE_SIZE) | ||
220 | cur->bsr_len = 4096; | ||
221 | |||
208 | switch(cur->bsr_bytes) { | 222 | switch(cur->bsr_bytes) { |
209 | case 8: | 223 | case 8: |
210 | cur->bsr_type = BSR_8; | 224 | cur->bsr_type = BSR_8; |
@@ -218,9 +232,11 @@ static int bsr_add_node(struct device_node *bn) | |||
218 | case 128: | 232 | case 128: |
219 | cur->bsr_type = BSR_128; | 233 | cur->bsr_type = BSR_128; |
220 | break; | 234 | break; |
235 | case 4096: | ||
236 | cur->bsr_type = BSR_4096; | ||
237 | break; | ||
221 | default: | 238 | default: |
222 | cur->bsr_type = BSR_UNKNOWN; | 239 | cur->bsr_type = BSR_UNKNOWN; |
223 | printk(KERN_INFO "unknown BSR size %d\n",cur->bsr_bytes); | ||
224 | } | 240 | } |
225 | 241 | ||
226 | cur->bsr_num = bsr_types[cur->bsr_type]; | 242 | cur->bsr_num = bsr_types[cur->bsr_type]; |