]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/drm/sis_mm.c
This commit was generated by cvs2svn to compensate for changes in r146895,
[FreeBSD/FreeBSD.git] / sys / dev / drm / sis_mm.c
1 /* sis_mm.c -- Private header for Direct Rendering Manager -*- linux-c -*-
2  * Created: Mon Jan  4 10:05:05 1999 by sclin@sis.com.tw */
3 /*-
4  * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.
5  * All rights reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11  * and/or sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the next
15  * paragraph) shall be included in all copies or substantial portions of the
16  * Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21  * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
22  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24  * DEALINGS IN THE SOFTWARE.
25  *
26  * Authors:
27  *    Sung-Ching Lin <sclin@sis.com.tw>
28  *
29  * $FreeBSD$
30  */
31
32 #if defined(__linux__) && defined(CONFIG_FB_SIS)
33 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
34 #include <video/sisfb.h>
35 #else
36 #include <linux/sisfb.h>
37 #endif
38 #endif
39 #include "dev/drm/drmP.h"
40 #include "dev/drm/sis_drm.h"
41 #include "dev/drm/sis_drv.h"
42 #include "dev/drm/sis_ds.h"
43
44 #define MAX_CONTEXT 100
45 #define VIDEO_TYPE 0
46 #define AGP_TYPE 1
47
48 typedef struct {
49         int used;
50         int context;
51         set_t *sets[2];         /* 0 for video, 1 for AGP */
52 } sis_context_t;
53
54 static sis_context_t global_ppriv[MAX_CONTEXT];
55
56 static int add_alloc_set(int context, int type, unsigned int val)
57 {
58         int i, retval = 0;
59
60         for (i = 0; i < MAX_CONTEXT; i++) {
61                 if (global_ppriv[i].used && global_ppriv[i].context == context) {
62                         retval = setAdd(global_ppriv[i].sets[type], val);
63                         break;
64                 }
65         }
66         return retval;
67 }
68
69 static int del_alloc_set(int context, int type, unsigned int val)
70 {
71         int i, retval = 0;
72
73         for (i = 0; i < MAX_CONTEXT; i++) {
74                 if (global_ppriv[i].used && global_ppriv[i].context == context) {
75                         retval = setDel(global_ppriv[i].sets[type], val);
76                         break;
77                 }
78         }
79         return retval;
80 }
81
82 /* fb management via fb device */
83 #if defined(__linux__) && defined(CONFIG_FB_SIS)
84
85 static int sis_fb_init(DRM_IOCTL_ARGS)
86 {
87         return 0;
88 }
89
90 static int sis_fb_alloc(DRM_IOCTL_ARGS)
91 {
92         drm_sis_mem_t fb;
93         struct sis_memreq req;
94         drm_sis_mem_t __user *argp = (void __user *)data;
95         int retval = 0;
96
97         DRM_COPY_FROM_USER_IOCTL(fb, argp, sizeof(fb));
98
99         req.size = fb.size;
100         sis_malloc(&req);
101         if (req.offset) {
102                 /* TODO */
103                 fb.offset = req.offset;
104                 fb.free = req.offset;
105                 if (!add_alloc_set(fb.context, VIDEO_TYPE, fb.free)) {
106                         DRM_DEBUG("adding to allocation set fails\n");
107                         sis_free(req.offset);
108                         retval = DRM_ERR(EINVAL);
109                 }
110         } else {
111                 fb.offset = 0;
112                 fb.size = 0;
113                 fb.free = 0;
114         }
115
116         DRM_COPY_TO_USER_IOCTL(argp, fb, sizeof(fb));
117
118         DRM_DEBUG("alloc fb, size = %d, offset = %ld\n", fb.size, req.offset);
119
120         return retval;
121 }
122
123 static int sis_fb_free(DRM_IOCTL_ARGS)
124 {
125         drm_sis_mem_t fb;
126         int retval = 0;
127
128         DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t __user *) data, sizeof(fb));
129
130         if (!fb.free)
131                 return DRM_ERR(EINVAL);
132
133         if (!del_alloc_set(fb.context, VIDEO_TYPE, fb.free))
134                 retval = DRM_ERR(EINVAL);
135         sis_free(fb.free);
136
137         DRM_DEBUG("free fb, offset = 0x%lx\n", fb.free);
138
139         return retval;
140 }
141
142 #else
143
144 /* Called by the X Server to initialize the FB heap.  Allocations will fail
145  * unless this is called.  Offset is the beginning of the heap from the
146  * framebuffer offset (MaxXFBMem in XFree86).
147  *
148  * Memory layout according to Thomas Winischofer:
149  * |------------------|DDDDDDDDDDDDDDDDDDDDDDDDDDDDD|HHHH|CCCCCCCCCCC|
150  *
151  *    X driver/sisfb                                  HW-   Command-
152  *  framebuffer memory           DRI heap           Cursor   queue
153  */
154 static int sis_fb_init(DRM_IOCTL_ARGS)
155 {
156         DRM_DEVICE;
157         drm_sis_private_t *dev_priv = dev->dev_private;
158         drm_sis_fb_t fb;
159
160         DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_fb_t __user *) data, sizeof(fb));
161
162         if (dev_priv == NULL) {
163                 dev->dev_private = drm_calloc(1, sizeof(drm_sis_private_t),
164                                               DRM_MEM_DRIVER);
165                 dev_priv = dev->dev_private;
166                 if (dev_priv == NULL)
167                         return ENOMEM;
168         }
169
170         if (dev_priv->FBHeap != NULL)
171                 return DRM_ERR(EINVAL);
172
173         dev_priv->FBHeap = mmInit(fb.offset, fb.size);
174
175         DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size);
176
177         return 0;
178 }
179
180 static int sis_fb_alloc(DRM_IOCTL_ARGS)
181 {
182         DRM_DEVICE;
183         drm_sis_private_t *dev_priv = dev->dev_private;
184         drm_sis_mem_t __user *argp = (void __user *)data;
185         drm_sis_mem_t fb;
186         PMemBlock block;
187         int retval = 0;
188
189         if (dev_priv == NULL || dev_priv->FBHeap == NULL)
190                 return DRM_ERR(EINVAL);
191
192         DRM_COPY_FROM_USER_IOCTL(fb, argp, sizeof(fb));
193
194         block = mmAllocMem(dev_priv->FBHeap, fb.size, 0, 0);
195         if (block) {
196                 /* TODO */
197                 fb.offset = block->ofs;
198                 fb.free = (unsigned long)block;
199                 if (!add_alloc_set(fb.context, VIDEO_TYPE, fb.free)) {
200                         DRM_DEBUG("adding to allocation set fails\n");
201                         mmFreeMem((PMemBlock) fb.free);
202                         retval = DRM_ERR(EINVAL);
203                 }
204         } else {
205                 fb.offset = 0;
206                 fb.size = 0;
207                 fb.free = 0;
208         }
209
210         DRM_COPY_TO_USER_IOCTL(argp, fb, sizeof(fb));
211
212         DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size, fb.offset);
213
214         return retval;
215 }
216
217 static int sis_fb_free(DRM_IOCTL_ARGS)
218 {
219         DRM_DEVICE;
220         drm_sis_private_t *dev_priv = dev->dev_private;
221         drm_sis_mem_t fb;
222
223         if (dev_priv == NULL || dev_priv->FBHeap == NULL)
224                 return DRM_ERR(EINVAL);
225
226         DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t __user *) data, sizeof(fb));
227
228         if (!mmBlockInHeap(dev_priv->FBHeap, (PMemBlock) fb.free))
229                 return DRM_ERR(EINVAL);
230
231         if (!del_alloc_set(fb.context, VIDEO_TYPE, fb.free))
232                 return DRM_ERR(EINVAL);
233         mmFreeMem((PMemBlock) fb.free);
234
235         DRM_DEBUG("free fb, free = 0x%lx\n", fb.free);
236
237         return 0;
238 }
239
240 #endif
241
242 /* agp memory management */
243
244 static int sis_ioctl_agp_init(DRM_IOCTL_ARGS)
245 {
246         DRM_DEVICE;
247         drm_sis_private_t *dev_priv = dev->dev_private;
248         drm_sis_agp_t agp;
249
250         if (dev_priv == NULL) {
251                 dev->dev_private = drm_calloc(1, sizeof(drm_sis_private_t),
252                                               DRM_MEM_DRIVER);
253                 dev_priv = dev->dev_private;
254                 if (dev_priv == NULL)
255                         return ENOMEM;
256         }
257
258         if (dev_priv->AGPHeap != NULL)
259                 return DRM_ERR(EINVAL);
260
261         DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_agp_t __user *) data,
262                                  sizeof(agp));
263
264         dev_priv->AGPHeap = mmInit(agp.offset, agp.size);
265
266         DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size);
267
268         return 0;
269 }
270
271 static int sis_ioctl_agp_alloc(DRM_IOCTL_ARGS)
272 {
273         DRM_DEVICE;
274         drm_sis_private_t *dev_priv = dev->dev_private;
275         drm_sis_mem_t __user *argp = (drm_sis_mem_t __user *)data;
276         drm_sis_mem_t agp;
277         PMemBlock block;
278         int retval = 0;
279
280         if (dev_priv == NULL || dev_priv->AGPHeap == NULL)
281                 return DRM_ERR(EINVAL);
282
283         DRM_COPY_FROM_USER_IOCTL(agp, argp, sizeof(agp));
284
285         block = mmAllocMem(dev_priv->AGPHeap, agp.size, 0, 0);
286         if (block) {
287                 /* TODO */
288                 agp.offset = block->ofs;
289                 agp.free = (unsigned long)block;
290                 if (!add_alloc_set(agp.context, AGP_TYPE, agp.free)) {
291                         DRM_DEBUG("adding to allocation set fails\n");
292                         mmFreeMem((PMemBlock) agp.free);
293                         retval = -1;
294                 }
295         } else {
296                 agp.offset = 0;
297                 agp.size = 0;
298                 agp.free = 0;
299         }
300
301         DRM_COPY_TO_USER_IOCTL(argp, agp, sizeof(agp));
302
303         DRM_DEBUG("alloc agp, size = %d, offset = %d\n", agp.size, agp.offset);
304
305         return retval;
306 }
307
308 static int sis_ioctl_agp_free(DRM_IOCTL_ARGS)
309 {
310         DRM_DEVICE;
311         drm_sis_private_t *dev_priv = dev->dev_private;
312         drm_sis_mem_t agp;
313
314         if (dev_priv == NULL || dev_priv->AGPHeap == NULL)
315                 return DRM_ERR(EINVAL);
316
317         DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_mem_t __user *) data,
318                                  sizeof(agp));
319
320         if (!mmBlockInHeap(dev_priv->AGPHeap, (PMemBlock) agp.free))
321                 return DRM_ERR(EINVAL);
322
323         mmFreeMem((PMemBlock) agp.free);
324         if (!del_alloc_set(agp.context, AGP_TYPE, agp.free))
325                 return DRM_ERR(EINVAL);
326
327         DRM_DEBUG("free agp, free = 0x%lx\n", agp.free);
328
329         return 0;
330 }
331
332 int sis_init_context(struct drm_device *dev, int context)
333 {
334         int i;
335
336         for (i = 0; i < MAX_CONTEXT; i++) {
337                 if (global_ppriv[i].used &&
338                     (global_ppriv[i].context == context))
339                         break;
340         }
341
342         if (i >= MAX_CONTEXT) {
343                 for (i = 0; i < MAX_CONTEXT; i++) {
344                         if (!global_ppriv[i].used) {
345                                 global_ppriv[i].context = context;
346                                 global_ppriv[i].used = 1;
347                                 global_ppriv[i].sets[0] = setInit();
348                                 global_ppriv[i].sets[1] = setInit();
349                                 DRM_DEBUG("init allocation set, socket=%d, "
350                                           "context = %d\n", i, context);
351                                 break;
352                         }
353                 }
354                 if ((i >= MAX_CONTEXT) || (global_ppriv[i].sets[0] == NULL) ||
355                     (global_ppriv[i].sets[1] == NULL)) {
356                         return 0;
357                 }
358         }
359
360         return 1;
361 }
362
363 int sis_final_context(struct drm_device *dev, int context)
364 {
365         int i;
366
367         for (i = 0; i < MAX_CONTEXT; i++) {
368                 if (global_ppriv[i].used &&
369                     (global_ppriv[i].context == context))
370                         break;
371         }
372
373         if (i < MAX_CONTEXT) {
374                 set_t *set;
375                 ITEM_TYPE item;
376                 int retval;
377
378                 DRM_DEBUG("find socket %d, context = %d\n", i, context);
379
380                 /* Video Memory */
381                 set = global_ppriv[i].sets[0];
382                 retval = setFirst(set, &item);
383                 while (retval) {
384                         DRM_DEBUG("free video memory 0x%lx\n", item);
385 #if defined(__linux__) && defined(CONFIG_FB_SIS)
386                         sis_free(item);
387 #else
388                         mmFreeMem((PMemBlock) item);
389 #endif
390                         retval = setNext(set, &item);
391                 }
392                 setDestroy(set);
393
394                 /* AGP Memory */
395                 set = global_ppriv[i].sets[1];
396                 retval = setFirst(set, &item);
397                 while (retval) {
398                         DRM_DEBUG("free agp memory 0x%lx\n", item);
399                         mmFreeMem((PMemBlock) item);
400                         retval = setNext(set, &item);
401                 }
402                 setDestroy(set);
403
404                 global_ppriv[i].used = 0;
405         }
406
407         return 1;
408 }
409
410 drm_ioctl_desc_t sis_ioctls[] = {
411         [DRM_IOCTL_NR(DRM_SIS_FB_ALLOC)] = {sis_fb_alloc, 1, 0},
412         [DRM_IOCTL_NR(DRM_SIS_FB_FREE)] = {sis_fb_free, 1, 0},
413         [DRM_IOCTL_NR(DRM_SIS_AGP_INIT)] = {sis_ioctl_agp_init, 1, 1},
414         [DRM_IOCTL_NR(DRM_SIS_AGP_ALLOC)] = {sis_ioctl_agp_alloc, 1, 0},
415         [DRM_IOCTL_NR(DRM_SIS_AGP_FREE)] = {sis_ioctl_agp_free, 1, 0},
416         [DRM_IOCTL_NR(DRM_SIS_FB_INIT)] = {sis_fb_init, 1, 1}
417 };
418
419 int sis_max_ioctl = DRM_ARRAY_SIZE(sis_ioctls);