Mercurial > mplayer.hg
comparison drivers/tdfx_vid.c @ 9545:d1bbeae9f46a
tdfx_vid a new kernel driver for tdfx wich let use agp move :)
author | albeu |
---|---|
date | Fri, 07 Mar 2003 18:42:08 +0000 |
parents | |
children | 29aa61268e54 |
comparison
equal
deleted
inserted
replaced
9544:97f61ffa441e | 9545:d1bbeae9f46a |
---|---|
1 | |
2 #include <linux/config.h> | |
3 #include <linux/version.h> | |
4 #include <linux/module.h> | |
5 #include <linux/types.h> | |
6 #include <linux/kernel.h> | |
7 #include <linux/sched.h> | |
8 #include <linux/mm.h> | |
9 #include <linux/string.h> | |
10 #include <linux/errno.h> | |
11 | |
12 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) | |
13 #include <linux/malloc.h> | |
14 #else | |
15 #include <linux/slab.h> | |
16 #endif | |
17 | |
18 #include <linux/pci.h> | |
19 #include <linux/ioport.h> | |
20 #include <linux/init.h> | |
21 #include <linux/agp_backend.h> | |
22 | |
23 #include <asm/uaccess.h> | |
24 #include <asm/system.h> | |
25 #include <asm/io.h> | |
26 | |
27 #include "tdfx_vid.h" | |
28 #include "3dfx.h" | |
29 | |
30 | |
31 #define TDFX_VID_MAJOR 178 | |
32 | |
33 MODULE_AUTHOR("Albeu"); | |
34 | |
35 #ifdef MODULE_LICENSE | |
36 MODULE_LICENSE("GPL"); | |
37 #endif | |
38 | |
39 #ifndef min | |
40 #define min(x,y) (((x)<(y))?(x):(y)) | |
41 #endif | |
42 | |
43 static struct pci_dev *pci_dev; | |
44 | |
45 static uint8_t *tdfx_mmio_base = 0; | |
46 static uint32_t tdfx_mem_base = 0; | |
47 static struct voodoo_2d_reg_t* tdfx_2d_regs = NULL; | |
48 | |
49 static int tdfx_ram_size = 0; | |
50 | |
51 static int tdfx_vid_in_use = 0; | |
52 | |
53 static drm_agp_t *drm_agp = NULL; | |
54 static agp_kern_info agp_info; | |
55 static agp_memory *agp_mem = NULL; | |
56 | |
57 | |
58 | |
59 static inline u32 tdfx_inl(unsigned int reg) { | |
60 return readl(tdfx_mmio_base + reg); | |
61 } | |
62 | |
63 static inline void tdfx_outl(unsigned int reg, u32 val) { | |
64 writel(val,tdfx_mmio_base + reg); | |
65 } | |
66 | |
67 static inline void banshee_make_room(int size) { | |
68 while((tdfx_inl(STATUS) & 0x1f) < size); | |
69 } | |
70 | |
71 static inline void banshee_wait_idle(void) { | |
72 int i = 0; | |
73 | |
74 banshee_make_room(1); | |
75 tdfx_outl(COMMAND_3D, COMMAND_3D_NOP); | |
76 | |
77 while(1) { | |
78 i = (tdfx_inl(STATUS) & STATUS_BUSY) ? 0 : i + 1; | |
79 if(i == 3) break; | |
80 } | |
81 } | |
82 | |
83 static unsigned long get_lfb_size(void) { | |
84 u32 draminit0 = 0; | |
85 u32 draminit1 = 0; | |
86 // u32 miscinit1 = 0; | |
87 u32 lfbsize = 0; | |
88 int sgram_p = 0; | |
89 | |
90 draminit0 = tdfx_inl(DRAMINIT0); | |
91 draminit1 = tdfx_inl(DRAMINIT1); | |
92 | |
93 if ((pci_dev->device == PCI_DEVICE_ID_3DFX_BANSHEE) || | |
94 (pci_dev->device == PCI_DEVICE_ID_3DFX_VOODOO3)) { | |
95 sgram_p = (draminit1 & DRAMINIT1_MEM_SDRAM) ? 0 : 1; | |
96 | |
97 lfbsize = sgram_p ? | |
98 (((draminit0 & DRAMINIT0_SGRAM_NUM) ? 2 : 1) * | |
99 ((draminit0 & DRAMINIT0_SGRAM_TYPE) ? 8 : 4) * 1024 * 1024) : | |
100 16 * 1024 * 1024; | |
101 } else { | |
102 /* Voodoo4/5 */ | |
103 u32 chips, psize, banks; | |
104 | |
105 chips = ((draminit0 & (1 << 26)) == 0) ? 4 : 8; | |
106 psize = 1 << ((draminit0 & 0x38000000) >> 28); | |
107 banks = ((draminit0 & (1 << 30)) == 0) ? 2 : 4; | |
108 lfbsize = chips * psize * banks; | |
109 lfbsize <<= 20; | |
110 } | |
111 | |
112 #if 0 | |
113 /* disable block writes for SDRAM (why?) */ | |
114 miscinit1 = tdfx_inl(MISCINIT1); | |
115 miscinit1 |= sgram_p ? 0 : MISCINIT1_2DBLOCK_DIS; | |
116 miscinit1 |= MISCINIT1_CLUT_INV; | |
117 | |
118 banshee_make_room(1); | |
119 tdfx_outl(MISCINIT1, miscinit1); | |
120 #endif | |
121 | |
122 return lfbsize; | |
123 } | |
124 | |
125 static int tdfx_vid_find_card(void) | |
126 { | |
127 struct pci_dev *dev = NULL; | |
128 // unsigned int card_option; | |
129 | |
130 if((dev = pci_find_device(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_BANSHEE, NULL))) | |
131 printk(KERN_INFO "tdfx_vid: Found VOODOO BANSHEE\n"); | |
132 else if((dev = pci_find_device(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO3, NULL))) | |
133 printk(KERN_INFO "tdfx_vid: Found VOODOO 3 \n"); | |
134 else | |
135 return 0; | |
136 | |
137 | |
138 pci_dev = dev; | |
139 | |
140 #if LINUX_VERSION_CODE >= 0x020300 | |
141 tdfx_mmio_base = ioremap_nocache(dev->resource[0].start,1 << 24); | |
142 tdfx_mem_base = dev->resource[1].start; | |
143 #else | |
144 tdfx_mmio_base = ioremap_nocache(dev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK,0x4000); | |
145 tdfx_mem_base = dev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK; | |
146 #endif | |
147 printk(KERN_INFO "tdfx_vid: MMIO at 0x%p\n", tdfx_mmio_base); | |
148 tdfx_2d_regs = (struct voodoo_2d_reg_t*)tdfx_mmio_base; | |
149 tdfx_ram_size = get_lfb_size(); | |
150 | |
151 printk(KERN_INFO "tdfx_vid: Found %d MB (%d bytes) of memory\n", | |
152 tdfx_ram_size / 1024 / 1024,tdfx_ram_size); | |
153 | |
154 | |
155 #if 0 | |
156 { | |
157 int temp; | |
158 printk("List resources -----------\n"); | |
159 for(temp=0;temp<DEVICE_COUNT_RESOURCE;temp++){ | |
160 struct resource *res=&pci_dev->resource[temp]; | |
161 if(res->flags){ | |
162 int size=(1+res->end-res->start)>>20; | |
163 printk(KERN_DEBUG "res %d: start: 0x%X end: 0x%X (%d MB) flags=0x%X\n",temp,res->start,res->end,size,res->flags); | |
164 if(res->flags&(IORESOURCE_MEM|IORESOURCE_PREFETCH)){ | |
165 if(size>tdfx_ram_size && size<=64) tdfx_ram_size=size; | |
166 } | |
167 } | |
168 } | |
169 } | |
170 #endif | |
171 | |
172 | |
173 return 1; | |
174 } | |
175 | |
176 static int agp_init(void) { | |
177 | |
178 drm_agp = (drm_agp_t*)inter_module_get("drm_agp"); | |
179 | |
180 if(!drm_agp) { | |
181 printk(KERN_ERR "tdfx_vid: Unable to get drm_agp pointer\n"); | |
182 return 0; | |
183 } | |
184 | |
185 if(drm_agp->acquire()) { | |
186 printk(KERN_ERR "tdfx_vid: Unable to acquire the agp backend\n"); | |
187 drm_agp = NULL; | |
188 return 0; | |
189 } | |
190 | |
191 drm_agp->copy_info(&agp_info); | |
192 #if 0 | |
193 printk(KERN_DEBUG "AGP Version : %d %d\n" | |
194 "AGP Mode: %#X\nAperture Base: %p\nAperture Size: %d\n" | |
195 "Max memory = %d\nCurrent mem = %d\nCan use perture : %s\n" | |
196 "Page mask = %#X\n", | |
197 agp_info.version.major,agp_info.version.minor, | |
198 agp_info.mode,agp_info.aper_base,agp_info.aper_size, | |
199 agp_info.max_memory,agp_info.current_memory, | |
200 agp_info.cant_use_aperture ? "no" : "yes", | |
201 agp_info.page_mask); | |
202 #endif | |
203 drm_agp->enable(agp_info.mode); | |
204 | |
205 | |
206 printk(KERN_INFO "AGP Enabled\n"); | |
207 | |
208 return 1; | |
209 } | |
210 | |
211 static void agp_close(void) { | |
212 | |
213 if(!drm_agp) return; | |
214 | |
215 if(agp_mem) { | |
216 drm_agp->unbind_memory(agp_mem); | |
217 drm_agp->free_memory(agp_mem); | |
218 agp_mem = NULL; | |
219 } | |
220 | |
221 | |
222 drm_agp->release(); | |
223 | |
224 } | |
225 | |
226 static int agp_move(tdfx_vid_agp_move_t* m) { | |
227 // u32 mov = 0; | |
228 u32 src = 0; | |
229 u32 src_h,src_l; | |
230 | |
231 if(!agp_mem) | |
232 return (-EAGAIN); | |
233 | |
234 if(m->move2 > 3) { | |
235 printk(KERN_DEBUG "tdfx_vid: AGP move invalid destination %d\n", | |
236 m->move2); | |
237 return (-EAGAIN); | |
238 } | |
239 | |
240 | |
241 src = agp_info.aper_base + m->src; | |
242 | |
243 src_l = (u32)src; | |
244 src_h = (m->width | (m->src_stride << 14)) & 0x0FFFFFFF; | |
245 | |
246 // banshee_wait_idle(); | |
247 banshee_make_room(6); | |
248 tdfx_outl(AGPHOSTADDRESSHIGH,src_h); | |
249 tdfx_outl(AGPHOSTADDRESSLOW,src_l); | |
250 | |
251 tdfx_outl(AGPGRAPHICSADDRESS, m->dst); | |
252 tdfx_outl(AGPGRAPHICSSTRIDE, m->dst_stride); | |
253 tdfx_outl(AGPREQSIZE,m->src_stride*m->height); | |
254 | |
255 tdfx_outl(AGPMOVECMD,m->move2 << 3); | |
256 banshee_wait_idle(); | |
257 | |
258 banshee_make_room(5); | |
259 tdfx_outl(AGPHOSTADDRESSHIGH,0); | |
260 tdfx_outl(AGPHOSTADDRESSLOW,0); | |
261 | |
262 tdfx_outl(AGPGRAPHICSADDRESS,0); | |
263 tdfx_outl(AGPGRAPHICSSTRIDE,0); | |
264 tdfx_outl(AGPREQSIZE,0); | |
265 banshee_wait_idle(); | |
266 | |
267 return 0; | |
268 } | |
269 | |
270 static void setup_fifo(u32 offset,ssize_t pages) { | |
271 long addr = agp_info.aper_base + offset; | |
272 u32 size = pages | 0x700; // fifo on, in agp mem, disable hole cnt | |
273 | |
274 banshee_wait_idle(); | |
275 | |
276 tdfx_outl(CMDBASEADDR0,addr >> 4); | |
277 tdfx_outl(CMDRDPTRL0, addr << 4); | |
278 tdfx_outl(CMDRDPTRH0, addr >> 28); | |
279 tdfx_outl(CMDAMIN0, (addr - 4) & 0xFFFFFF); | |
280 tdfx_outl(CMDAMAX0, (addr - 4) & 0xFFFFFF); | |
281 tdfx_outl(CMDFIFODEPTH0, 0); | |
282 tdfx_outl(CMDHOLECNT0, 0); | |
283 tdfx_outl(CMDBASESIZE0,size); | |
284 | |
285 banshee_wait_idle(); | |
286 | |
287 } | |
288 | |
289 static int bump_fifo(u16 size) { | |
290 | |
291 banshee_wait_idle(); | |
292 tdfx_outl(CMDBUMP0 , size); | |
293 banshee_wait_idle(); | |
294 | |
295 return 0; | |
296 } | |
297 | |
298 static void tdfx_vid_get_config(tdfx_vid_config_t* cfg) { | |
299 u32 in; | |
300 | |
301 cfg->version = TDFX_VID_VERSION; | |
302 cfg->ram_size = tdfx_ram_size; | |
303 | |
304 in = tdfx_inl(VIDSCREENSIZE); | |
305 cfg->screen_width = in & 0xFFF; | |
306 cfg->screen_height = (in >> 12) & 0xFFF; | |
307 in = (tdfx_inl(VIDPROCCFG)>> 18)& 0x7; | |
308 switch(in) { | |
309 case 0: | |
310 cfg->screen_format = TDFX_VID_FORMAT_BGR8; | |
311 break; | |
312 case 1: | |
313 cfg->screen_format = TDFX_VID_FORMAT_BGR16; | |
314 break; | |
315 case 2: | |
316 cfg->screen_format = TDFX_VID_FORMAT_BGR24; | |
317 break; | |
318 case 3: | |
319 cfg->screen_format = TDFX_VID_FORMAT_BGR32; | |
320 break; | |
321 default: | |
322 printk(KERN_INFO "tdfx_vid: unknow screen format %d\n",in); | |
323 cfg->screen_format = 0; | |
324 break; | |
325 } | |
326 cfg->screen_stride = tdfx_inl(VIDDESKSTRIDE); | |
327 cfg->screen_start = tdfx_inl(VIDDESKSTART); | |
328 } | |
329 | |
330 inline static u32 tdfx_vid_make_format(int src,u16 stride,u32 fmt) { | |
331 u32 r = stride & 0xFFF3; | |
332 u32 tdfx_fmt = 0; | |
333 | |
334 // src and dest formats | |
335 switch(fmt) { | |
336 case TDFX_VID_FORMAT_BGR8: | |
337 tdfx_fmt = 1; | |
338 break; | |
339 case TDFX_VID_FORMAT_BGR16: | |
340 tdfx_fmt = 3; | |
341 break; | |
342 case TDFX_VID_FORMAT_BGR24: | |
343 tdfx_fmt = 4; | |
344 break; | |
345 case TDFX_VID_FORMAT_BGR32: | |
346 tdfx_fmt = 5; | |
347 break; | |
348 } | |
349 | |
350 if(!src && !tdfx_fmt) { | |
351 printk(KERN_INFO "tdfx_vid: Invalid destination format %#X\n",fmt); | |
352 return 0; | |
353 } | |
354 | |
355 if(src && !tdfx_fmt) { | |
356 // src only format | |
357 switch(fmt){ | |
358 case TDFX_VID_FORMAT_BGR1: | |
359 tdfx_fmt = 0; | |
360 break; | |
361 case TDFX_VID_FORMAT_YUY2: | |
362 tdfx_fmt = 8; | |
363 break; | |
364 case TDFX_VID_FORMAT_UYVY: | |
365 tdfx_fmt = 9; | |
366 break; | |
367 default: | |
368 printk(KERN_INFO "tdfx_vid: Invalid source format %#X\n",fmt); | |
369 return 0; | |
370 } | |
371 } | |
372 | |
373 r |= tdfx_fmt << 16; | |
374 | |
375 return r; | |
376 } | |
377 | |
378 static int tdfx_vid_blit(tdfx_vid_blit_t* blit) { | |
379 u32 src_fmt,dst_fmt; | |
380 u32 cmin,cmax,srcbase,srcxy,srcfmt,srcsize; | |
381 u32 dstbase,dstxy,dstfmt,dstsize; | |
382 | |
383 //printk(KERN_INFO "tdfx_vid: Make src fmt 0x%x\n",blit->src_format); | |
384 src_fmt = tdfx_vid_make_format(1,blit->src_stride,blit->src_format); | |
385 if(!src_fmt) | |
386 return 0; | |
387 //printk(KERN_INFO "tdfx_vid: Make dst fmt 0x%x\n", blit->dst_format); | |
388 dst_fmt = tdfx_vid_make_format(0,blit->dst_stride,blit->dst_format); | |
389 if(!dst_fmt) | |
390 return 0; | |
391 | |
392 // Save the regs otherwise fb get crazy | |
393 // we can perhaps avoid some ... | |
394 cmin = tdfx_inl(CLIP0MIN); | |
395 cmax = tdfx_inl(CLIP0MAX); | |
396 srcbase = tdfx_inl(SRCBASE); | |
397 srcxy = tdfx_inl(SRCXY); | |
398 srcfmt = tdfx_inl(SRCFORMAT); | |
399 srcsize = tdfx_inl(SRCSIZE); | |
400 dstbase = tdfx_inl(DSTBASE); | |
401 dstxy = tdfx_inl(DSTXY); | |
402 dstfmt = tdfx_inl(DSTFORMAT); | |
403 dstsize = tdfx_inl(DSTSIZE); | |
404 | |
405 // Get rid of the clipping at the moment | |
406 banshee_make_room(11); | |
407 | |
408 tdfx_outl(CLIP0MIN,0); | |
409 tdfx_outl(CLIP0MAX,0x0fff0fff); | |
410 | |
411 // Setup the src | |
412 tdfx_outl(SRCBASE,blit->src & 0x00FFFFFF); | |
413 tdfx_outl(SRCXY,XYREG(blit->src_x,blit->src_y)); | |
414 tdfx_outl(SRCFORMAT,src_fmt); | |
415 tdfx_outl(SRCSIZE,XYREG(blit->src_w,blit->src_h)); | |
416 | |
417 // Setup the dst | |
418 tdfx_outl(DSTBASE,blit->dst & 0x00FFFFFF); | |
419 tdfx_outl(DSTXY,XYREG(blit->dst_x,blit->dst_y)); | |
420 tdfx_outl(DSTFORMAT,dst_fmt); | |
421 tdfx_outl(DSTSIZE,XYREG(blit->dst_w,blit->dst_h)); | |
422 | |
423 // Send the command | |
424 tdfx_outl(COMMAND_2D,0xcc000102); // | (ROP_COPY << 24)); | |
425 banshee_wait_idle(); | |
426 | |
427 // Now restore the regs to make fb happy | |
428 banshee_make_room(10); | |
429 tdfx_outl(CLIP0MIN, cmin); | |
430 tdfx_outl(CLIP0MAX, cmax); | |
431 tdfx_outl(SRCBASE, srcbase); | |
432 tdfx_outl(SRCXY, srcxy); | |
433 tdfx_outl(SRCFORMAT, srcfmt); | |
434 tdfx_outl(SRCSIZE, srcsize); | |
435 tdfx_outl(DSTBASE, dstbase); | |
436 tdfx_outl(DSTXY, dstxy); | |
437 tdfx_outl(DSTFORMAT, dstfmt); | |
438 tdfx_outl(DSTSIZE, dstsize); | |
439 banshee_wait_idle(); | |
440 | |
441 return 1; | |
442 } | |
443 | |
444 static int tdfx_vid_set_yuv(unsigned long arg) { | |
445 tdfx_vid_yuv_t yuv; | |
446 | |
447 if(copy_from_user(&yuv,(tdfx_vid_yuv_t*)arg,sizeof(tdfx_vid_yuv_t))) { | |
448 printk(KERN_DEBUG "tdfx_vid:failed copy from userspace\n"); | |
449 return(-EFAULT); | |
450 } | |
451 banshee_make_room(2); | |
452 tdfx_outl(YUVBASEADDRESS,yuv.base & 0x01FFFFFF); | |
453 tdfx_outl(YUVSTRIDE, yuv.stride & 0x3FFF); | |
454 | |
455 banshee_wait_idle(); | |
456 | |
457 return 0; | |
458 } | |
459 | |
460 static int tdfx_vid_get_yuv(unsigned long arg) { | |
461 tdfx_vid_yuv_t yuv; | |
462 | |
463 yuv.base = tdfx_inl(YUVBASEADDRESS) & 0x01FFFFFF; | |
464 yuv.stride = tdfx_inl(YUVSTRIDE) & 0x3FFF; | |
465 | |
466 if(copy_to_user((tdfx_vid_yuv_t*)arg,&yuv,sizeof(tdfx_vid_yuv_t))) { | |
467 printk(KERN_INFO "tdfx_vid:failed copy to userspace\n"); | |
468 return(-EFAULT); | |
469 } | |
470 | |
471 return 0; | |
472 } | |
473 | |
474 static int tdfx_vid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) | |
475 { | |
476 tdfx_vid_agp_move_t move; | |
477 tdfx_vid_config_t cfg; | |
478 tdfx_vid_blit_t blit; | |
479 u16 int16; | |
480 | |
481 switch(cmd) { | |
482 case TDFX_VID_AGP_MOVE: | |
483 if(copy_from_user(&move,(tdfx_vid_agp_move_t*)arg,sizeof(tdfx_vid_agp_move_t))) { | |
484 printk(KERN_INFO "tdfx_vid:failed copy from userspace\n"); | |
485 return(-EFAULT); | |
486 } | |
487 return agp_move(&move); | |
488 case TDFX_VID_BUMP0: | |
489 if(copy_from_user(&int16,(u16*)arg,sizeof(u16))) { | |
490 printk(KERN_INFO "tdfx_vid:failed copy from userspace\n"); | |
491 return(-EFAULT); | |
492 } | |
493 return bump_fifo(int16); | |
494 case TDFX_VID_BLIT: | |
495 if(copy_from_user(&blit,(tdfx_vid_blit_t*)arg,sizeof(tdfx_vid_blit_t))) { | |
496 printk(KERN_INFO "tdfx_vid:failed copy from userspace\n"); | |
497 return(-EFAULT); | |
498 } | |
499 if(!tdfx_vid_blit(&blit)) { | |
500 printk(KERN_INFO "tdfx_vid: Blit failed\n"); | |
501 return(-EFAULT); | |
502 } | |
503 return 0; | |
504 case TDFX_VID_GET_CONFIG: | |
505 if(copy_from_user(&cfg,(tdfx_vid_config_t*)arg,sizeof(tdfx_vid_config_t))) { | |
506 printk(KERN_INFO "tdfx_vid:failed copy from userspace\n"); | |
507 return(-EFAULT); | |
508 } | |
509 tdfx_vid_get_config(&cfg); | |
510 if(copy_to_user((tdfx_vid_config_t*)arg,&cfg,sizeof(tdfx_vid_config_t))) { | |
511 printk(KERN_INFO "tdfx_vid:failed copy to userspace\n"); | |
512 return(-EFAULT); | |
513 } | |
514 return 0; | |
515 case TDFX_VID_SET_YUV: | |
516 return tdfx_vid_set_yuv(arg); | |
517 case TDFX_VID_GET_YUV: | |
518 return tdfx_vid_get_yuv(arg); | |
519 default: | |
520 printk(KERN_ERR "tdfx_vid: Invalid ioctl %d\n",cmd); | |
521 return (-EINVAL); | |
522 } | |
523 return 0; | |
524 } | |
525 | |
526 | |
527 | |
528 static ssize_t tdfx_vid_read(struct file *file, char *buf, size_t count, loff_t *ppos) | |
529 { | |
530 return 0; | |
531 } | |
532 | |
533 static ssize_t tdfx_vid_write(struct file *file, const char *buf, size_t count, loff_t *ppos) | |
534 { | |
535 | |
536 return 0; | |
537 } | |
538 | |
539 | |
540 static int tdfx_vid_mmap(struct file *file, struct vm_area_struct *vma) | |
541 { | |
542 size_t size; | |
543 //u32 pages; | |
544 #ifdef MP_DEBUG | |
545 printk(KERN_DEBUG "tdfx_vid: mapping agp memory into userspace\n"); | |
546 #endif | |
547 | |
548 if(agp_mem) | |
549 return(-EAGAIN); | |
550 | |
551 size = (vma->vm_end-vma->vm_start + PAGE_SIZE - 1) / PAGE_SIZE; | |
552 | |
553 agp_mem = drm_agp->allocate_memory(size,AGP_NORMAL_MEMORY); | |
554 if(!agp_mem) { | |
555 printk(KERN_ERR "Failed to allocate AGP memory\n"); | |
556 return(-ENOMEM); | |
557 } | |
558 | |
559 if(drm_agp->bind_memory(agp_mem,0)) { | |
560 printk(KERN_ERR "Failed to bind the AGP memory\n"); | |
561 drm_agp->free_memory(agp_mem); | |
562 agp_mem = NULL; | |
563 return(-ENOMEM); | |
564 } | |
565 | |
566 printk(KERN_INFO "%d pages of AGP mem allocated (%ld/%ld bytes) :)))\n", | |
567 size,vma->vm_end-vma->vm_start,size*PAGE_SIZE); | |
568 | |
569 //setup_fifo(0,size); | |
570 | |
571 | |
572 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,3) | |
573 if(remap_page_range(vma, vma->vm_start,agp_info.aper_base, | |
574 vma->vm_end - vma->vm_start, vma->vm_page_prot)) | |
575 #else | |
576 if(remap_page_range(vma->vm_start, (unsigned long)agp_info.aper_base, | |
577 vma->vm_end - vma->vm_start, vma->vm_page_prot)) | |
578 #endif | |
579 { | |
580 printk(KERN_ERR "tdfx_vid: error mapping video memory\n"); | |
581 return(-EAGAIN); | |
582 } | |
583 | |
584 | |
585 printk(KERN_INFO "AGP Mem mapped in user space !!!!!\n"); | |
586 | |
587 return 0; | |
588 } | |
589 | |
590 | |
591 static int tdfx_vid_release(struct inode *inode, struct file *file) | |
592 { | |
593 //Close the window just in case | |
594 #ifdef MP_DEBUG | |
595 printk(KERN_DEBUG "tdfx_vid: Video OFF (release)\n"); | |
596 #endif | |
597 | |
598 // Release the agp mem | |
599 if(agp_mem) { | |
600 drm_agp->unbind_memory(agp_mem); | |
601 drm_agp->free_memory(agp_mem); | |
602 agp_mem = NULL; | |
603 } | |
604 | |
605 tdfx_vid_in_use = 0; | |
606 | |
607 MOD_DEC_USE_COUNT; | |
608 return 0; | |
609 } | |
610 | |
611 static long long tdfx_vid_lseek(struct file *file, long long offset, int origin) | |
612 { | |
613 return -ESPIPE; | |
614 } | |
615 | |
616 static int tdfx_vid_open(struct inode *inode, struct file *file) | |
617 { | |
618 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,2) | |
619 int minor = MINOR(inode->i_rdev.value); | |
620 #else | |
621 int minor = MINOR(inode->i_rdev); | |
622 #endif | |
623 | |
624 if(minor != 0) | |
625 return(-ENXIO); | |
626 | |
627 if(tdfx_vid_in_use == 1) | |
628 return(-EBUSY); | |
629 | |
630 tdfx_vid_in_use = 1; | |
631 MOD_INC_USE_COUNT; | |
632 return(0); | |
633 } | |
634 | |
635 #if LINUX_VERSION_CODE >= 0x020400 | |
636 static struct file_operations tdfx_vid_fops = | |
637 { | |
638 llseek: tdfx_vid_lseek, | |
639 read: tdfx_vid_read, | |
640 write: tdfx_vid_write, | |
641 ioctl: tdfx_vid_ioctl, | |
642 mmap: tdfx_vid_mmap, | |
643 open: tdfx_vid_open, | |
644 release: tdfx_vid_release | |
645 }; | |
646 #else | |
647 static struct file_operations tdfx_vid_fops = | |
648 { | |
649 tdfx_vid_lseek, | |
650 tdfx_vid_read, | |
651 tdfx_vid_write, | |
652 NULL, | |
653 NULL, | |
654 tdfx_vid_ioctl, | |
655 tdfx_vid_mmap, | |
656 tdfx_vid_open, | |
657 NULL, | |
658 tdfx_vid_release | |
659 }; | |
660 #endif | |
661 | |
662 | |
663 int init_module(void) | |
664 { | |
665 tdfx_vid_in_use = 0; | |
666 | |
667 if(register_chrdev(TDFX_VID_MAJOR, "tdfx_vid", &tdfx_vid_fops)) { | |
668 printk(KERN_ERR "tdfx_vid: unable to get major: %d\n", TDFX_VID_MAJOR); | |
669 return -EIO; | |
670 } | |
671 | |
672 if(!agp_init()) { | |
673 printk(KERN_ERR "tdfx_vid: AGP init failed\n"); | |
674 unregister_chrdev(TDFX_VID_MAJOR, "tdfx_vid"); | |
675 return -EINVAL; | |
676 } | |
677 | |
678 if (!tdfx_vid_find_card()) { | |
679 printk(KERN_ERR "tdfx_vid: no supported devices found\n"); | |
680 agp_close(); | |
681 unregister_chrdev(TDFX_VID_MAJOR, "tdfx_vid"); | |
682 return -EINVAL; | |
683 } | |
684 | |
685 | |
686 | |
687 return (0); | |
688 | |
689 } | |
690 | |
691 void cleanup_module(void) | |
692 { | |
693 if(tdfx_mmio_base) | |
694 iounmap(tdfx_mmio_base); | |
695 agp_close(); | |
696 printk(KERN_INFO "tdfx_vid: Cleaning up module\n"); | |
697 unregister_chrdev(TDFX_VID_MAJOR, "tdfx_vid"); | |
698 } |