Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* sbuslib.c: Helper library for SBUS framebuffer drivers. |
2 | * | |
3 | * Copyright (C) 2003 David S. Miller (davem@redhat.com) | |
4 | */ | |
5 | ||
6 | #include <linux/kernel.h> | |
7 | #include <linux/module.h> | |
8 | #include <linux/string.h> | |
9 | #include <linux/fb.h> | |
10 | #include <linux/mm.h> | |
11 | ||
12 | #include <asm/oplib.h> | |
13 | #include <asm/fbio.h> | |
14 | ||
15 | #include "sbuslib.h" | |
16 | ||
17 | void sbusfb_fill_var(struct fb_var_screeninfo *var, int prom_node, int bpp) | |
18 | { | |
19 | memset(var, 0, sizeof(*var)); | |
20 | ||
21 | var->xres = prom_getintdefault(prom_node, "width", 1152); | |
22 | var->yres = prom_getintdefault(prom_node, "height", 900); | |
23 | var->xres_virtual = var->xres; | |
24 | var->yres_virtual = var->yres; | |
25 | var->bits_per_pixel = bpp; | |
26 | } | |
27 | ||
28 | EXPORT_SYMBOL(sbusfb_fill_var); | |
29 | ||
30 | static unsigned long sbusfb_mmapsize(long size, unsigned long fbsize) | |
31 | { | |
32 | if (size == SBUS_MMAP_EMPTY) return 0; | |
33 | if (size >= 0) return size; | |
34 | return fbsize * (-size); | |
35 | } | |
36 | ||
37 | int sbusfb_mmap_helper(struct sbus_mmap_map *map, | |
38 | unsigned long physbase, | |
39 | unsigned long fbsize, | |
40 | unsigned long iospace, | |
41 | struct vm_area_struct *vma) | |
42 | { | |
43 | unsigned int size, page, r, map_size; | |
44 | unsigned long map_offset = 0; | |
45 | unsigned long off; | |
46 | int i; | |
47 | ||
48 | size = vma->vm_end - vma->vm_start; | |
49 | if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) | |
50 | return -EINVAL; | |
51 | ||
52 | off = vma->vm_pgoff << PAGE_SHIFT; | |
53 | ||
54 | /* To stop the swapper from even considering these pages */ | |
55 | vma->vm_flags |= (VM_IO | VM_RESERVED); | |
56 | ||
57 | /* Each page, see which map applies */ | |
58 | for (page = 0; page < size; ){ | |
59 | map_size = 0; | |
60 | for (i = 0; map[i].size; i++) | |
61 | if (map[i].voff == off+page) { | |
62 | map_size = sbusfb_mmapsize(map[i].size, fbsize); | |
63 | #ifdef __sparc_v9__ | |
64 | #define POFF_MASK (PAGE_MASK|0x1UL) | |
65 | #else | |
66 | #define POFF_MASK (PAGE_MASK) | |
67 | #endif | |
68 | map_offset = (physbase + map[i].poff) & POFF_MASK; | |
69 | break; | |
70 | } | |
71 | if (!map_size){ | |
72 | page += PAGE_SIZE; | |
73 | continue; | |
74 | } | |
75 | if (page + map_size > size) | |
76 | map_size = size - page; | |
77 | r = io_remap_pfn_range(vma, | |
78 | vma->vm_start + page, | |
79 | MK_IOSPACE_PFN(iospace, | |
80 | map_offset >> PAGE_SHIFT), | |
81 | map_size, | |
82 | vma->vm_page_prot); | |
83 | if (r) | |
84 | return -EAGAIN; | |
85 | page += map_size; | |
86 | } | |
87 | ||
88 | return 0; | |
89 | } | |
90 | EXPORT_SYMBOL(sbusfb_mmap_helper); | |
91 | ||
92 | int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg, | |
93 | struct fb_info *info, | |
94 | int type, int fb_depth, unsigned long fb_size) | |
95 | { | |
96 | switch(cmd) { | |
97 | case FBIOGTYPE: { | |
98 | struct fbtype __user *f = (struct fbtype __user *) arg; | |
99 | ||
100 | if (put_user(type, &f->fb_type) || | |
101 | __put_user(info->var.yres, &f->fb_height) || | |
102 | __put_user(info->var.xres, &f->fb_width) || | |
103 | __put_user(fb_depth, &f->fb_depth) || | |
104 | __put_user(0, &f->fb_cmsize) || | |
105 | __put_user(fb_size, &f->fb_cmsize)) | |
106 | return -EFAULT; | |
107 | return 0; | |
108 | } | |
109 | case FBIOPUTCMAP_SPARC: { | |
110 | struct fbcmap __user *c = (struct fbcmap __user *) arg; | |
111 | struct fb_cmap cmap; | |
112 | u16 red, green, blue; | |
113 | u8 red8, green8, blue8; | |
114 | unsigned char __user *ured; | |
115 | unsigned char __user *ugreen; | |
116 | unsigned char __user *ublue; | |
117 | int index, count, i; | |
118 | ||
119 | if (get_user(index, &c->index) || | |
120 | __get_user(count, &c->count) || | |
121 | __get_user(ured, &c->red) || | |
122 | __get_user(ugreen, &c->green) || | |
123 | __get_user(ublue, &c->blue)) | |
124 | return -EFAULT; | |
125 | ||
126 | cmap.len = 1; | |
127 | cmap.red = &red; | |
128 | cmap.green = &green; | |
129 | cmap.blue = &blue; | |
130 | cmap.transp = NULL; | |
131 | for (i = 0; i < count; i++) { | |
132 | int err; | |
133 | ||
134 | if (get_user(red8, &ured[i]) || | |
135 | get_user(green8, &ugreen[i]) || | |
136 | get_user(blue8, &ublue[i])) | |
137 | return -EFAULT; | |
138 | ||
139 | red = red8 << 8; | |
140 | green = green8 << 8; | |
141 | blue = blue8 << 8; | |
142 | ||
143 | cmap.start = index + i; | |
144 | err = fb_set_cmap(&cmap, info); | |
145 | if (err) | |
146 | return err; | |
147 | } | |
148 | return 0; | |
149 | } | |
150 | case FBIOGETCMAP_SPARC: { | |
151 | struct fbcmap __user *c = (struct fbcmap __user *) arg; | |
152 | unsigned char __user *ured; | |
153 | unsigned char __user *ugreen; | |
154 | unsigned char __user *ublue; | |
155 | struct fb_cmap *cmap = &info->cmap; | |
156 | int index, count, i; | |
157 | u8 red, green, blue; | |
158 | ||
159 | if (get_user(index, &c->index) || | |
160 | __get_user(count, &c->count) || | |
161 | __get_user(ured, &c->red) || | |
162 | __get_user(ugreen, &c->green) || | |
163 | __get_user(ublue, &c->blue)) | |
164 | return -EFAULT; | |
165 | ||
166 | if (index + count > cmap->len) | |
167 | return -EINVAL; | |
168 | ||
169 | for (i = 0; i < count; i++) { | |
170 | red = cmap->red[index + i] >> 8; | |
171 | green = cmap->green[index + i] >> 8; | |
172 | blue = cmap->blue[index + i] >> 8; | |
173 | if (put_user(red, &ured[i]) || | |
174 | put_user(green, &ugreen[i]) || | |
175 | put_user(blue, &ublue[i])) | |
176 | return -EFAULT; | |
177 | } | |
178 | return 0; | |
179 | } | |
180 | default: | |
181 | return -EINVAL; | |
182 | }; | |
183 | } | |
184 | EXPORT_SYMBOL(sbusfb_ioctl_helper); |