PageRenderTime 43ms CodeModel.GetById 18ms app.highlight 21ms RepoModel.GetById 1ms app.codeStats 0ms

/drivers/char/drm/sis_mm.c

https://bitbucket.org/evzijst/gittest
C | 417 lines | 288 code | 83 blank | 46 comment | 70 complexity | 206ed1f8d34ec91e86f1511911aa4503 MD5 | raw file
  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 */
 30
 31#include "drmP.h"
 32#include "sis_drm.h"
 33#include "sis_drv.h"
 34#include "sis_ds.h"
 35#if defined(__linux__) && defined(CONFIG_FB_SIS)
 36#include <video/sisfb.h>
 37#endif
 38
 39#define MAX_CONTEXT 100
 40#define VIDEO_TYPE 0 
 41#define AGP_TYPE 1
 42
 43typedef struct {
 44	int used;
 45	int context;
 46	set_t *sets[2]; /* 0 for video, 1 for AGP */
 47} sis_context_t;
 48
 49static sis_context_t global_ppriv[MAX_CONTEXT];
 50
 51
 52static int add_alloc_set(int context, int type, unsigned int val)
 53{
 54	int i, retval = 0;
 55	
 56	for (i = 0; i < MAX_CONTEXT; i++) {
 57		if (global_ppriv[i].used && global_ppriv[i].context == context)
 58		{
 59			retval = setAdd(global_ppriv[i].sets[type], val);
 60			break;
 61		}
 62	}
 63	return retval;
 64}
 65
 66static int del_alloc_set(int context, int type, unsigned int val)
 67{  
 68	int i, retval = 0;
 69
 70	for (i = 0; i < MAX_CONTEXT; i++) {
 71		if (global_ppriv[i].used && global_ppriv[i].context == context)
 72		{
 73			retval = setDel(global_ppriv[i].sets[type], val);
 74			break;
 75		}
 76	}
 77	return retval;
 78}
 79
 80/* fb management via fb device */ 
 81#if defined(__linux__) && defined(CONFIG_FB_SIS)
 82
 83static int sis_fb_init( DRM_IOCTL_ARGS )
 84{
 85	return 0;
 86}
 87
 88static int sis_fb_alloc( DRM_IOCTL_ARGS )
 89{
 90	drm_sis_mem_t fb;
 91	struct sis_memreq req;
 92	drm_sis_mem_t __user *argp = (void __user *)data;
 93	int retval = 0;
 94
 95	DRM_COPY_FROM_USER_IOCTL(fb, argp, sizeof(fb));
 96
 97	req.size = fb.size;
 98	sis_malloc(&req);
 99	if (req.offset) {
100		/* TODO */
101		fb.offset = req.offset;
102		fb.free = req.offset;
103		if (!add_alloc_set(fb.context, VIDEO_TYPE, fb.free)) {
104			DRM_DEBUG("adding to allocation set fails\n");
105			sis_free(req.offset);
106			retval = DRM_ERR(EINVAL);
107		}
108	} else {  
109		fb.offset = 0;
110		fb.size = 0;
111		fb.free = 0;
112	}
113
114	DRM_COPY_TO_USER_IOCTL(argp, fb, sizeof(fb));
115
116	DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size, req.offset);
117
118	return retval;
119}
120
121static int sis_fb_free( DRM_IOCTL_ARGS )
122{
123	drm_sis_mem_t fb;
124	int retval = 0;
125
126	DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t __user *)data, sizeof(fb));
127
128	if (!fb.free)
129		return DRM_ERR(EINVAL);
130
131	if (!del_alloc_set(fb.context, VIDEO_TYPE, fb.free))
132		retval = DRM_ERR(EINVAL);
133	sis_free((u32)fb.free);
134
135	DRM_DEBUG("free fb, offset = %lu\n", fb.free);
136
137	return retval;
138}
139
140#else
141
142/* Called by the X Server to initialize the FB heap.  Allocations will fail
143 * unless this is called.  Offset is the beginning of the heap from the
144 * framebuffer offset (MaxXFBMem in XFree86).
145 *
146 * Memory layout according to Thomas Winischofer:
147 * |------------------|DDDDDDDDDDDDDDDDDDDDDDDDDDDDD|HHHH|CCCCCCCCCCC|
148 *
149 *    X driver/sisfb                                  HW-   Command-
150 *  framebuffer memory           DRI heap           Cursor   queue
151 */
152static int sis_fb_init( DRM_IOCTL_ARGS )
153{
154	DRM_DEVICE;
155	drm_sis_private_t *dev_priv = dev->dev_private;
156	drm_sis_fb_t fb;
157
158	DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_fb_t __user *)data, sizeof(fb));
159
160	if (dev_priv == NULL) {
161		dev->dev_private = drm_calloc(1, sizeof(drm_sis_private_t),
162		    DRM_MEM_DRIVER);
163		dev_priv = dev->dev_private;
164		if (dev_priv == NULL)
165			return ENOMEM;
166	}
167
168	if (dev_priv->FBHeap != NULL)
169		return DRM_ERR(EINVAL);
170
171	dev_priv->FBHeap = mmInit(fb.offset, fb.size);
172
173	DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size);
174
175	return 0;
176}
177
178static int sis_fb_alloc( DRM_IOCTL_ARGS )
179{
180	DRM_DEVICE;
181	drm_sis_private_t *dev_priv = dev->dev_private;
182	drm_sis_mem_t __user *argp = (void __user *)data;
183	drm_sis_mem_t fb;
184	PMemBlock block;
185	int retval = 0;
186
187	if (dev_priv == NULL || dev_priv->FBHeap == NULL)
188		return DRM_ERR(EINVAL);
189  
190	DRM_COPY_FROM_USER_IOCTL(fb, argp, sizeof(fb));
191  
192	block = mmAllocMem(dev_priv->FBHeap, fb.size, 0, 0);
193	if (block) {
194		/* TODO */
195		fb.offset = block->ofs;
196		fb.free = (unsigned long)block;
197		if (!add_alloc_set(fb.context, VIDEO_TYPE, fb.free)) {
198			DRM_DEBUG("adding to allocation set fails\n");
199			mmFreeMem((PMemBlock)fb.free);
200			retval = DRM_ERR(EINVAL);
201		}
202	} else {
203		fb.offset = 0;
204		fb.size = 0;
205		fb.free = 0;
206	}
207
208	DRM_COPY_TO_USER_IOCTL(argp, fb, sizeof(fb));
209
210	DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size, fb.offset);
211
212	return retval;
213}
214
215static int sis_fb_free( DRM_IOCTL_ARGS )
216{
217	DRM_DEVICE;
218	drm_sis_private_t *dev_priv = dev->dev_private;
219	drm_sis_mem_t fb;
220
221	if (dev_priv == NULL || dev_priv->FBHeap == NULL)
222		return DRM_ERR(EINVAL);
223
224	DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t __user *)data, sizeof(fb));
225
226	if (!mmBlockInHeap(dev_priv->FBHeap, (PMemBlock)fb.free))
227		return DRM_ERR(EINVAL);
228
229	if (!del_alloc_set(fb.context, VIDEO_TYPE, fb.free))
230		return DRM_ERR(EINVAL);
231	mmFreeMem((PMemBlock)fb.free);
232
233	DRM_DEBUG("free fb, free = 0x%lx\n", fb.free);
234
235	return 0;
236}
237
238#endif
239
240/* agp memory management */ 
241
242static int sis_ioctl_agp_init( DRM_IOCTL_ARGS )
243{
244	DRM_DEVICE;
245	drm_sis_private_t *dev_priv = dev->dev_private;
246	drm_sis_agp_t agp;
247
248	if (dev_priv == NULL) {
249		dev->dev_private = drm_calloc(1, sizeof(drm_sis_private_t),
250		    DRM_MEM_DRIVER);
251		dev_priv = dev->dev_private;
252		if (dev_priv == NULL)
253			return ENOMEM;
254	}
255
256	if (dev_priv->AGPHeap != NULL)
257		return DRM_ERR(EINVAL);
258
259	DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_agp_t __user *)data, sizeof(agp));
260
261	dev_priv->AGPHeap = mmInit(agp.offset, agp.size);
262
263	DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size);
264  
265	return 0;
266}
267
268static int sis_ioctl_agp_alloc( DRM_IOCTL_ARGS )
269{
270	DRM_DEVICE;
271	drm_sis_private_t *dev_priv = dev->dev_private;
272	drm_sis_mem_t __user *argp = (void __user *)data;
273	drm_sis_mem_t agp;
274	PMemBlock block;
275	int retval = 0;
276   
277	if (dev_priv == NULL || dev_priv->AGPHeap == NULL)
278		return DRM_ERR(EINVAL);
279  
280	DRM_COPY_FROM_USER_IOCTL(agp, argp, sizeof(agp));
281  
282	block = mmAllocMem(dev_priv->AGPHeap, agp.size, 0, 0);
283	if (block) {
284		/* TODO */
285		agp.offset = block->ofs;
286		agp.free = (unsigned long)block;
287		if (!add_alloc_set(agp.context, AGP_TYPE, agp.free)) {
288			DRM_DEBUG("adding to allocation set fails\n");
289			mmFreeMem((PMemBlock)agp.free);
290			retval = -1;
291		}
292	} else {  
293		agp.offset = 0;
294		agp.size = 0;
295		agp.free = 0;
296	}
297
298	DRM_COPY_TO_USER_IOCTL(argp, agp, sizeof(agp));
299
300	DRM_DEBUG("alloc agp, size = %d, offset = %d\n", agp.size, agp.offset);
301
302	return retval;
303}
304
305static int sis_ioctl_agp_free( DRM_IOCTL_ARGS )
306{
307	DRM_DEVICE;
308	drm_sis_private_t *dev_priv = dev->dev_private;
309	drm_sis_mem_t agp;
310
311	if (dev_priv == NULL || dev_priv->AGPHeap == NULL)
312		return DRM_ERR(EINVAL);
313
314	DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_mem_t __user *)data, sizeof(agp));
315
316	if (!mmBlockInHeap(dev_priv->AGPHeap, (PMemBlock)agp.free))
317		return DRM_ERR(EINVAL);
318
319	mmFreeMem((PMemBlock)agp.free);
320	if (!del_alloc_set(agp.context, AGP_TYPE, agp.free))
321		return DRM_ERR(EINVAL);
322
323	DRM_DEBUG("free agp, free = 0x%lx\n", agp.free);
324
325	return 0;
326}
327
328int sis_init_context(struct drm_device *dev, int context)
329{
330	int i;
331
332	for (i = 0; i < MAX_CONTEXT ; i++) {
333		if (global_ppriv[i].used &&
334		    (global_ppriv[i].context == context))
335			break;
336	}
337
338	if (i >= MAX_CONTEXT) {
339		for (i = 0; i < MAX_CONTEXT ; i++) {
340			if (!global_ppriv[i].used) {
341				global_ppriv[i].context = context;
342				global_ppriv[i].used = 1;
343				global_ppriv[i].sets[0] = setInit();
344				global_ppriv[i].sets[1] = setInit();
345				DRM_DEBUG("init allocation set, socket=%d, "
346				    "context = %d\n", i, context);
347				break;
348			}
349		}
350		if ((i >= MAX_CONTEXT) || (global_ppriv[i].sets[0] == NULL) ||
351		    (global_ppriv[i].sets[1] == NULL))
352		{
353			return 0;
354		}
355	}
356	
357	return 1;
358}
359
360int sis_final_context(struct drm_device *dev, int context)
361{
362	int i;
363
364	for (i=0; i<MAX_CONTEXT; i++) {
365		if (global_ppriv[i].used &&
366		    (global_ppriv[i].context == context))
367			break;
368	}
369
370	if (i < MAX_CONTEXT) {
371		set_t *set;
372		unsigned int item;
373		int retval;
374
375		DRM_DEBUG("find socket %d, context = %d\n", i, context);
376
377		/* Video Memory */
378		set = global_ppriv[i].sets[0];
379		retval = setFirst(set, &item);
380		while (retval) {
381			DRM_DEBUG("free video memory 0x%x\n", item);
382#if defined(__linux__) && defined(CONFIG_FB_SIS)
383			sis_free(item);
384#else
385			mmFreeMem((PMemBlock)item);
386#endif
387			retval = setNext(set, &item);
388		}
389		setDestroy(set);
390
391		/* AGP Memory */
392		set = global_ppriv[i].sets[1];
393		retval = setFirst(set, &item);
394		while (retval) {
395			DRM_DEBUG("free agp memory 0x%x\n", item);
396			mmFreeMem((PMemBlock)item);
397			retval = setNext(set, &item);
398		}
399		setDestroy(set);
400
401		global_ppriv[i].used = 0;	  
402        }
403	
404	return 1;
405}
406
407drm_ioctl_desc_t sis_ioctls[] = {
408	[DRM_IOCTL_NR(DRM_SIS_FB_ALLOC)]  = { sis_fb_alloc,        1, 0 },
409	[DRM_IOCTL_NR(DRM_SIS_FB_FREE)]   = { sis_fb_free,         1, 0 },
410	[DRM_IOCTL_NR(DRM_SIS_AGP_INIT)]  = { sis_ioctl_agp_init,  1, 1 },
411	[DRM_IOCTL_NR(DRM_SIS_AGP_ALLOC)] = { sis_ioctl_agp_alloc, 1, 0 },
412	[DRM_IOCTL_NR(DRM_SIS_AGP_FREE)]  = { sis_ioctl_agp_free,  1, 0 },
413	[DRM_IOCTL_NR(DRM_SIS_FB_INIT)]   = { sis_fb_init,         1, 1 }
414};
415
416int sis_max_ioctl = DRM_ARRAY_SIZE(sis_ioctls);
417