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]; |
