9545
|
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");
|
9566
|
34 MODULE_DESCRIPTION("A driver for Banshee targeted for video app");
|
9545
|
35
|
|
36 #ifdef MODULE_LICENSE
|
|
37 MODULE_LICENSE("GPL");
|
|
38 #endif
|
|
39
|
|
40 #ifndef min
|
|
41 #define min(x,y) (((x)<(y))?(x):(y))
|
|
42 #endif
|
|
43
|
|
44 static struct pci_dev *pci_dev;
|
|
45
|
|
46 static uint8_t *tdfx_mmio_base = 0;
|
|
47 static uint32_t tdfx_mem_base = 0;
|
9558
|
48 static uint32_t tdfx_io_base = 0;
|
9545
|
49
|
|
50 static int tdfx_ram_size = 0;
|
|
51
|
|
52 static int tdfx_vid_in_use = 0;
|
|
53
|
|
54 static drm_agp_t *drm_agp = NULL;
|
|
55 static agp_kern_info agp_info;
|
|
56 static agp_memory *agp_mem = NULL;
|
|
57
|
9558
|
58 static __initdata int tdfx_map_io = 1;
|
9566
|
59 static __initdata unsigned long map_start = 0; //0x7300000;
|
|
60 static __initdata unsigned long map_max = (10*1024*1024);
|
|
61 static unsigned long map_base = 0;
|
9545
|
62
|
9558
|
63 MODULE_PARM(tdfx_map_io,"i");
|
|
64 MODULE_PARM_DESC(tdfx_map_io, "Set to 0 to use the page fault handler (you need to patch agpgart_be.c to allow the mapping in user space)\n");
|
9566
|
65 MODULE_PARM(map_start,"l");
|
|
66 MODULE_PARM_DESC(map_start,"Use a block of physical mem instead of the agp arerture.");
|
|
67 MODULE_PARM(map_max,"l");
|
|
68 MODULE_PARM_DESC(map_max, "Maximum amout of physical memory (in bytes) that can be used\n");
|
9545
|
69
|
|
70 static inline u32 tdfx_inl(unsigned int reg) {
|
|
71 return readl(tdfx_mmio_base + reg);
|
|
72 }
|
|
73
|
|
74 static inline void tdfx_outl(unsigned int reg, u32 val) {
|
|
75 writel(val,tdfx_mmio_base + reg);
|
|
76 }
|
|
77
|
|
78 static inline void banshee_make_room(int size) {
|
|
79 while((tdfx_inl(STATUS) & 0x1f) < size);
|
|
80 }
|
|
81
|
|
82 static inline void banshee_wait_idle(void) {
|
|
83 int i = 0;
|
|
84
|
|
85 banshee_make_room(1);
|
|
86 tdfx_outl(COMMAND_3D, COMMAND_3D_NOP);
|
|
87
|
|
88 while(1) {
|
|
89 i = (tdfx_inl(STATUS) & STATUS_BUSY) ? 0 : i + 1;
|
|
90 if(i == 3) break;
|
|
91 }
|
|
92 }
|
|
93
|
|
94 static unsigned long get_lfb_size(void) {
|
|
95 u32 draminit0 = 0;
|
|
96 u32 draminit1 = 0;
|
|
97 // u32 miscinit1 = 0;
|
|
98 u32 lfbsize = 0;
|
|
99 int sgram_p = 0;
|
|
100
|
|
101 draminit0 = tdfx_inl(DRAMINIT0);
|
|
102 draminit1 = tdfx_inl(DRAMINIT1);
|
|
103
|
|
104 if ((pci_dev->device == PCI_DEVICE_ID_3DFX_BANSHEE) ||
|
|
105 (pci_dev->device == PCI_DEVICE_ID_3DFX_VOODOO3)) {
|
|
106 sgram_p = (draminit1 & DRAMINIT1_MEM_SDRAM) ? 0 : 1;
|
|
107
|
|
108 lfbsize = sgram_p ?
|
|
109 (((draminit0 & DRAMINIT0_SGRAM_NUM) ? 2 : 1) *
|
|
110 ((draminit0 & DRAMINIT0_SGRAM_TYPE) ? 8 : 4) * 1024 * 1024) :
|
|
111 16 * 1024 * 1024;
|
|
112 } else {
|
|
113 /* Voodoo4/5 */
|
|
114 u32 chips, psize, banks;
|
|
115
|
|
116 chips = ((draminit0 & (1 << 26)) == 0) ? 4 : 8;
|
|
117 psize = 1 << ((draminit0 & 0x38000000) >> 28);
|
|
118 banks = ((draminit0 & (1 << 30)) == 0) ? 2 : 4;
|
|
119 lfbsize = chips * psize * banks;
|
|
120 lfbsize <<= 20;
|
|
121 }
|
|
122
|
|
123 #if 0
|
|
124 /* disable block writes for SDRAM (why?) */
|
|
125 miscinit1 = tdfx_inl(MISCINIT1);
|
|
126 miscinit1 |= sgram_p ? 0 : MISCINIT1_2DBLOCK_DIS;
|
|
127 miscinit1 |= MISCINIT1_CLUT_INV;
|
|
128
|
|
129 banshee_make_room(1);
|
|
130 tdfx_outl(MISCINIT1, miscinit1);
|
|
131 #endif
|
|
132
|
|
133 return lfbsize;
|
|
134 }
|
|
135
|
|
136 static int tdfx_vid_find_card(void)
|
|
137 {
|
|
138 struct pci_dev *dev = NULL;
|
|
139 // unsigned int card_option;
|
|
140
|
|
141 if((dev = pci_find_device(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_BANSHEE, NULL)))
|
|
142 printk(KERN_INFO "tdfx_vid: Found VOODOO BANSHEE\n");
|
|
143 else if((dev = pci_find_device(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO3, NULL)))
|
|
144 printk(KERN_INFO "tdfx_vid: Found VOODOO 3 \n");
|
|
145 else
|
|
146 return 0;
|
|
147
|
|
148
|
|
149 pci_dev = dev;
|
|
150
|
|
151 #if LINUX_VERSION_CODE >= 0x020300
|
|
152 tdfx_mmio_base = ioremap_nocache(dev->resource[0].start,1 << 24);
|
|
153 tdfx_mem_base = dev->resource[1].start;
|
9558
|
154 tdfx_io_base = dev->resource[2].start;
|
9545
|
155 #else
|
|
156 tdfx_mmio_base = ioremap_nocache(dev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK,0x4000);
|
|
157 tdfx_mem_base = dev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK;
|
9558
|
158 tdfx_io_base = dev->base_address[2] & PCI_BASE_ADDRESS_MEM_MASK;
|
9545
|
159 #endif
|
|
160 printk(KERN_INFO "tdfx_vid: MMIO at 0x%p\n", tdfx_mmio_base);
|
|
161 tdfx_ram_size = get_lfb_size();
|
|
162
|
|
163 printk(KERN_INFO "tdfx_vid: Found %d MB (%d bytes) of memory\n",
|
|
164 tdfx_ram_size / 1024 / 1024,tdfx_ram_size);
|
|
165
|
|
166
|
|
167 #if 0
|
|
168 {
|
|
169 int temp;
|
|
170 printk("List resources -----------\n");
|
|
171 for(temp=0;temp<DEVICE_COUNT_RESOURCE;temp++){
|
|
172 struct resource *res=&pci_dev->resource[temp];
|
|
173 if(res->flags){
|
|
174 int size=(1+res->end-res->start)>>20;
|
|
175 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);
|
|
176 if(res->flags&(IORESOURCE_MEM|IORESOURCE_PREFETCH)){
|
|
177 if(size>tdfx_ram_size && size<=64) tdfx_ram_size=size;
|
|
178 }
|
|
179 }
|
|
180 }
|
|
181 }
|
|
182 #endif
|
|
183
|
|
184
|
|
185 return 1;
|
|
186 }
|
|
187
|
|
188 static int agp_init(void) {
|
|
189
|
|
190 drm_agp = (drm_agp_t*)inter_module_get("drm_agp");
|
|
191
|
|
192 if(!drm_agp) {
|
|
193 printk(KERN_ERR "tdfx_vid: Unable to get drm_agp pointer\n");
|
|
194 return 0;
|
|
195 }
|
|
196
|
|
197 if(drm_agp->acquire()) {
|
|
198 printk(KERN_ERR "tdfx_vid: Unable to acquire the agp backend\n");
|
|
199 drm_agp = NULL;
|
|
200 return 0;
|
|
201 }
|
|
202
|
|
203 drm_agp->copy_info(&agp_info);
|
|
204 #if 0
|
|
205 printk(KERN_DEBUG "AGP Version : %d %d\n"
|
|
206 "AGP Mode: %#X\nAperture Base: %p\nAperture Size: %d\n"
|
|
207 "Max memory = %d\nCurrent mem = %d\nCan use perture : %s\n"
|
|
208 "Page mask = %#X\n",
|
|
209 agp_info.version.major,agp_info.version.minor,
|
|
210 agp_info.mode,agp_info.aper_base,agp_info.aper_size,
|
|
211 agp_info.max_memory,agp_info.current_memory,
|
|
212 agp_info.cant_use_aperture ? "no" : "yes",
|
|
213 agp_info.page_mask);
|
|
214 #endif
|
|
215 drm_agp->enable(agp_info.mode);
|
|
216
|
|
217
|
|
218 printk(KERN_INFO "AGP Enabled\n");
|
|
219
|
|
220 return 1;
|
|
221 }
|
|
222
|
|
223 static void agp_close(void) {
|
|
224
|
|
225 if(!drm_agp) return;
|
|
226
|
|
227 if(agp_mem) {
|
|
228 drm_agp->unbind_memory(agp_mem);
|
|
229 drm_agp->free_memory(agp_mem);
|
|
230 agp_mem = NULL;
|
|
231 }
|
|
232
|
|
233
|
|
234 drm_agp->release();
|
9566
|
235 inter_module_put("drm_agp");
|
9545
|
236 }
|
|
237
|
|
238 static int agp_move(tdfx_vid_agp_move_t* m) {
|
|
239 u32 src = 0;
|
|
240 u32 src_h,src_l;
|
|
241
|
9566
|
242 if(!(agp_mem||map_start))
|
9545
|
243 return (-EAGAIN);
|
|
244
|
|
245 if(m->move2 > 3) {
|
|
246 printk(KERN_DEBUG "tdfx_vid: AGP move invalid destination %d\n",
|
|
247 m->move2);
|
|
248 return (-EAGAIN);
|
|
249 }
|
|
250
|
9566
|
251 if(map_start)
|
|
252 src = map_start + m->src;
|
|
253 else
|
|
254 src = agp_info.aper_base + m->src;
|
9545
|
255
|
|
256 src_l = (u32)src;
|
|
257 src_h = (m->width | (m->src_stride << 14)) & 0x0FFFFFFF;
|
|
258
|
|
259 // banshee_wait_idle();
|
|
260 banshee_make_room(6);
|
|
261 tdfx_outl(AGPHOSTADDRESSHIGH,src_h);
|
|
262 tdfx_outl(AGPHOSTADDRESSLOW,src_l);
|
|
263
|
|
264 tdfx_outl(AGPGRAPHICSADDRESS, m->dst);
|
|
265 tdfx_outl(AGPGRAPHICSSTRIDE, m->dst_stride);
|
|
266 tdfx_outl(AGPREQSIZE,m->src_stride*m->height);
|
|
267
|
|
268 tdfx_outl(AGPMOVECMD,m->move2 << 3);
|
|
269 banshee_wait_idle();
|
|
270
|
|
271 return 0;
|
|
272 }
|
|
273
|
|
274 static void setup_fifo(u32 offset,ssize_t pages) {
|
|
275 long addr = agp_info.aper_base + offset;
|
|
276 u32 size = pages | 0x700; // fifo on, in agp mem, disable hole cnt
|
|
277
|
|
278 banshee_wait_idle();
|
|
279
|
|
280 tdfx_outl(CMDBASEADDR0,addr >> 4);
|
|
281 tdfx_outl(CMDRDPTRL0, addr << 4);
|
|
282 tdfx_outl(CMDRDPTRH0, addr >> 28);
|
|
283 tdfx_outl(CMDAMIN0, (addr - 4) & 0xFFFFFF);
|
|
284 tdfx_outl(CMDAMAX0, (addr - 4) & 0xFFFFFF);
|
|
285 tdfx_outl(CMDFIFODEPTH0, 0);
|
|
286 tdfx_outl(CMDHOLECNT0, 0);
|
|
287 tdfx_outl(CMDBASESIZE0,size);
|
|
288
|
|
289 banshee_wait_idle();
|
|
290
|
|
291 }
|
|
292
|
|
293 static int bump_fifo(u16 size) {
|
|
294
|
|
295 banshee_wait_idle();
|
|
296 tdfx_outl(CMDBUMP0 , size);
|
|
297 banshee_wait_idle();
|
|
298
|
|
299 return 0;
|
|
300 }
|
|
301
|
|
302 static void tdfx_vid_get_config(tdfx_vid_config_t* cfg) {
|
|
303 u32 in;
|
|
304
|
|
305 cfg->version = TDFX_VID_VERSION;
|
|
306 cfg->ram_size = tdfx_ram_size;
|
|
307
|
|
308 in = tdfx_inl(VIDSCREENSIZE);
|
|
309 cfg->screen_width = in & 0xFFF;
|
|
310 cfg->screen_height = (in >> 12) & 0xFFF;
|
|
311 in = (tdfx_inl(VIDPROCCFG)>> 18)& 0x7;
|
|
312 switch(in) {
|
|
313 case 0:
|
|
314 cfg->screen_format = TDFX_VID_FORMAT_BGR8;
|
|
315 break;
|
|
316 case 1:
|
|
317 cfg->screen_format = TDFX_VID_FORMAT_BGR16;
|
|
318 break;
|
|
319 case 2:
|
|
320 cfg->screen_format = TDFX_VID_FORMAT_BGR24;
|
|
321 break;
|
|
322 case 3:
|
|
323 cfg->screen_format = TDFX_VID_FORMAT_BGR32;
|
|
324 break;
|
|
325 default:
|
10397
|
326 printk(KERN_INFO "tdfx_vid: unknown screen format %d\n",in);
|
9545
|
327 cfg->screen_format = 0;
|
|
328 break;
|
|
329 }
|
9566
|
330 cfg->screen_stride = tdfx_inl(VIDDESKSTRIDE) & 0x7FFF;
|
9545
|
331 cfg->screen_start = tdfx_inl(VIDDESKSTART);
|
|
332 }
|
|
333
|
|
334 inline static u32 tdfx_vid_make_format(int src,u16 stride,u32 fmt) {
|
|
335 u32 r = stride & 0xFFF3;
|
|
336 u32 tdfx_fmt = 0;
|
|
337
|
|
338 // src and dest formats
|
|
339 switch(fmt) {
|
|
340 case TDFX_VID_FORMAT_BGR8:
|
|
341 tdfx_fmt = 1;
|
|
342 break;
|
|
343 case TDFX_VID_FORMAT_BGR16:
|
|
344 tdfx_fmt = 3;
|
|
345 break;
|
|
346 case TDFX_VID_FORMAT_BGR24:
|
|
347 tdfx_fmt = 4;
|
|
348 break;
|
|
349 case TDFX_VID_FORMAT_BGR32:
|
|
350 tdfx_fmt = 5;
|
|
351 break;
|
|
352 }
|
|
353
|
|
354 if(!src && !tdfx_fmt) {
|
|
355 printk(KERN_INFO "tdfx_vid: Invalid destination format %#X\n",fmt);
|
|
356 return 0;
|
|
357 }
|
|
358
|
|
359 if(src && !tdfx_fmt) {
|
|
360 // src only format
|
|
361 switch(fmt){
|
|
362 case TDFX_VID_FORMAT_BGR1:
|
|
363 tdfx_fmt = 0;
|
|
364 break;
|
9558
|
365 case TDFX_VID_FORMAT_BGR15: // To check
|
|
366 tdfx_fmt = 2;
|
|
367 break;
|
9545
|
368 case TDFX_VID_FORMAT_YUY2:
|
|
369 tdfx_fmt = 8;
|
|
370 break;
|
|
371 case TDFX_VID_FORMAT_UYVY:
|
|
372 tdfx_fmt = 9;
|
|
373 break;
|
|
374 default:
|
|
375 printk(KERN_INFO "tdfx_vid: Invalid source format %#X\n",fmt);
|
|
376 return 0;
|
|
377 }
|
|
378 }
|
|
379
|
|
380 r |= tdfx_fmt << 16;
|
|
381
|
|
382 return r;
|
|
383 }
|
|
384
|
|
385 static int tdfx_vid_blit(tdfx_vid_blit_t* blit) {
|
9566
|
386 u32 src_fmt,dst_fmt,cmd = 2;
|
9545
|
387 u32 cmin,cmax,srcbase,srcxy,srcfmt,srcsize;
|
9566
|
388 u32 dstbase,dstxy,dstfmt,dstsize = 0;
|
9558
|
389 u32 cmd_extra = 0,src_ck[2],dst_ck[2],rop123=0;
|
9545
|
390
|
|
391 //printk(KERN_INFO "tdfx_vid: Make src fmt 0x%x\n",blit->src_format);
|
|
392 src_fmt = tdfx_vid_make_format(1,blit->src_stride,blit->src_format);
|
|
393 if(!src_fmt)
|
|
394 return 0;
|
|
395 //printk(KERN_INFO "tdfx_vid: Make dst fmt 0x%x\n", blit->dst_format);
|
|
396 dst_fmt = tdfx_vid_make_format(0,blit->dst_stride,blit->dst_format);
|
|
397 if(!dst_fmt)
|
|
398 return 0;
|
9558
|
399 blit->colorkey &= 0x3;
|
|
400 // Be nice if user just want a simple blit
|
|
401 if((!blit->colorkey) && (!blit->rop[0]))
|
|
402 blit->rop[0] = TDFX_VID_ROP_COPY;
|
9566
|
403 // No stretch : fix me the cmd should be 1 but it
|
|
404 // doesn't work. Maybe some other regs need to be set
|
|
405 // as non-stretch blit have more options
|
|
406 if(((!blit->dst_w) && (!blit->dst_h)) ||
|
|
407 ((blit->dst_w == blit->src_w) && (blit->dst_h == blit->src_h)))
|
|
408 cmd = 2;
|
9558
|
409
|
9545
|
410 // Save the regs otherwise fb get crazy
|
|
411 // we can perhaps avoid some ...
|
9558
|
412 banshee_wait_idle();
|
9545
|
413 cmin = tdfx_inl(CLIP0MIN);
|
|
414 cmax = tdfx_inl(CLIP0MAX);
|
|
415 srcbase = tdfx_inl(SRCBASE);
|
|
416 srcxy = tdfx_inl(SRCXY);
|
|
417 srcfmt = tdfx_inl(SRCFORMAT);
|
|
418 srcsize = tdfx_inl(SRCSIZE);
|
|
419 dstbase = tdfx_inl(DSTBASE);
|
|
420 dstxy = tdfx_inl(DSTXY);
|
|
421 dstfmt = tdfx_inl(DSTFORMAT);
|
9566
|
422 if(cmd == 2)
|
|
423 dstsize = tdfx_inl(DSTSIZE);
|
9558
|
424 if(blit->colorkey & TDFX_VID_SRC_COLORKEY) {
|
|
425 src_ck[0] = tdfx_inl(SRCCOLORKEYMIN);
|
|
426 src_ck[1] = tdfx_inl(SRCCOLORKEYMAX);
|
|
427 tdfx_outl(SRCCOLORKEYMIN,blit->src_colorkey[0]);
|
|
428 tdfx_outl(SRCCOLORKEYMAX,blit->src_colorkey[1]);
|
|
429 }
|
|
430 if(blit->colorkey & TDFX_VID_DST_COLORKEY) {
|
|
431 dst_ck[0] = tdfx_inl(DSTCOLORKEYMIN);
|
|
432 dst_ck[1] = tdfx_inl(DSTCOLORKEYMAX);
|
|
433 tdfx_outl(SRCCOLORKEYMIN,blit->dst_colorkey[0]);
|
|
434 tdfx_outl(SRCCOLORKEYMAX,blit->dst_colorkey[1]);
|
|
435 }
|
|
436 if(blit->colorkey) {
|
|
437 cmd_extra = tdfx_inl(COMMANDEXTRA_2D);
|
|
438 rop123 = tdfx_inl(ROP123);
|
|
439 tdfx_outl(COMMANDEXTRA_2D, blit->colorkey);
|
|
440 tdfx_outl(ROP123,(blit->rop[1] | (blit->rop[2] << 8) | blit->rop[3] << 16));
|
|
441
|
|
442 }
|
9545
|
443 // Get rid of the clipping at the moment
|
|
444 tdfx_outl(CLIP0MIN,0);
|
|
445 tdfx_outl(CLIP0MAX,0x0fff0fff);
|
|
446
|
|
447 // Setup the src
|
|
448 tdfx_outl(SRCBASE,blit->src & 0x00FFFFFF);
|
|
449 tdfx_outl(SRCXY,XYREG(blit->src_x,blit->src_y));
|
|
450 tdfx_outl(SRCFORMAT,src_fmt);
|
|
451 tdfx_outl(SRCSIZE,XYREG(blit->src_w,blit->src_h));
|
|
452
|
|
453 // Setup the dst
|
|
454 tdfx_outl(DSTBASE,blit->dst & 0x00FFFFFF);
|
|
455 tdfx_outl(DSTXY,XYREG(blit->dst_x,blit->dst_y));
|
|
456 tdfx_outl(DSTFORMAT,dst_fmt);
|
9566
|
457 if(cmd == 2)
|
|
458 tdfx_outl(DSTSIZE,XYREG(blit->dst_w,blit->dst_h));
|
9545
|
459
|
|
460 // Send the command
|
9566
|
461 tdfx_outl(COMMAND_2D,cmd | 0x100 | (blit->rop[0] << 24));
|
9545
|
462 banshee_wait_idle();
|
|
463
|
|
464 // Now restore the regs to make fb happy
|
|
465 tdfx_outl(CLIP0MIN, cmin);
|
|
466 tdfx_outl(CLIP0MAX, cmax);
|
|
467 tdfx_outl(SRCBASE, srcbase);
|
|
468 tdfx_outl(SRCXY, srcxy);
|
|
469 tdfx_outl(SRCFORMAT, srcfmt);
|
|
470 tdfx_outl(SRCSIZE, srcsize);
|
|
471 tdfx_outl(DSTBASE, dstbase);
|
|
472 tdfx_outl(DSTXY, dstxy);
|
|
473 tdfx_outl(DSTFORMAT, dstfmt);
|
9566
|
474 if(cmd == 2)
|
|
475 tdfx_outl(DSTSIZE, dstsize);
|
9558
|
476 if(blit->colorkey & TDFX_VID_SRC_COLORKEY) {
|
|
477 tdfx_outl(SRCCOLORKEYMIN,src_ck[0]);
|
|
478 tdfx_outl(SRCCOLORKEYMAX,src_ck[1]);
|
|
479 }
|
|
480 if(blit->colorkey & TDFX_VID_DST_COLORKEY) {
|
|
481 tdfx_outl(SRCCOLORKEYMIN,dst_ck[0]);
|
|
482 tdfx_outl(SRCCOLORKEYMAX,dst_ck[1]);
|
|
483 }
|
|
484 if(blit->colorkey) {
|
|
485 tdfx_outl(COMMANDEXTRA_2D,cmd_extra);
|
|
486 tdfx_outl(ROP123,rop123);
|
|
487 }
|
9545
|
488 return 1;
|
|
489 }
|
|
490
|
|
491 static int tdfx_vid_set_yuv(unsigned long arg) {
|
|
492 tdfx_vid_yuv_t yuv;
|
|
493
|
|
494 if(copy_from_user(&yuv,(tdfx_vid_yuv_t*)arg,sizeof(tdfx_vid_yuv_t))) {
|
|
495 printk(KERN_DEBUG "tdfx_vid:failed copy from userspace\n");
|
|
496 return(-EFAULT);
|
|
497 }
|
|
498 banshee_make_room(2);
|
|
499 tdfx_outl(YUVBASEADDRESS,yuv.base & 0x01FFFFFF);
|
|
500 tdfx_outl(YUVSTRIDE, yuv.stride & 0x3FFF);
|
|
501
|
|
502 banshee_wait_idle();
|
|
503
|
|
504 return 0;
|
|
505 }
|
|
506
|
|
507 static int tdfx_vid_get_yuv(unsigned long arg) {
|
|
508 tdfx_vid_yuv_t yuv;
|
|
509
|
|
510 yuv.base = tdfx_inl(YUVBASEADDRESS) & 0x01FFFFFF;
|
|
511 yuv.stride = tdfx_inl(YUVSTRIDE) & 0x3FFF;
|
|
512
|
|
513 if(copy_to_user((tdfx_vid_yuv_t*)arg,&yuv,sizeof(tdfx_vid_yuv_t))) {
|
|
514 printk(KERN_INFO "tdfx_vid:failed copy to userspace\n");
|
|
515 return(-EFAULT);
|
|
516 }
|
|
517
|
|
518 return 0;
|
|
519 }
|
|
520
|
9566
|
521 static int tdfx_vid_set_overlay(unsigned long arg) {
|
|
522 tdfx_vid_overlay_t ov;
|
|
523 uint32_t screen_w,screen_h;
|
|
524 uint32_t vidcfg,stride,vidbuf;
|
|
525 int disp_w,disp_h;
|
|
526
|
|
527 if(copy_from_user(&ov,(tdfx_vid_overlay_t*)arg,sizeof(tdfx_vid_overlay_t))) {
|
|
528 printk(KERN_DEBUG "tdfx_vid:failed copy from userspace\n");
|
|
529 return(-EFAULT);
|
|
530 }
|
|
531
|
10339
|
532 if(ov.dst_y < 0) {
|
|
533 int shift;
|
|
534 if(-ov.dst_y >= ov.src_height) {
|
|
535 printk(KERN_DEBUG "tdfx_vid: Overlay outside of the screen ????\n");
|
|
536 return(-EFAULT);
|
|
537 }
|
|
538 shift = (-ov.dst_y)/(double)ov.dst_height*ov.src_height;
|
|
539 ov.src[0] += shift*ov.src_stride;
|
|
540 ov.src_height -= shift;
|
|
541 ov.dst_height += ov.dst_y;
|
|
542 ov.dst_y = 0;
|
|
543 }
|
|
544
|
|
545 if(ov.dst_x < 0) {
|
|
546 int shift;
|
|
547 if(-ov.dst_x >= ov.src_width) {
|
|
548 printk(KERN_DEBUG "tdfx_vid: Overlay outside of the screen ????\n");
|
|
549 return(-EFAULT);
|
|
550 }
|
|
551 shift = (-ov.dst_x)/(double)ov.dst_width*ov.src_width;
|
|
552 shift = ((shift+3)/2)*2;
|
|
553 ov.src[0] += shift*2;
|
|
554 ov.src_width -= shift;
|
|
555 ov.dst_width += ov.dst_x;
|
|
556 ov.dst_x = 0;
|
9566
|
557 }
|
|
558
|
|
559 vidcfg = tdfx_inl(VIDPROCCFG);
|
|
560 // clear the overlay fmt
|
|
561 vidcfg &= ~(7 << 21);
|
|
562 switch(ov.format) {
|
|
563 case TDFX_VID_FORMAT_BGR15:
|
|
564 vidcfg |= (1 << 21);
|
|
565 break;
|
|
566 case TDFX_VID_FORMAT_BGR16:
|
|
567 vidcfg |= (7 << 21);
|
|
568 break;
|
|
569 case TDFX_VID_FORMAT_YUY2:
|
|
570 vidcfg |= (5 << 21);
|
|
571 break;
|
|
572 case TDFX_VID_FORMAT_UYVY:
|
|
573 vidcfg |= (6 << 21);
|
|
574 break;
|
|
575 default:
|
|
576 printk(KERN_DEBUG "tdfx_vid: Invalid overlay fmt 0x%x\n",ov.format);
|
|
577 return (-EFAULT);
|
|
578 }
|
|
579
|
|
580 // YUV422 need 4 bytes aligned stride and address
|
|
581 if((ov.format == TDFX_VID_FORMAT_YUY2 ||
|
|
582 ov.format == TDFX_VID_FORMAT_UYVY)) {
|
|
583 if((ov.src_stride & ~0x3) != ov.src_stride) {
|
|
584 printk(KERN_DEBUG "tdfx_vid: YUV need a 4 bytes aligned stride %d\n",ov.src_stride);
|
|
585 return(-EFAULT);
|
|
586 }
|
|
587 if((ov.src[0] & ~0x3) != ov.src[0] || (ov.src[1] & ~0x3) != ov.src[1]){
|
|
588 printk(KERN_DEBUG "tdfx_vid: YUV need a 4 bytes aligned address 0x%x 0x%x\n",ov.src[0],ov.src[1]);
|
|
589 return(-EFAULT);
|
|
590 }
|
|
591 }
|
|
592
|
|
593 // Now we have a good input format
|
|
594 // but first get the screen size to check a bit
|
|
595 // if the size/position is valid
|
|
596 screen_w = tdfx_inl(VIDSCREENSIZE);
|
|
597 screen_h = (screen_w >> 12) & 0xFFF;
|
|
598 screen_w &= 0xFFF;
|
10339
|
599 disp_w = ov.dst_x + ov.dst_width >= screen_w ?
|
9566
|
600 screen_w - ov.dst_x : ov.dst_width;
|
10339
|
601 disp_h = ov.dst_y + ov.dst_height >= screen_h ?
|
9566
|
602 screen_h - ov.dst_y : ov.dst_height;
|
|
603
|
|
604 if(ov.dst_x >= screen_w || ov.dst_y >= screen_h ||
|
|
605 disp_h <= 0 || disp_h > screen_h || disp_w <= 0 || disp_w > screen_w) {
|
|
606 printk(KERN_DEBUG "tdfx_vid: Invalid overlay dimension and/or position\n");
|
|
607 return (-EFAULT);
|
|
608 }
|
|
609 // Setup the vidproc
|
|
610 // H scaling
|
9706
|
611 if(ov.src_width < ov.dst_width)
|
9566
|
612 vidcfg |= (1<<14);
|
|
613 else
|
|
614 vidcfg &= ~(1<<14);
|
|
615 // V scaling
|
9706
|
616 if(ov.src_height < ov.dst_height)
|
9566
|
617 vidcfg |= (1<<15);
|
|
618 else
|
|
619 vidcfg &= ~(1<<15);
|
|
620 // Filtering can only be used in 1x mode
|
|
621 if(!(vidcfg | (1<<26)))
|
|
622 vidcfg |= (3<<16);
|
|
623 else
|
|
624 vidcfg &= ~(3<<16);
|
|
625 // disable overlay stereo mode
|
|
626 vidcfg &= ~(1<<2);
|
|
627 // Colorkey on/off
|
|
628 if(ov.use_colorkey) {
|
|
629 // Colorkey inversion
|
|
630 if(ov.invert_colorkey)
|
|
631 vidcfg |= (1<<6);
|
|
632 else
|
|
633 vidcfg &= ~(1<<6);
|
|
634 vidcfg |= (1<<5);
|
|
635 } else
|
|
636 vidcfg &= ~(1<<5);
|
|
637 // Overlay isn't VidIn
|
|
638 vidcfg &= ~(1<<9);
|
|
639 // vidcfg |= (1<<8);
|
|
640 tdfx_outl(VIDPROCCFG,vidcfg);
|
|
641
|
|
642 // Start coord
|
9568
|
643 //printk(KERN_DEBUG "tdfx_vid: start %dx%d\n",ov.dst_x & 0xFFF,ov.dst_y & 0xFFF);
|
9566
|
644 tdfx_outl(VIDOVRSTARTCRD,(ov.dst_x & 0xFFF)|((ov.dst_y & 0xFFF)<<12));
|
|
645 // End coord
|
10339
|
646 tdfx_outl(VIDOVRENDCRD, ((ov.dst_x + disp_w-1) & 0xFFF)|
|
|
647 (((ov.dst_y + disp_h-1) & 0xFFF)<<12));
|
9566
|
648 // H Scaling
|
|
649 tdfx_outl(VIDOVRDUDX,( ((u32)ov.src_width) << 20) / ov.dst_width);
|
|
650 // Src offset and width (in bytes)
|
|
651 tdfx_outl(VIDOVRDUDXOFF,((ov.src_width<<1) & 0xFFF) << 19);
|
|
652 // V Scaling
|
|
653 tdfx_outl(VIDOVRDVDY, ( ((u32)ov.src_height) << 20) / ov.dst_height);
|
|
654 //else
|
|
655 // tdfx_outl(VIDOVRDVDY,0);
|
|
656 // V Offset
|
|
657 tdfx_outl(VIDOVRDVDYOFF,0);
|
|
658 // Overlay stride
|
|
659 stride = tdfx_inl(VIDDESKSTRIDE) & 0xFFFF;
|
|
660 tdfx_outl(VIDDESKSTRIDE,stride | (((u32)ov.src_stride) << 16));
|
|
661 // Buffers address
|
|
662 tdfx_outl(LEFTOVBUF, ov.src[0]);
|
|
663 tdfx_outl(RIGHTOVBUF, ov.src[1]);
|
|
664
|
|
665 // Send a swap buffer cmd if we are not on one of the 2 buffers
|
|
666 vidbuf = tdfx_inl(VIDCUROVRSTART);
|
|
667 if(vidbuf != ov.src[0] && vidbuf != ov.src[1]) {
|
|
668 tdfx_outl(SWAPPENDING,0);
|
|
669 tdfx_outl(SWAPBUFCMD, 1);
|
|
670 }
|
9568
|
671 //printk(KERN_DEBUG "tdfx_vid: Buf0=0x%x Buf1=0x%x Current=0x%x\n",
|
|
672 // ov.src[0],ov.src[1],tdfx_inl(VIDCUROVRSTART));
|
9566
|
673 // Colorkey
|
|
674 if(ov.use_colorkey) {
|
|
675 tdfx_outl(VIDCHRMIN,ov.colorkey[0]);
|
|
676 tdfx_outl(VIDCHRMAX,ov.colorkey[1]);
|
|
677 }
|
|
678
|
|
679 return 0;
|
|
680 }
|
|
681
|
|
682 static int tdfx_vid_overlay_on(void) {
|
|
683 uint32_t vidcfg = tdfx_inl(VIDPROCCFG);
|
|
684 //return 0;
|
|
685 if(vidcfg & (1<<8)) { // Overlay is alredy on
|
9568
|
686 //printk(KERN_DEBUG "tdfx_vid: Overlay is alredy on\n");
|
9566
|
687 return (-EFAULT);
|
|
688 }
|
|
689 vidcfg |= (1<<8);
|
|
690 tdfx_outl(VIDPROCCFG,vidcfg);
|
|
691 return 0;
|
|
692 }
|
|
693
|
|
694 static int tdfx_vid_overlay_off(void) {
|
|
695 uint32_t vidcfg = tdfx_inl(VIDPROCCFG);
|
|
696
|
|
697 if(vidcfg & (1<<8)) {
|
|
698 vidcfg &= ~(1<<8);
|
|
699 tdfx_outl(VIDPROCCFG,vidcfg);
|
|
700 return 0;
|
|
701 }
|
|
702
|
|
703 printk(KERN_DEBUG "tdfx_vid: Overlay is alredy off\n");
|
|
704 return (-EFAULT);
|
|
705 }
|
|
706
|
|
707
|
9545
|
708 static int tdfx_vid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
|
|
709 {
|
|
710 tdfx_vid_agp_move_t move;
|
|
711 tdfx_vid_config_t cfg;
|
|
712 tdfx_vid_blit_t blit;
|
|
713 u16 int16;
|
|
714
|
|
715 switch(cmd) {
|
|
716 case TDFX_VID_AGP_MOVE:
|
|
717 if(copy_from_user(&move,(tdfx_vid_agp_move_t*)arg,sizeof(tdfx_vid_agp_move_t))) {
|
|
718 printk(KERN_INFO "tdfx_vid:failed copy from userspace\n");
|
|
719 return(-EFAULT);
|
|
720 }
|
|
721 return agp_move(&move);
|
|
722 case TDFX_VID_BUMP0:
|
|
723 if(copy_from_user(&int16,(u16*)arg,sizeof(u16))) {
|
|
724 printk(KERN_INFO "tdfx_vid:failed copy from userspace\n");
|
|
725 return(-EFAULT);
|
|
726 }
|
|
727 return bump_fifo(int16);
|
|
728 case TDFX_VID_BLIT:
|
|
729 if(copy_from_user(&blit,(tdfx_vid_blit_t*)arg,sizeof(tdfx_vid_blit_t))) {
|
|
730 printk(KERN_INFO "tdfx_vid:failed copy from userspace\n");
|
|
731 return(-EFAULT);
|
|
732 }
|
|
733 if(!tdfx_vid_blit(&blit)) {
|
|
734 printk(KERN_INFO "tdfx_vid: Blit failed\n");
|
|
735 return(-EFAULT);
|
|
736 }
|
|
737 return 0;
|
|
738 case TDFX_VID_GET_CONFIG:
|
|
739 if(copy_from_user(&cfg,(tdfx_vid_config_t*)arg,sizeof(tdfx_vid_config_t))) {
|
|
740 printk(KERN_INFO "tdfx_vid:failed copy from userspace\n");
|
|
741 return(-EFAULT);
|
|
742 }
|
|
743 tdfx_vid_get_config(&cfg);
|
|
744 if(copy_to_user((tdfx_vid_config_t*)arg,&cfg,sizeof(tdfx_vid_config_t))) {
|
|
745 printk(KERN_INFO "tdfx_vid:failed copy to userspace\n");
|
|
746 return(-EFAULT);
|
|
747 }
|
|
748 return 0;
|
|
749 case TDFX_VID_SET_YUV:
|
|
750 return tdfx_vid_set_yuv(arg);
|
|
751 case TDFX_VID_GET_YUV:
|
|
752 return tdfx_vid_get_yuv(arg);
|
9566
|
753 case TDFX_VID_SET_OVERLAY:
|
|
754 return tdfx_vid_set_overlay(arg);
|
|
755 case TDFX_VID_OVERLAY_ON:
|
|
756 return tdfx_vid_overlay_on();
|
|
757 case TDFX_VID_OVERLAY_OFF:
|
|
758 return tdfx_vid_overlay_off();
|
9545
|
759 default:
|
|
760 printk(KERN_ERR "tdfx_vid: Invalid ioctl %d\n",cmd);
|
|
761 return (-EINVAL);
|
|
762 }
|
|
763 return 0;
|
|
764 }
|
|
765
|
|
766
|
|
767
|
|
768 static ssize_t tdfx_vid_read(struct file *file, char *buf, size_t count, loff_t *ppos)
|
|
769 {
|
|
770 return 0;
|
|
771 }
|
|
772
|
|
773 static ssize_t tdfx_vid_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
|
|
774 {
|
|
775
|
|
776 return 0;
|
|
777 }
|
|
778
|
9558
|
779 static void tdfx_vid_mopen(struct vm_area_struct *vma) {
|
|
780 int i;
|
|
781 struct page *page;
|
|
782 unsigned long phys;
|
|
783
|
|
784 printk(KERN_DEBUG "tdfx_vid: mopen\n");
|
|
785
|
|
786 for(i = 0 ; i < agp_mem->page_count ; i++) {
|
|
787 phys = agp_mem->memory[i] & ~(0x00000fff);
|
|
788 page = virt_to_page(phys_to_virt(phys));
|
|
789 if(!page) {
|
|
790 printk(KERN_DEBUG "tdfx_vid: Can't get the page %d\%d\n",i,agp_mem->page_count);
|
|
791 return;
|
|
792 }
|
|
793 get_page(page);
|
|
794 }
|
|
795 MOD_INC_USE_COUNT;
|
|
796 }
|
|
797
|
|
798 static void tdfx_vid_mclose(struct vm_area_struct *vma) {
|
|
799 int i;
|
|
800 struct page *page;
|
|
801 unsigned long phys;
|
|
802
|
|
803 printk(KERN_DEBUG "tdfx_vid: mclose\n");
|
|
804
|
|
805 for(i = 0 ; i < agp_mem->page_count ; i++) {
|
|
806 phys = agp_mem->memory[i] & ~(0x00000fff);
|
|
807 page = virt_to_page(phys_to_virt(phys));
|
|
808 if(!page) {
|
|
809 printk(KERN_DEBUG "tdfx_vid: Can't get the page %d\%d\n",i,agp_mem->page_count);
|
|
810 return;
|
|
811 }
|
|
812 put_page(page);
|
|
813 }
|
|
814
|
|
815 MOD_DEC_USE_COUNT;
|
|
816 }
|
|
817
|
|
818 static struct page *tdfx_vid_nopage(struct vm_area_struct *vma,
|
|
819 unsigned long address,
|
|
820 int write_access) {
|
|
821 unsigned long off;
|
|
822 uint32_t n;
|
|
823 struct page *page;
|
|
824 unsigned long phys;
|
|
825
|
|
826 off = address - vma->vm_start + (vma->vm_pgoff<<PAGE_SHIFT);
|
|
827 n = off / PAGE_SIZE;
|
|
828
|
|
829 if(n >= agp_mem->page_count) {
|
|
830 printk(KERN_DEBUG "tdfx_vid: Too far away\n");
|
|
831 return ((struct page *)0UL);
|
|
832 }
|
|
833 phys = agp_mem->memory[n] & ~(0x00000fff);
|
|
834 page = virt_to_page(phys_to_virt(phys));
|
|
835 if(!page) {
|
|
836 printk(KERN_DEBUG "tdfx_vid: Can't get the page\n");
|
|
837 return ((struct page *)0UL);
|
|
838 }
|
|
839 return page;
|
|
840 }
|
|
841
|
|
842 /* memory handler functions */
|
|
843 static struct vm_operations_struct tdfx_vid_vm_ops = {
|
|
844 open: tdfx_vid_mopen, /* mmap-open */
|
|
845 close: tdfx_vid_mclose,/* mmap-close */
|
|
846 nopage: tdfx_vid_nopage, /* no-page fault handler */
|
|
847 };
|
|
848
|
9545
|
849
|
|
850 static int tdfx_vid_mmap(struct file *file, struct vm_area_struct *vma)
|
|
851 {
|
|
852 size_t size;
|
|
853 #ifdef MP_DEBUG
|
|
854 printk(KERN_DEBUG "tdfx_vid: mapping agp memory into userspace\n");
|
|
855 #endif
|
|
856
|
9566
|
857 size = (vma->vm_end-vma->vm_start + PAGE_SIZE - 1) / PAGE_SIZE;
|
|
858
|
|
859 if(map_start) { // Ok we map directly in the physcal ram
|
|
860 if(size*PAGE_SIZE > map_max) {
|
|
861 printk(KERN_ERR "tdfx_vid: Not enouth mem\n");
|
|
862 return(-EAGAIN);
|
|
863 }
|
|
864 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,3)
|
|
865 if(remap_page_range(vma, vma->vm_start,map_start,
|
|
866 vma->vm_end - vma->vm_start, vma->vm_page_prot))
|
|
867 #else
|
|
868 if(remap_page_range(vma->vm_start, (unsigned long)map_start,
|
|
869 vma->vm_end - vma->vm_start, vma->vm_page_prot))
|
|
870 #endif
|
|
871 {
|
|
872 printk(KERN_ERR "tdfx_vid: error mapping video memory\n");
|
|
873 return(-EAGAIN);
|
|
874 }
|
|
875 printk(KERN_INFO "Physical mem 0x%lx mapped in userspace\n",map_start);
|
|
876 return 0;
|
|
877 }
|
|
878
|
9545
|
879 if(agp_mem)
|
|
880 return(-EAGAIN);
|
9566
|
881
|
9545
|
882 agp_mem = drm_agp->allocate_memory(size,AGP_NORMAL_MEMORY);
|
|
883 if(!agp_mem) {
|
|
884 printk(KERN_ERR "Failed to allocate AGP memory\n");
|
|
885 return(-ENOMEM);
|
|
886 }
|
|
887
|
|
888 if(drm_agp->bind_memory(agp_mem,0)) {
|
|
889 printk(KERN_ERR "Failed to bind the AGP memory\n");
|
|
890 drm_agp->free_memory(agp_mem);
|
|
891 agp_mem = NULL;
|
|
892 return(-ENOMEM);
|
|
893 }
|
|
894
|
|
895 printk(KERN_INFO "%d pages of AGP mem allocated (%ld/%ld bytes) :)))\n",
|
|
896 size,vma->vm_end-vma->vm_start,size*PAGE_SIZE);
|
|
897
|
|
898
|
9558
|
899 if(tdfx_map_io) {
|
9545
|
900 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,3)
|
9558
|
901 if(remap_page_range(vma, vma->vm_start,agp_info.aper_base,
|
|
902 vma->vm_end - vma->vm_start, vma->vm_page_prot))
|
9545
|
903 #else
|
9558
|
904 if(remap_page_range(vma->vm_start, (unsigned long)agp_info.aper_base,
|
|
905 vma->vm_end - vma->vm_start, vma->vm_page_prot))
|
9545
|
906 #endif
|
9558
|
907 {
|
|
908 printk(KERN_ERR "tdfx_vid: error mapping video memory\n");
|
|
909 return(-EAGAIN);
|
|
910 }
|
|
911 } else {
|
|
912 // Never swap it out
|
|
913 vma->vm_flags |= VM_LOCKED | VM_IO;
|
|
914 vma->vm_ops = &tdfx_vid_vm_ops;
|
|
915 vma->vm_ops->open(vma);
|
9566
|
916 printk(KERN_INFO "Page fault handler ready !!!!!\n");
|
9558
|
917 }
|
9545
|
918
|
|
919 return 0;
|
|
920 }
|
|
921
|
|
922
|
|
923 static int tdfx_vid_release(struct inode *inode, struct file *file)
|
|
924 {
|
|
925 #ifdef MP_DEBUG
|
|
926 printk(KERN_DEBUG "tdfx_vid: Video OFF (release)\n");
|
|
927 #endif
|
|
928
|
|
929 // Release the agp mem
|
|
930 if(agp_mem) {
|
|
931 drm_agp->unbind_memory(agp_mem);
|
|
932 drm_agp->free_memory(agp_mem);
|
|
933 agp_mem = NULL;
|
|
934 }
|
|
935
|
|
936 tdfx_vid_in_use = 0;
|
|
937
|
|
938 MOD_DEC_USE_COUNT;
|
|
939 return 0;
|
|
940 }
|
|
941
|
|
942 static long long tdfx_vid_lseek(struct file *file, long long offset, int origin)
|
|
943 {
|
|
944 return -ESPIPE;
|
|
945 }
|
|
946
|
|
947 static int tdfx_vid_open(struct inode *inode, struct file *file)
|
|
948 {
|
|
949 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,2)
|
|
950 int minor = MINOR(inode->i_rdev.value);
|
|
951 #else
|
|
952 int minor = MINOR(inode->i_rdev);
|
|
953 #endif
|
|
954
|
|
955 if(minor != 0)
|
|
956 return(-ENXIO);
|
|
957
|
|
958 if(tdfx_vid_in_use == 1)
|
|
959 return(-EBUSY);
|
|
960
|
|
961 tdfx_vid_in_use = 1;
|
|
962 MOD_INC_USE_COUNT;
|
|
963 return(0);
|
|
964 }
|
|
965
|
|
966 #if LINUX_VERSION_CODE >= 0x020400
|
|
967 static struct file_operations tdfx_vid_fops =
|
|
968 {
|
|
969 llseek: tdfx_vid_lseek,
|
|
970 read: tdfx_vid_read,
|
|
971 write: tdfx_vid_write,
|
|
972 ioctl: tdfx_vid_ioctl,
|
|
973 mmap: tdfx_vid_mmap,
|
|
974 open: tdfx_vid_open,
|
|
975 release: tdfx_vid_release
|
|
976 };
|
|
977 #else
|
|
978 static struct file_operations tdfx_vid_fops =
|
|
979 {
|
|
980 tdfx_vid_lseek,
|
|
981 tdfx_vid_read,
|
|
982 tdfx_vid_write,
|
|
983 NULL,
|
|
984 NULL,
|
|
985 tdfx_vid_ioctl,
|
|
986 tdfx_vid_mmap,
|
|
987 tdfx_vid_open,
|
|
988 NULL,
|
|
989 tdfx_vid_release
|
|
990 };
|
|
991 #endif
|
|
992
|
|
993
|
|
994 int init_module(void)
|
|
995 {
|
|
996 tdfx_vid_in_use = 0;
|
|
997
|
|
998 if(register_chrdev(TDFX_VID_MAJOR, "tdfx_vid", &tdfx_vid_fops)) {
|
|
999 printk(KERN_ERR "tdfx_vid: unable to get major: %d\n", TDFX_VID_MAJOR);
|
|
1000 return -EIO;
|
|
1001 }
|
|
1002
|
|
1003 if(!agp_init()) {
|
|
1004 printk(KERN_ERR "tdfx_vid: AGP init failed\n");
|
|
1005 unregister_chrdev(TDFX_VID_MAJOR, "tdfx_vid");
|
|
1006 return -EINVAL;
|
|
1007 }
|
|
1008
|
|
1009 if (!tdfx_vid_find_card()) {
|
|
1010 printk(KERN_ERR "tdfx_vid: no supported devices found\n");
|
|
1011 agp_close();
|
|
1012 unregister_chrdev(TDFX_VID_MAJOR, "tdfx_vid");
|
|
1013 return -EINVAL;
|
|
1014 }
|
|
1015
|
|
1016
|
|
1017
|
|
1018 return (0);
|
|
1019
|
|
1020 }
|
|
1021
|
|
1022 void cleanup_module(void)
|
|
1023 {
|
|
1024 if(tdfx_mmio_base)
|
|
1025 iounmap(tdfx_mmio_base);
|
|
1026 agp_close();
|
|
1027 printk(KERN_INFO "tdfx_vid: Cleaning up module\n");
|
|
1028 unregister_chrdev(TDFX_VID_MAJOR, "tdfx_vid");
|
|
1029 }
|