OSDN Git Service

This patch adds three new ioctl's to the VIA Unichrome/Pro DRM driver:
[android-x86/external-libdrm.git] / shared-core / via_mm.c
1 /*
2  * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
3  * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sub license,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial portions
14  * of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19  * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  */
24 #define __NO_VERSION__
25 #include "via.h"
26 #include "drmP.h"
27 #include "via_drm.h"
28 #include "via_drv.h"
29 #include "via_ds.h"
30 #include "via_mm.h"
31
32 #define MAX_CONTEXT 100
33
34 unsigned int VIA_DEBUG = 1;
35
36 typedef struct {
37         int used;
38         int context;
39         set_t *sets[2]; /* 0 for frame buffer, 1 for AGP , 2 for System*/
40 } via_context_t;
41
42 static via_context_t global_ppriv[MAX_CONTEXT];
43
44 static int add_alloc_set(int context, int type, unsigned int val)
45 {
46         int i, retval = 0;
47   
48         for (i = 0; i < MAX_CONTEXT; i++) {
49                 if (global_ppriv[i].used && 
50                     global_ppriv[i].context == context) {
51                         retval = via_setAdd(global_ppriv[i].sets[type], val);
52                         break;
53                 }
54         }
55   
56         return retval;
57 }
58
59 static int del_alloc_set(int context, int type, unsigned int val)
60 {  
61         int i, retval = 0;
62   
63         for (i = 0; i < MAX_CONTEXT; i++)
64                 if (global_ppriv[i].used && 
65                     global_ppriv[i].context == context) {
66                         retval = via_setDel(global_ppriv[i].sets[type], val);
67                         break;
68                 }
69   
70         return retval;
71 }
72
73 /* agp memory management */ 
74 static memHeap_t *AgpHeap = NULL;
75
76 int via_agp_init( DRM_IOCTL_ARGS )
77 {
78         drm_via_agp_t agp;
79   
80         DRM_COPY_FROM_USER_IOCTL(agp, (drm_via_agp_t *)data, sizeof(agp));
81
82         AgpHeap = via_mmInit(agp.offset, agp.size);
83
84         DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size);
85   
86         return 0;
87 }
88
89 /* fb memory management */ 
90 static memHeap_t *FBHeap = NULL;
91
92 int via_fb_init( DRM_IOCTL_ARGS )
93 {
94         drm_via_fb_t fb;
95
96    
97         DRM_COPY_FROM_USER_IOCTL(fb, (drm_via_fb_t *)data, sizeof(fb));
98
99         FBHeap = via_mmInit(fb.offset, fb.size);
100
101         DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size);
102
103         return 0;
104 }
105
106 int via_init_context(struct drm_device *dev, int context)
107 {
108         int i;
109     
110         for (i = 0; i < MAX_CONTEXT ; i++)
111                 if (global_ppriv[i].used && 
112                     (global_ppriv[i].context == context))
113                         break;
114     
115         if (i >= MAX_CONTEXT) {
116                 for (i = 0; i < MAX_CONTEXT ; i++) {
117                         if (!global_ppriv[i].used) {
118                                 global_ppriv[i].context = context;
119                                 global_ppriv[i].used = 1;
120                                 global_ppriv[i].sets[0] = via_setInit();
121                                 global_ppriv[i].sets[1] = via_setInit();
122                                 DRM_DEBUG("init allocation set, socket=%d,"
123                                           " context = %d\n", i, context);
124                                 break;
125                         }
126                 }
127         
128                 if ((i >= MAX_CONTEXT) || (global_ppriv[i].sets[0] == NULL) ||
129                     (global_ppriv[i].sets[1] == NULL)) {
130                         return 0;
131                 }
132         }
133     
134         return 1;
135 }
136
137 int via_final_context(struct drm_device *dev, int context)
138 {
139         int i;
140         for (i=0; i<MAX_CONTEXT; i++)
141                 if (global_ppriv[i].used && 
142                     (global_ppriv[i].context == context))
143                         break;
144     
145         if (i < MAX_CONTEXT) {
146                 set_t *set;
147                 unsigned int item;
148                 int retval;
149           
150                 DRM_DEBUG("find socket %d, context = %d\n", i, context);
151             
152                 /* Video Memory */
153                 set = global_ppriv[i].sets[0];
154                 retval = via_setFirst(set, &item);
155                 while (retval) {
156                         DRM_DEBUG("free video memory 0x%x\n", item);
157                         via_mmFreeMem((PMemBlock)item);
158                         retval = via_setNext(set, &item);
159                 }
160                 via_setDestroy(set);
161             
162                 /* AGP Memory */
163                 set = global_ppriv[i].sets[1];
164                 retval = via_setFirst(set, &item);
165                 while (retval) {
166                         DRM_DEBUG("free agp memory 0x%x\n", item);
167                         via_mmFreeMem((PMemBlock)item);
168                         retval = via_setNext(set, &item);
169                 }
170                 via_setDestroy(set);
171         
172                 global_ppriv[i].used = 0;         
173         }
174
175 #if defined(__linux__)
176         /* Linux specific until context tracking code gets ported to BSD */
177         /* Last context, perform cleanup */
178         if (dev->ctx_count == 1 && dev->dev_private) {
179                 if (dev->irq) DRM(irq_uninstall)(dev);
180
181                 via_do_cleanup_map(dev);
182         }
183 #endif
184     
185         return 1;
186 }
187 int via_mem_alloc( DRM_IOCTL_ARGS)
188 {
189         drm_via_mem_t mem;
190     
191         DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t *)data, sizeof(mem));
192         switch (mem.type) {
193         case VIDEO :
194                 if (via_fb_alloc(&mem) < 0)
195                         return -EFAULT;
196                 DRM_COPY_TO_USER_IOCTL((drm_via_mem_t *)data, mem, 
197                                        sizeof(mem));
198                 return 0;
199         case AGP :
200                 if (via_agp_alloc(&mem) < 0)
201                         return -EFAULT;
202                 DRM_COPY_TO_USER_IOCTL((drm_via_mem_t *)data, mem, 
203                                        sizeof(mem));
204                 return 0;
205         }
206
207         return -EFAULT;
208 }
209
210 int via_fb_alloc(drm_via_mem_t* mem)
211 {
212         drm_via_mm_t fb;
213         PMemBlock block;
214         int retval = 0;
215    
216         if (!FBHeap)
217                 return -1;
218
219         fb.size = mem->size;
220         fb.context = mem->context;
221   
222         block = via_mmAllocMem(FBHeap, fb.size, 5, 0);
223         if (block) {
224                 fb.offset = block->ofs;
225                 fb.free = (unsigned int)block;
226                 if (!add_alloc_set(fb.context, VIDEO, fb.free)) {
227                         DRM_DEBUG("adding to allocation set fails\n");
228                         via_mmFreeMem((PMemBlock)fb.free);
229                         retval = -1;
230                 }
231         }
232         else {  
233                 fb.offset = 0;
234                 fb.size = 0;
235                 fb.free = 0;
236                 retval = -1;
237         }
238    
239         mem->offset = fb.offset;
240         mem->index = fb.free;
241
242         DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size, 
243                   (int)fb.offset);
244   
245         return retval;
246 }
247 int via_agp_alloc(drm_via_mem_t* mem)
248 {
249         drm_via_mm_t agp;
250         PMemBlock block;
251         int retval = 0;
252
253         if (!AgpHeap)
254                 return -1;
255
256         agp.size = mem->size;
257         agp.context = mem->context;
258   
259         block = via_mmAllocMem(AgpHeap, agp.size, 5, 0);
260         if (block) {
261                 agp.offset = block->ofs;
262                 agp.free = (unsigned int)block;
263                 if (!add_alloc_set(agp.context, AGP, agp.free)) {
264                         DRM_DEBUG("adding to allocation set fails\n");
265                         via_mmFreeMem((PMemBlock)agp.free);
266                         retval = -1;
267                 }
268         }
269         else {  
270                 agp.offset = 0;
271                 agp.size = 0;
272                 agp.free = 0;
273         }       
274    
275         mem->offset = agp.offset;
276         mem->index = agp.free;
277
278         DRM_DEBUG("alloc agp, size = %d, offset = %d\n", agp.size, 
279                   (unsigned int)agp.offset);
280         return retval;
281 }
282
283 int via_mem_free( DRM_IOCTL_ARGS )
284 {
285         drm_via_mem_t mem;
286     
287         DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t *)data, sizeof(mem));
288
289         switch (mem.type) {
290
291         case VIDEO :
292                 if (via_fb_free(&mem) == 0)
293                         return 0;
294                 break;
295         case AGP :
296                 if (via_agp_free(&mem) == 0)
297                         return 0;
298                 break;
299         }
300     
301         return -EFAULT;
302 }
303 int via_fb_free(drm_via_mem_t* mem)
304 {
305         drm_via_mm_t fb;
306         int retval = 0;
307
308     
309         if (!FBHeap) {
310                 return -1;
311         }
312
313         fb.free = mem->index;
314         fb.context = mem->context;
315     
316         if (!fb.free)
317                 {
318                         return -1;
319
320                 }
321
322         via_mmFreeMem((PMemBlock)fb.free);
323     
324         if (!del_alloc_set(fb.context, VIDEO, fb.free))
325                 {
326                         retval = -1;
327                 }
328     
329         DRM_DEBUG("free fb, free = %d\n", fb.free);
330     
331         return retval;
332
333 int via_agp_free(drm_via_mem_t* mem)
334 {
335         drm_via_mm_t agp;
336   
337         int retval = 0;
338
339         agp.free = mem->index;
340         agp.context = mem->context;
341     
342         if (!agp.free)
343                 return -1;
344
345         via_mmFreeMem((PMemBlock)agp.free);
346     
347         if (!del_alloc_set(agp.context, AGP, agp.free)) {
348                 retval = -1;
349         }
350
351         DRM_DEBUG("free agp, free = %d\n", agp.free);
352   
353         return retval;
354 }
355
356 EXPORT_SYMBOL(via_fb_alloc);
357 EXPORT_SYMBOL(via_fb_free);
358
359 void DRM(driver_register_fns)(drm_device_t *dev)
360 {
361   dev->fn_tbl.context_ctor = via_init_context;
362   dev->fn_tbl.context_dtor = via_final_context;
363 }