This source file includes following definitions.
- PROC_CONSOLE
- fb_read
- fb_write
- fb_ioctl
- fb_mmap
- fb_open
- fb_release
- register_framebuffer
- unregister_framebuffer
- fbmem_init
1
2
3
4
5
6
7
8
9
10
11 #include <linux/types.h>
12 #include <linux/errno.h>
13 #include <linux/sched.h>
14 #include <linux/kernel.h>
15 #include <linux/major.h>
16 #include <linux/malloc.h>
17 #include <linux/mman.h>
18 #include <linux/tty.h>
19
20 #include <asm/segment.h>
21 #include <asm/bootinfo.h>
22 #include <asm/page.h>
23 #include <asm/pgtable.h>
24
25 #include <linux/fb.h>
26
27 #define FB_MAJOR 29
28
29 #define FB_MODES_SHIFT 5
30 #define FB_NUM_MINORS 256
31 #define FB_MAX (FB_NUM_MINORS / (1 << FB_MODES_SHIFT))
32
33 #define GET_INODE(i) MKDEV(FB_MAJOR, (i) << FB_MODES_SHIFT)
34 #define GET_FB_IDX(node) (MINOR(node) >> FB_MODES_SHIFT)
35 #define GET_FB_VAR_IDX(node) (MINOR(node) & ((1 << FB_MODES_SHIFT)-1))
36
37 struct fb_ops *registered_fb[FB_MAX];
38 struct fb_var_screeninfo *registered_fb_var[FB_MAX];
39 int registered_fb_var_num[FB_MAX];
40 int fb_curr_open[FB_MAX];
41 int fb_open_count[FB_MAX];
42
43 static inline int PROC_CONSOLE(void)
44 {
45 if (!current->tty)
46 return fg_console;
47
48 if (MINOR(current->tty->device) < 1)
49 return fg_console;
50
51 return MINOR(current->tty->device) - 1;
52 }
53
54 static int
55 fb_read(struct inode *inode, struct file *file, char *buf, int count)
56 {
57 unsigned long p = file->f_pos;
58 struct fb_ops *fb = registered_fb[GET_FB_IDX(inode->i_rdev)];
59 struct fb_fix_screeninfo fix;
60 char *base_addr;
61 int copy_size;
62
63 if (! fb)
64 return -ENODEV;
65 if (count < 0)
66 return -EINVAL;
67
68 fb->fb_get_fix(&fix,PROC_CONSOLE());
69 base_addr=(char *) fix.smem_start;
70 copy_size=(count + p <= fix.smem_len ? count : fix.smem_len - p);
71 memcpy_tofs(buf, base_addr+p, copy_size);
72 file->f_pos += copy_size;
73 return copy_size;
74 }
75
76 static int
77 fb_write(struct inode *inode, struct file *file, const char *buf, int count)
78 {
79 unsigned long p = file->f_pos;
80 struct fb_ops *fb = registered_fb[GET_FB_IDX(inode->i_rdev)];
81 struct fb_fix_screeninfo fix;
82 char *base_addr;
83 int copy_size;
84
85 if (! fb)
86 return -ENODEV;
87 if (count < 0)
88 return -EINVAL;
89 fb->fb_get_fix(&fix, PROC_CONSOLE());
90 base_addr=(char *) fix.smem_start;
91 copy_size=(count + p <= fix.smem_len ? count : fix.smem_len - p);
92 memcpy_fromfs(base_addr+p, buf, copy_size);
93 file->f_pos += copy_size;
94 return copy_size;
95 }
96
97
98 static int
99 fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
100 unsigned long arg)
101 {
102 struct fb_ops *fb = registered_fb[GET_FB_IDX(inode->i_rdev)];
103 struct fb_cmap cmap;
104 struct fb_var_screeninfo var;
105 struct fb_fix_screeninfo fix;
106
107 int i,fbidx,vidx;
108
109 if (! fb)
110 return -ENODEV;
111 switch (cmd) {
112 case FBIOGET_VSCREENINFO:
113 i = verify_area(VERIFY_WRITE, (void *) arg,
114 sizeof(struct fb_var_screeninfo));
115 if (i) return i;
116 fbidx=GET_FB_IDX(inode->i_rdev);
117 vidx=GET_FB_VAR_IDX(inode->i_rdev);
118 if (! vidx)
119 i=fb->fb_get_var(&var, PROC_CONSOLE());
120 else
121 var=registered_fb_var[fbidx][vidx-1];
122 memcpy_tofs((void *) arg, &var, sizeof(var));
123 return i;
124 case FBIOPUT_VSCREENINFO:
125 i = verify_area(VERIFY_WRITE, (void *) arg,
126 sizeof(struct fb_var_screeninfo));
127 if (i) return i;
128 memcpy_fromfs(&var, (void *) arg, sizeof(var));
129 i=fb->fb_set_var(&var, PROC_CONSOLE());
130 memcpy_tofs((void *) arg, &var, sizeof(var));
131 fbidx=GET_FB_IDX(inode->i_rdev);
132 vidx=GET_FB_VAR_IDX(inode->i_rdev);
133 if (! i && vidx)
134 registered_fb_var[fbidx][vidx-1]=var;
135 return i;
136 case FBIOGET_FSCREENINFO:
137 i = verify_area(VERIFY_WRITE, (void *) arg,
138 sizeof(struct fb_fix_screeninfo));
139 if (i) return i;
140 i=fb->fb_get_fix(&fix, PROC_CONSOLE());
141 memcpy_tofs((void *) arg, &fix, sizeof(fix));
142 return i;
143 case FBIOPUTCMAP:
144 i = verify_area(VERIFY_READ, (void *) arg,
145 sizeof(struct fb_cmap));
146 if (i) return i;
147 memcpy_fromfs(&cmap, (void *) arg, sizeof(cmap));
148 i = verify_area(VERIFY_READ, (void *) cmap.red,
149 cmap.len * sizeof(unsigned short));
150 if (i) return i;
151 i = verify_area(VERIFY_READ, (void *) cmap.green,
152 cmap.len * sizeof(unsigned short));
153 if (i) return i;
154 i = verify_area(VERIFY_READ, (void *) cmap.blue,
155 cmap.len * sizeof(unsigned short));
156 if (i) return i;
157 if (cmap.transp) {
158 i = verify_area(VERIFY_READ, (void *) cmap.transp,
159 cmap.len * sizeof(unsigned short));
160 if (i) return i;
161 }
162 return (fb->fb_set_cmap(&cmap, 0, PROC_CONSOLE()));
163 case FBIOGETCMAP:
164 i = verify_area(VERIFY_READ, (void *) arg,
165 sizeof(struct fb_cmap));
166 if (i) return i;
167 memcpy_fromfs(&cmap, (void *) arg, sizeof(cmap));
168 i = verify_area(VERIFY_WRITE, (void *) cmap.red,
169 cmap.len * sizeof(unsigned short));
170 if (i) return i;
171 i = verify_area(VERIFY_WRITE, (void *) cmap.green,
172 cmap.len * sizeof(unsigned short));
173 if (i) return i;
174 i = verify_area(VERIFY_WRITE, (void *) cmap.blue,
175 cmap.len * sizeof(unsigned short));
176 if (i) return i;
177 if (cmap.transp) {
178 i = verify_area(VERIFY_WRITE, (void *) cmap.transp,
179 cmap.len * sizeof(unsigned short));
180 if (i) return i;
181 }
182 return (fb->fb_get_cmap(&cmap, 0, PROC_CONSOLE()));
183 default:
184 return (fb->fb_ioctl(inode, file, cmd, arg, PROC_CONSOLE()));
185 }
186 }
187
188 static int
189 fb_mmap(struct inode *inode, struct file *file, struct vm_area_struct * vma)
190 {
191 struct fb_ops *fb = registered_fb[GET_FB_IDX(inode->i_rdev)];
192 struct fb_fix_screeninfo fix;
193
194 if (! fb)
195 return -ENODEV;
196 fb->fb_get_fix(&fix, PROC_CONSOLE());
197 if ((vma->vm_end - vma->vm_start + vma->vm_offset) > fix.smem_len)
198 return -EINVAL;
199 vma->vm_offset += fix.smem_start;
200 if (vma->vm_offset & ~PAGE_MASK)
201 return -ENXIO;
202 if (boot_info.cputype & CPU_68040)
203 pgprot_val(vma->vm_page_prot) &= _CACHEMASK040;
204 if (remap_page_range(vma->vm_start, vma->vm_offset,
205 vma->vm_end - vma->vm_start, vma->vm_page_prot))
206 return -EAGAIN;
207 vma->vm_inode = inode;
208 inode->i_count++;
209 return 0;
210 }
211
212 static int
213 fb_open(struct inode *inode, struct file *file)
214 {
215 int fbidx=GET_FB_IDX(inode->i_rdev);
216 int vidx=GET_FB_VAR_IDX(inode->i_rdev);
217 struct fb_ops *fb = registered_fb[fbidx];
218 int err;
219
220 if (! vidx)
221 return 0;
222 if (vidx > registered_fb_var_num[fbidx])
223 return -EINVAL;
224 if (fb_curr_open[fbidx] && fb_curr_open[fbidx] != vidx)
225 return -EBUSY;
226 if (file->f_mode & 2)
227 if ((err=fb->fb_set_var(registered_fb_var[fbidx] + vidx-1, PROC_CONSOLE())))
228 return err;
229 fb_curr_open[fbidx] = vidx;
230 fb_open_count[fbidx]++;
231 return 0;
232 }
233
234 static void
235 fb_release(struct inode *inode, struct file *file)
236 {
237 int fbidx=GET_FB_IDX(inode->i_rdev);
238 int vidx=GET_FB_VAR_IDX(inode->i_rdev);
239 if (! vidx)
240 return;
241 if (! (--fb_open_count[fbidx]))
242 fb_curr_open[fbidx]=0;
243 }
244
245 static struct file_operations fb_fops = {
246 NULL,
247 fb_read,
248 fb_write,
249 NULL,
250 NULL,
251 fb_ioctl,
252 fb_mmap,
253 fb_open,
254 fb_release,
255 NULL
256 };
257
258 int
259 register_framebuffer(char *id, int *node, struct fb_ops *fbops, int fbvar_num,
260 struct fb_var_screeninfo *fbvar)
261 {
262 int i;
263 for (i = 0 ; i < FB_MAX; i++)
264 if (! registered_fb[i])
265 break;
266 if (i == FB_MAX)
267 return -ENXIO;
268 registered_fb[i]=fbops;
269 registered_fb_var[i]=fbvar;
270 registered_fb_var_num[i]=fbvar_num;
271 *node=GET_INODE(i);
272 return 0;
273 }
274
275 int
276 unregister_framebuffer(int node)
277 {
278 int i=GET_FB_IDX(node);
279 if (! registered_fb[i])
280 return -EINVAL;
281 registered_fb[i]=NULL;
282 registered_fb_var[i]=NULL;
283 return 0;
284 }
285
286 void
287 fbmem_init(void)
288 {
289 if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
290 printk("unable to get major %d for fb devs\n", FB_MAJOR);
291 }
292