~ubuntu-branches/ubuntu/gutsy/vnc4/gutsy

« back to all changes in this revision

Viewing changes to unix/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drm_bufs.h

  • Committer: Bazaar Package Importer
  • Author(s): Ola Lundqvist
  • Date: 2006-05-15 20:35:17 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20060515203517-l4lre1ku942mn26k
Tags: 4.1.1+X4.3.0-10
* Correction of critical security issue. Thanks to Martin Kogler
  <e9925248@student.tuwien.ac.at> that informed me about the issue,
  and provided the patch.
  This flaw was originally found by Steve Wiseman of intelliadmin.com.
* Applied patch from Javier Kohen <jkohen@users.sourceforge.net> that
  inform the user that only 8 first characters of the password will
  actually be used when typing more than 8 characters, closes:
  #355619.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* drm_bufs.h -- Generic buffer template -*- linux-c -*-
 
2
 * Created: Thu Nov 23 03:10:50 2000 by gareth@valinux.com
 
3
 *
 
4
 * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
 
5
 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
 
6
 * All Rights Reserved.
 
7
 *
 
8
 * Permission is hereby granted, free of charge, to any person obtaining a
 
9
 * copy of this software and associated documentation files (the "Software"),
 
10
 * to deal in the Software without restriction, including without limitation
 
11
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 
12
 * and/or sell copies of the Software, and to permit persons to whom the
 
13
 * Software is furnished to do so, subject to the following conditions:
 
14
 *
 
15
 * The above copyright notice and this permission notice (including the next
 
16
 * paragraph) shall be included in all copies or substantial portions of the
 
17
 * Software.
 
18
 *
 
19
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
20
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
21
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 
22
 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 
23
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 
24
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 
25
 * OTHER DEALINGS IN THE SOFTWARE.
 
26
 *
 
27
 * Authors:
 
28
 *    Rickard E. (Rik) Faith <faith@valinux.com>
 
29
 *    Gareth Hughes <gareth@valinux.com>
 
30
 */
 
31
 
 
32
#define __NO_VERSION__
 
33
#include <linux/vmalloc.h>
 
34
#include "drmP.h"
 
35
 
 
36
#ifndef __HAVE_PCI_DMA
 
37
#define __HAVE_PCI_DMA          0
 
38
#endif
 
39
 
 
40
#ifndef __HAVE_SG
 
41
#define __HAVE_SG               0
 
42
#endif
 
43
 
 
44
#ifndef DRIVER_BUF_PRIV_T
 
45
#define DRIVER_BUF_PRIV_T               u32
 
46
#endif
 
47
#ifndef DRIVER_AGP_BUFFERS_MAP
 
48
#if __HAVE_AGP && __HAVE_DMA
 
49
#error "You must define DRIVER_AGP_BUFFERS_MAP()"
 
50
#else
 
51
#define DRIVER_AGP_BUFFERS_MAP( dev )   NULL
 
52
#endif
 
53
#endif
 
54
 
 
55
/*
 
56
 * Compute order.  Can be made faster.
 
57
 */
 
58
int DRM(order)( unsigned long size )
 
59
{
 
60
        int order;
 
61
        unsigned long tmp;
 
62
 
 
63
        for ( order = 0, tmp = size ; tmp >>= 1 ; ++order );
 
64
 
 
65
        if ( size & ~(1 << order) )
 
66
                ++order;
 
67
 
 
68
        return order;
 
69
}
 
70
 
 
71
int DRM(addmap)( struct inode *inode, struct file *filp,
 
72
                 unsigned int cmd, unsigned long arg )
 
73
{
 
74
        drm_file_t *priv = filp->private_data;
 
75
        drm_device_t *dev = priv->dev;
 
76
        drm_map_t *map;
 
77
        drm_map_list_t *list;
 
78
 
 
79
        if ( !(filp->f_mode & 3) ) return -EACCES; /* Require read/write */
 
80
 
 
81
        map = DRM(alloc)( sizeof(*map), DRM_MEM_MAPS );
 
82
        if ( !map )
 
83
                return -ENOMEM;
 
84
 
 
85
        if ( copy_from_user( map, (drm_map_t *)arg, sizeof(*map) ) ) {
 
86
                DRM(free)( map, sizeof(*map), DRM_MEM_MAPS );
 
87
                return -EFAULT;
 
88
        }
 
89
 
 
90
        /* Only allow shared memory to be removable since we only keep enough
 
91
         * book keeping information about shared memory to allow for removal
 
92
         * when processes fork.
 
93
         */
 
94
        if ( (map->flags & _DRM_REMOVABLE) && map->type != _DRM_SHM ) {
 
95
                DRM(free)( map, sizeof(*map), DRM_MEM_MAPS );
 
96
                return -EINVAL;
 
97
        }
 
98
        DRM_DEBUG( "offset = 0x%08lx, size = 0x%08lx, type = %d\n",
 
99
                   map->offset, map->size, map->type );
 
100
        if ( (map->offset & (~PAGE_MASK)) || (map->size & (~PAGE_MASK)) ) {
 
101
                DRM(free)( map, sizeof(*map), DRM_MEM_MAPS );
 
102
                return -EINVAL;
 
103
        }
 
104
        map->mtrr   = -1;
 
105
        map->handle = 0;
 
106
 
 
107
        switch ( map->type ) {
 
108
        case _DRM_REGISTERS:
 
109
        case _DRM_FRAME_BUFFER:
 
110
#if !defined(__sparc__) && !defined(__alpha__)
 
111
                if ( map->offset + map->size < map->offset ||
 
112
                     map->offset < virt_to_phys(high_memory) ) {
 
113
                        DRM(free)( map, sizeof(*map), DRM_MEM_MAPS );
 
114
                        return -EINVAL;
 
115
                }
 
116
#endif
 
117
#ifdef __alpha__
 
118
                map->offset += dev->hose->mem_space->start;
 
119
#endif
 
120
#if __REALLY_HAVE_MTRR
 
121
                if ( map->type == _DRM_FRAME_BUFFER ||
 
122
                     (map->flags & _DRM_WRITE_COMBINING) ) {
 
123
                        map->mtrr = mtrr_add( map->offset, map->size,
 
124
                                              MTRR_TYPE_WRCOMB, 1 );
 
125
                }
 
126
#endif
 
127
                map->handle = DRM(ioremap)( map->offset, map->size );
 
128
                break;
 
129
 
 
130
        case _DRM_SHM:
 
131
                map->handle = vmalloc_32(map->size);
 
132
                DRM_DEBUG( "%ld %d %p\n",
 
133
                           map->size, DRM(order)( map->size ), map->handle );
 
134
                if ( !map->handle ) {
 
135
                        DRM(free)( map, sizeof(*map), DRM_MEM_MAPS );
 
136
                        return -ENOMEM;
 
137
                }
 
138
                map->offset = (unsigned long)map->handle;
 
139
                if ( map->flags & _DRM_CONTAINS_LOCK ) {
 
140
                        dev->sigdata.lock =
 
141
                        dev->lock.hw_lock = map->handle; /* Pointer to lock */
 
142
                }
 
143
                break;
 
144
#if __REALLY_HAVE_AGP
 
145
        case _DRM_AGP:
 
146
#ifdef __alpha__
 
147
                map->offset += dev->hose->mem_space->start;
 
148
#endif
 
149
                map->offset = map->offset + dev->agp->base;
 
150
                map->mtrr   = dev->agp->agp_mtrr; /* for getmap */
 
151
                break;
 
152
#endif
 
153
        case _DRM_SCATTER_GATHER:
 
154
                if (!dev->sg) {
 
155
                        DRM(free)(map, sizeof(*map), DRM_MEM_MAPS);
 
156
                        return -EINVAL;
 
157
                }
 
158
                map->offset = map->offset + dev->sg->handle;
 
159
                break;
 
160
 
 
161
        default:
 
162
                DRM(free)( map, sizeof(*map), DRM_MEM_MAPS );
 
163
                return -EINVAL;
 
164
        }
 
165
 
 
166
        list = DRM(alloc)(sizeof(*list), DRM_MEM_MAPS);
 
167
        if(!list) {
 
168
                DRM(free)(map, sizeof(*map), DRM_MEM_MAPS);
 
169
                return -EINVAL;
 
170
        }
 
171
        memset(list, 0, sizeof(*list));
 
172
        list->map = map;
 
173
 
 
174
        down(&dev->struct_sem);
 
175
        list_add(&list->head, &dev->maplist->head);
 
176
        up(&dev->struct_sem);
 
177
 
 
178
        if ( copy_to_user( (drm_map_t *)arg, map, sizeof(*map) ) )
 
179
                return -EFAULT;
 
180
        if ( map->type != _DRM_SHM ) {
 
181
                if ( copy_to_user( &((drm_map_t *)arg)->handle,
 
182
                                   &map->offset,
 
183
                                   sizeof(map->offset) ) )
 
184
                        return -EFAULT;
 
185
        }
 
186
        return 0;
 
187
}
 
188
 
 
189
 
 
190
/* Remove a map private from list and deallocate resources if the mapping
 
191
 * isn't in use.
 
192
 */
 
193
 
 
194
int DRM(rmmap)(struct inode *inode, struct file *filp,
 
195
               unsigned int cmd, unsigned long arg)
 
196
{
 
197
        drm_file_t      *priv   = filp->private_data;
 
198
        drm_device_t    *dev    = priv->dev;
 
199
        struct list_head *list;
 
200
        drm_map_list_t *r_list = NULL;
 
201
        drm_vma_entry_t *pt, *prev;
 
202
        drm_map_t *map;
 
203
        drm_map_t request;
 
204
        int found_maps = 0;
 
205
 
 
206
        if (copy_from_user(&request, (drm_map_t *)arg,
 
207
                           sizeof(request))) {
 
208
                return -EFAULT;
 
209
        }
 
210
 
 
211
        down(&dev->struct_sem);
 
212
        list = &dev->maplist->head;
 
213
        list_for_each(list, &dev->maplist->head) {
 
214
                r_list = (drm_map_list_t *) list;
 
215
 
 
216
                if(r_list->map &&
 
217
                   r_list->map->handle == request.handle &&
 
218
                   r_list->map->flags & _DRM_REMOVABLE) break;
 
219
        }
 
220
 
 
221
        /* List has wrapped around to the head pointer, or its empty we didn't
 
222
         * find anything.
 
223
         */
 
224
        if(list == (&dev->maplist->head)) {
 
225
                up(&dev->struct_sem);
 
226
                return -EINVAL;
 
227
        }
 
228
        map = r_list->map;
 
229
        list_del(list);
 
230
        DRM(free)(list, sizeof(*list), DRM_MEM_MAPS);
 
231
 
 
232
        for (pt = dev->vmalist, prev = NULL; pt; prev = pt, pt = pt->next) {
 
233
                if (pt->vma->vm_private_data == map) found_maps++;
 
234
        }
 
235
 
 
236
        if(!found_maps) {
 
237
                switch (map->type) {
 
238
                case _DRM_REGISTERS:
 
239
                case _DRM_FRAME_BUFFER:
 
240
#if __REALLY_HAVE_MTRR
 
241
                        if (map->mtrr >= 0) {
 
242
                                int retcode;
 
243
                                retcode = mtrr_del(map->mtrr,
 
244
                                                   map->offset,
 
245
                                                   map->size);
 
246
                                DRM_DEBUG("mtrr_del = %d\n", retcode);
 
247
                        }
 
248
#endif
 
249
                        DRM(ioremapfree)(map->handle, map->size);
 
250
                        break;
 
251
                case _DRM_SHM:
 
252
                        vfree(map->handle);
 
253
                        break;
 
254
                case _DRM_AGP:
 
255
                case _DRM_SCATTER_GATHER:
 
256
                        break;
 
257
                }
 
258
                DRM(free)(map, sizeof(*map), DRM_MEM_MAPS);
 
259
        }
 
260
        up(&dev->struct_sem);
 
261
        return 0;
 
262
}
 
263
 
 
264
#if __HAVE_DMA
 
265
 
 
266
 
 
267
static void DRM(cleanup_buf_error)(drm_buf_entry_t *entry)
 
268
{
 
269
        int i;
 
270
 
 
271
        if (entry->seg_count) {
 
272
                for (i = 0; i < entry->seg_count; i++) {
 
273
                        DRM(free_pages)(entry->seglist[i],
 
274
                                        entry->page_order,
 
275
                                        DRM_MEM_DMA);
 
276
                }
 
277
                DRM(free)(entry->seglist,
 
278
                          entry->seg_count *
 
279
                          sizeof(*entry->seglist),
 
280
                          DRM_MEM_SEGS);
 
281
 
 
282
                entry->seg_count = 0;
 
283
        }
 
284
 
 
285
        if(entry->buf_count) {
 
286
                for(i = 0; i < entry->buf_count; i++) {
 
287
                        if(entry->buflist[i].dev_private) {
 
288
                                DRM(free)(entry->buflist[i].dev_private,
 
289
                                          entry->buflist[i].dev_priv_size,
 
290
                                          DRM_MEM_BUFS);
 
291
                        }
 
292
                }
 
293
                DRM(free)(entry->buflist,
 
294
                          entry->buf_count *
 
295
                          sizeof(*entry->buflist),
 
296
                          DRM_MEM_BUFS);
 
297
 
 
298
#if __HAVE_DMA_FREELIST
 
299
                DRM(freelist_destroy)(&entry->freelist);
 
300
#endif
 
301
 
 
302
                entry->buf_count = 0;
 
303
        }
 
304
}
 
305
 
 
306
#if __REALLY_HAVE_AGP
 
307
int DRM(addbufs_agp)( struct inode *inode, struct file *filp,
 
308
                      unsigned int cmd, unsigned long arg )
 
309
{
 
310
        drm_file_t *priv = filp->private_data;
 
311
        drm_device_t *dev = priv->dev;
 
312
        drm_device_dma_t *dma = dev->dma;
 
313
        drm_buf_desc_t request;
 
314
        drm_buf_entry_t *entry;
 
315
        drm_buf_t *buf;
 
316
        unsigned long offset;
 
317
        unsigned long agp_offset;
 
318
        int count;
 
319
        int order;
 
320
        int size;
 
321
        int alignment;
 
322
        int page_order;
 
323
        int total;
 
324
        int byte_count;
 
325
        int i;
 
326
        drm_buf_t **temp_buflist;
 
327
 
 
328
        if ( !dma ) return -EINVAL;
 
329
 
 
330
        if ( copy_from_user( &request, (drm_buf_desc_t *)arg,
 
331
                             sizeof(request) ) )
 
332
                return -EFAULT;
 
333
 
 
334
        count = request.count;
 
335
        order = DRM(order)( request.size );
 
336
        size = 1 << order;
 
337
 
 
338
        alignment  = (request.flags & _DRM_PAGE_ALIGN)
 
339
                ? PAGE_ALIGN(size) : size;
 
340
        page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
 
341
        total = PAGE_SIZE << page_order;
 
342
 
 
343
        byte_count = 0;
 
344
        agp_offset = dev->agp->base + request.agp_start;
 
345
 
 
346
        DRM_DEBUG( "count:      %d\n",  count );
 
347
        DRM_DEBUG( "order:      %d\n",  order );
 
348
        DRM_DEBUG( "size:       %d\n",  size );
 
349
        DRM_DEBUG( "agp_offset: %ld\n", agp_offset );
 
350
        DRM_DEBUG( "alignment:  %d\n",  alignment );
 
351
        DRM_DEBUG( "page_order: %d\n",  page_order );
 
352
        DRM_DEBUG( "total:      %d\n",  total );
 
353
 
 
354
        if ( order < DRM_MIN_ORDER || order > DRM_MAX_ORDER ) return -EINVAL;
 
355
        if ( dev->queue_count ) return -EBUSY; /* Not while in use */
 
356
 
 
357
        spin_lock( &dev->count_lock );
 
358
        if ( dev->buf_use ) {
 
359
                spin_unlock( &dev->count_lock );
 
360
                return -EBUSY;
 
361
        }
 
362
        atomic_inc( &dev->buf_alloc );
 
363
        spin_unlock( &dev->count_lock );
 
364
 
 
365
        down( &dev->struct_sem );
 
366
        entry = &dma->bufs[order];
 
367
        if ( entry->buf_count ) {
 
368
                up( &dev->struct_sem );
 
369
                atomic_dec( &dev->buf_alloc );
 
370
                return -ENOMEM; /* May only call once for each order */
 
371
        }
 
372
 
 
373
        if (count < 0 || count > 4096) {
 
374
                up( &dev->struct_sem );
 
375
                atomic_dec( &dev->buf_alloc );
 
376
                return -EINVAL;
 
377
        }
 
378
 
 
379
        entry->buflist = DRM(alloc)( count * sizeof(*entry->buflist),
 
380
                                    DRM_MEM_BUFS );
 
381
        if ( !entry->buflist ) {
 
382
                up( &dev->struct_sem );
 
383
                atomic_dec( &dev->buf_alloc );
 
384
                return -ENOMEM;
 
385
        }
 
386
        memset( entry->buflist, 0, count * sizeof(*entry->buflist) );
 
387
 
 
388
        entry->buf_size = size;
 
389
        entry->page_order = page_order;
 
390
 
 
391
        offset = 0;
 
392
 
 
393
        while ( entry->buf_count < count ) {
 
394
                buf          = &entry->buflist[entry->buf_count];
 
395
                buf->idx     = dma->buf_count + entry->buf_count;
 
396
                buf->total   = alignment;
 
397
                buf->order   = order;
 
398
                buf->used    = 0;
 
399
 
 
400
                buf->offset  = (dma->byte_count + offset);
 
401
                buf->bus_address = agp_offset + offset;
 
402
                buf->address = (void *)(agp_offset + offset);
 
403
                buf->next    = NULL;
 
404
                buf->waiting = 0;
 
405
                buf->pending = 0;
 
406
                init_waitqueue_head( &buf->dma_wait );
 
407
                buf->pid     = 0;
 
408
 
 
409
                buf->dev_priv_size = sizeof(DRIVER_BUF_PRIV_T);
 
410
                buf->dev_private = DRM(alloc)( sizeof(DRIVER_BUF_PRIV_T),
 
411
                                               DRM_MEM_BUFS );
 
412
                if(!buf->dev_private) {
 
413
                        /* Set count correctly so we free the proper amount. */
 
414
                        entry->buf_count = count;
 
415
                        DRM(cleanup_buf_error)(entry);
 
416
                }
 
417
                memset( buf->dev_private, 0, buf->dev_priv_size );
 
418
 
 
419
#if __HAVE_DMA_HISTOGRAM
 
420
                buf->time_queued = 0;
 
421
                buf->time_dispatched = 0;
 
422
                buf->time_completed = 0;
 
423
                buf->time_freed = 0;
 
424
#endif
 
425
                DRM_DEBUG( "buffer %d @ %p\n",
 
426
                           entry->buf_count, buf->address );
 
427
 
 
428
                offset += alignment;
 
429
                entry->buf_count++;
 
430
                byte_count += PAGE_SIZE << page_order;
 
431
        }
 
432
 
 
433
        DRM_DEBUG( "byte_count: %d\n", byte_count );
 
434
 
 
435
        temp_buflist = DRM(realloc)( dma->buflist,
 
436
                                     dma->buf_count * sizeof(*dma->buflist),
 
437
                                     (dma->buf_count + entry->buf_count)
 
438
                                     * sizeof(*dma->buflist),
 
439
                                     DRM_MEM_BUFS );
 
440
        if(!temp_buflist) {
 
441
                /* Free the entry because it isn't valid */
 
442
                DRM(cleanup_buf_error)(entry);
 
443
                up( &dev->struct_sem );
 
444
                atomic_dec( &dev->buf_alloc );
 
445
                return -ENOMEM;
 
446
        }
 
447
        dma->buflist = temp_buflist;
 
448
 
 
449
        for ( i = 0 ; i < entry->buf_count ; i++ ) {
 
450
                dma->buflist[i + dma->buf_count] = &entry->buflist[i];
 
451
        }
 
452
 
 
453
        dma->buf_count += entry->buf_count;
 
454
        dma->byte_count += byte_count;
 
455
 
 
456
        DRM_DEBUG( "dma->buf_count : %d\n", dma->buf_count );
 
457
        DRM_DEBUG( "entry->buf_count : %d\n", entry->buf_count );
 
458
 
 
459
#if __HAVE_DMA_FREELIST
 
460
        DRM(freelist_create)( &entry->freelist, entry->buf_count );
 
461
        for ( i = 0 ; i < entry->buf_count ; i++ ) {
 
462
                DRM(freelist_put)( dev, &entry->freelist, &entry->buflist[i] );
 
463
        }
 
464
#endif
 
465
        up( &dev->struct_sem );
 
466
 
 
467
        request.count = entry->buf_count;
 
468
        request.size = size;
 
469
 
 
470
        if ( copy_to_user( (drm_buf_desc_t *)arg, &request, sizeof(request) ) )
 
471
                return -EFAULT;
 
472
 
 
473
        dma->flags = _DRM_DMA_USE_AGP;
 
474
 
 
475
        atomic_dec( &dev->buf_alloc );
 
476
        return 0;
 
477
}
 
478
#endif /* __REALLY_HAVE_AGP */
 
479
 
 
480
#if __HAVE_PCI_DMA
 
481
int DRM(addbufs_pci)( struct inode *inode, struct file *filp,
 
482
                      unsigned int cmd, unsigned long arg )
 
483
{
 
484
        drm_file_t *priv = filp->private_data;
 
485
        drm_device_t *dev = priv->dev;
 
486
        drm_device_dma_t *dma = dev->dma;
 
487
        drm_buf_desc_t request;
 
488
        int count;
 
489
        int order;
 
490
        int size;
 
491
        int total;
 
492
        int page_order;
 
493
        drm_buf_entry_t *entry;
 
494
        unsigned long page;
 
495
        drm_buf_t *buf;
 
496
        int alignment;
 
497
        unsigned long offset;
 
498
        int i;
 
499
        int byte_count;
 
500
        int page_count;
 
501
        unsigned long *temp_pagelist;
 
502
        drm_buf_t **temp_buflist;
 
503
 
 
504
        if ( !dma ) return -EINVAL;
 
505
 
 
506
        if ( copy_from_user( &request, (drm_buf_desc_t *)arg,
 
507
                             sizeof(request) ) )
 
508
                return -EFAULT;
 
509
 
 
510
        count = request.count;
 
511
        order = DRM(order)( request.size );
 
512
        size = 1 << order;
 
513
 
 
514
        DRM_DEBUG( "count=%d, size=%d (%d), order=%d, queue_count=%d\n",
 
515
                   request.count, request.size, size,
 
516
                   order, dev->queue_count );
 
517
 
 
518
        if ( order < DRM_MIN_ORDER || order > DRM_MAX_ORDER ) return -EINVAL;
 
519
        if ( dev->queue_count ) return -EBUSY; /* Not while in use */
 
520
 
 
521
        alignment = (request.flags & _DRM_PAGE_ALIGN)
 
522
                ? PAGE_ALIGN(size) : size;
 
523
        page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
 
524
        total = PAGE_SIZE << page_order;
 
525
 
 
526
        spin_lock( &dev->count_lock );
 
527
        if ( dev->buf_use ) {
 
528
                spin_unlock( &dev->count_lock );
 
529
                return -EBUSY;
 
530
        }
 
531
        atomic_inc( &dev->buf_alloc );
 
532
        spin_unlock( &dev->count_lock );
 
533
 
 
534
        down( &dev->struct_sem );
 
535
        entry = &dma->bufs[order];
 
536
        if ( entry->buf_count ) {
 
537
                up( &dev->struct_sem );
 
538
                atomic_dec( &dev->buf_alloc );
 
539
                return -ENOMEM; /* May only call once for each order */
 
540
        }
 
541
 
 
542
        if (count < 0 || count > 4096) {
 
543
                up( &dev->struct_sem );
 
544
                atomic_dec( &dev->buf_alloc );
 
545
                return -EINVAL;
 
546
        }
 
547
 
 
548
        entry->buflist = DRM(alloc)( count * sizeof(*entry->buflist),
 
549
                                    DRM_MEM_BUFS );
 
550
        if ( !entry->buflist ) {
 
551
                up( &dev->struct_sem );
 
552
                atomic_dec( &dev->buf_alloc );
 
553
                return -ENOMEM;
 
554
        }
 
555
        memset( entry->buflist, 0, count * sizeof(*entry->buflist) );
 
556
 
 
557
        entry->seglist = DRM(alloc)( count * sizeof(*entry->seglist),
 
558
                                    DRM_MEM_SEGS );
 
559
        if ( !entry->seglist ) {
 
560
                DRM(free)( entry->buflist,
 
561
                          count * sizeof(*entry->buflist),
 
562
                          DRM_MEM_BUFS );
 
563
                up( &dev->struct_sem );
 
564
                atomic_dec( &dev->buf_alloc );
 
565
                return -ENOMEM;
 
566
        }
 
567
        memset( entry->seglist, 0, count * sizeof(*entry->seglist) );
 
568
 
 
569
        temp_pagelist = DRM(realloc)( dma->pagelist,
 
570
                                      dma->page_count * sizeof(*dma->pagelist),
 
571
                                      (dma->page_count + (count << page_order))
 
572
                                      * sizeof(*dma->pagelist),
 
573
                                      DRM_MEM_PAGES );
 
574
        if(!temp_pagelist) {
 
575
                DRM(free)( entry->buflist,
 
576
                           count * sizeof(*entry->buflist),
 
577
                           DRM_MEM_BUFS );
 
578
                DRM(free)( entry->seglist,
 
579
                           count * sizeof(*entry->seglist),
 
580
                           DRM_MEM_SEGS );
 
581
                up( &dev->struct_sem );
 
582
                atomic_dec( &dev->buf_alloc );
 
583
                return -ENOMEM;
 
584
        }
 
585
 
 
586
        dma->pagelist = temp_pagelist;
 
587
        DRM_DEBUG( "pagelist: %d entries\n",
 
588
                   dma->page_count + (count << page_order) );
 
589
 
 
590
        entry->buf_size = size;
 
591
        entry->page_order = page_order;
 
592
        byte_count = 0;
 
593
        page_count = 0;
 
594
 
 
595
        while ( entry->buf_count < count ) {
 
596
                page = DRM(alloc_pages)( page_order, DRM_MEM_DMA );
 
597
                if ( !page ) break;
 
598
                entry->seglist[entry->seg_count++] = page;
 
599
                for ( i = 0 ; i < (1 << page_order) ; i++ ) {
 
600
                        DRM_DEBUG( "page %d @ 0x%08lx\n",
 
601
                                   dma->page_count + page_count,
 
602
                                   page + PAGE_SIZE * i );
 
603
                        dma->pagelist[dma->page_count + page_count++]
 
604
                                = page + PAGE_SIZE * i;
 
605
                }
 
606
                for ( offset = 0 ;
 
607
                      offset + size <= total && entry->buf_count < count ;
 
608
                      offset += alignment, ++entry->buf_count ) {
 
609
                        buf          = &entry->buflist[entry->buf_count];
 
610
                        buf->idx     = dma->buf_count + entry->buf_count;
 
611
                        buf->total   = alignment;
 
612
                        buf->order   = order;
 
613
                        buf->used    = 0;
 
614
                        buf->offset  = (dma->byte_count + byte_count + offset);
 
615
                        buf->address = (void *)(page + offset);
 
616
                        buf->next    = NULL;
 
617
                        buf->waiting = 0;
 
618
                        buf->pending = 0;
 
619
                        init_waitqueue_head( &buf->dma_wait );
 
620
                        buf->pid     = 0;
 
621
#if __HAVE_DMA_HISTOGRAM
 
622
                        buf->time_queued     = 0;
 
623
                        buf->time_dispatched = 0;
 
624
                        buf->time_completed  = 0;
 
625
                        buf->time_freed      = 0;
 
626
#endif
 
627
                        DRM_DEBUG( "buffer %d @ %p\n",
 
628
                                   entry->buf_count, buf->address );
 
629
                }
 
630
                byte_count += PAGE_SIZE << page_order;
 
631
        }
 
632
 
 
633
        temp_buflist = DRM(realloc)( dma->buflist,
 
634
                                     dma->buf_count * sizeof(*dma->buflist),
 
635
                                     (dma->buf_count + entry->buf_count)
 
636
                                     * sizeof(*dma->buflist),
 
637
                                     DRM_MEM_BUFS );
 
638
        if(!temp_buflist) {
 
639
                /* Free the entry because it isn't valid */
 
640
                DRM(cleanup_buf_error)(entry);
 
641
                up( &dev->struct_sem );
 
642
                atomic_dec( &dev->buf_alloc );
 
643
                return -ENOMEM;
 
644
        }
 
645
        dma->buflist = temp_buflist;
 
646
 
 
647
        for ( i = 0 ; i < entry->buf_count ; i++ ) {
 
648
                dma->buflist[i + dma->buf_count] = &entry->buflist[i];
 
649
        }
 
650
 
 
651
        dma->buf_count += entry->buf_count;
 
652
        dma->seg_count += entry->seg_count;
 
653
        dma->page_count += entry->seg_count << page_order;
 
654
        dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order);
 
655
 
 
656
#if __HAVE_DMA_FREELIST
 
657
        DRM(freelist_create)( &entry->freelist, entry->buf_count );
 
658
        for ( i = 0 ; i < entry->buf_count ; i++ ) {
 
659
                DRM(freelist_put)( dev, &entry->freelist, &entry->buflist[i] );
 
660
        }
 
661
#endif
 
662
        up( &dev->struct_sem );
 
663
 
 
664
        request.count = entry->buf_count;
 
665
        request.size = size;
 
666
 
 
667
        if ( copy_to_user( (drm_buf_desc_t *)arg, &request, sizeof(request) ) )
 
668
                return -EFAULT;
 
669
 
 
670
        atomic_dec( &dev->buf_alloc );
 
671
        return 0;
 
672
 
 
673
}
 
674
#endif /* __HAVE_PCI_DMA */
 
675
 
 
676
#ifdef __HAVE_SG
 
677
int DRM(addbufs_sg)( struct inode *inode, struct file *filp,
 
678
                     unsigned int cmd, unsigned long arg )
 
679
{
 
680
        drm_file_t *priv = filp->private_data;
 
681
        drm_device_t *dev = priv->dev;
 
682
        drm_device_dma_t *dma = dev->dma;
 
683
        drm_buf_desc_t request;
 
684
        drm_buf_entry_t *entry;
 
685
        drm_buf_t *buf;
 
686
        unsigned long offset;
 
687
        unsigned long agp_offset;
 
688
        int count;
 
689
        int order;
 
690
        int size;
 
691
        int alignment;
 
692
        int page_order;
 
693
        int total;
 
694
        int byte_count;
 
695
        int i;
 
696
        drm_buf_t **temp_buflist;
 
697
 
 
698
        if ( !dma ) return -EINVAL;
 
699
 
 
700
        if ( copy_from_user( &request, (drm_buf_desc_t *)arg,
 
701
                             sizeof(request) ) )
 
702
                return -EFAULT;
 
703
 
 
704
        count = request.count;
 
705
        order = DRM(order)( request.size );
 
706
        size = 1 << order;
 
707
 
 
708
        alignment  = (request.flags & _DRM_PAGE_ALIGN)
 
709
                        ? PAGE_ALIGN(size) : size;
 
710
        page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
 
711
        total = PAGE_SIZE << page_order;
 
712
 
 
713
        byte_count = 0;
 
714
        agp_offset = request.agp_start;
 
715
 
 
716
        DRM_DEBUG( "count:      %d\n",  count );
 
717
        DRM_DEBUG( "order:      %d\n",  order );
 
718
        DRM_DEBUG( "size:       %d\n",  size );
 
719
        DRM_DEBUG( "agp_offset: %ld\n", agp_offset );
 
720
        DRM_DEBUG( "alignment:  %d\n",  alignment );
 
721
        DRM_DEBUG( "page_order: %d\n",  page_order );
 
722
        DRM_DEBUG( "total:      %d\n",  total );
 
723
 
 
724
        if ( order < DRM_MIN_ORDER || order > DRM_MAX_ORDER ) return -EINVAL;
 
725
        if ( dev->queue_count ) return -EBUSY; /* Not while in use */
 
726
 
 
727
        spin_lock( &dev->count_lock );
 
728
        if ( dev->buf_use ) {
 
729
                spin_unlock( &dev->count_lock );
 
730
                return -EBUSY;
 
731
        }
 
732
        atomic_inc( &dev->buf_alloc );
 
733
        spin_unlock( &dev->count_lock );
 
734
 
 
735
        down( &dev->struct_sem );
 
736
        entry = &dma->bufs[order];
 
737
        if ( entry->buf_count ) {
 
738
                up( &dev->struct_sem );
 
739
                atomic_dec( &dev->buf_alloc );
 
740
                return -ENOMEM; /* May only call once for each order */
 
741
        }
 
742
 
 
743
        if (count < 0 || count > 4096) {
 
744
                up( &dev->struct_sem );
 
745
                atomic_dec( &dev->buf_alloc );
 
746
                return -EINVAL;
 
747
        }
 
748
 
 
749
        entry->buflist = DRM(alloc)( count * sizeof(*entry->buflist),
 
750
                                     DRM_MEM_BUFS );
 
751
        if ( !entry->buflist ) {
 
752
                up( &dev->struct_sem );
 
753
                atomic_dec( &dev->buf_alloc );
 
754
                return -ENOMEM;
 
755
        }
 
756
        memset( entry->buflist, 0, count * sizeof(*entry->buflist) );
 
757
 
 
758
        entry->buf_size = size;
 
759
        entry->page_order = page_order;
 
760
 
 
761
        offset = 0;
 
762
 
 
763
        while ( entry->buf_count < count ) {
 
764
                buf          = &entry->buflist[entry->buf_count];
 
765
                buf->idx     = dma->buf_count + entry->buf_count;
 
766
                buf->total   = alignment;
 
767
                buf->order   = order;
 
768
                buf->used    = 0;
 
769
 
 
770
                buf->offset  = (dma->byte_count + offset);
 
771
                buf->bus_address = agp_offset + offset;
 
772
                buf->address = (void *)(agp_offset + offset + dev->sg->handle);
 
773
                buf->next    = NULL;
 
774
                buf->waiting = 0;
 
775
                buf->pending = 0;
 
776
                init_waitqueue_head( &buf->dma_wait );
 
777
                buf->pid     = 0;
 
778
 
 
779
                buf->dev_priv_size = sizeof(DRIVER_BUF_PRIV_T);
 
780
                buf->dev_private = DRM(alloc)( sizeof(DRIVER_BUF_PRIV_T),
 
781
                                               DRM_MEM_BUFS );
 
782
                if(!buf->dev_private) {
 
783
                        /* Set count correctly so we free the proper amount. */
 
784
                        entry->buf_count = count;
 
785
                        DRM(cleanup_buf_error)(entry);
 
786
                        up( &dev->struct_sem );
 
787
                        atomic_dec( &dev->buf_alloc );
 
788
                        return -ENOMEM;
 
789
                }
 
790
 
 
791
                memset( buf->dev_private, 0, buf->dev_priv_size );
 
792
 
 
793
# if __HAVE_DMA_HISTOGRAM
 
794
                buf->time_queued = 0;
 
795
                buf->time_dispatched = 0;
 
796
                buf->time_completed = 0;
 
797
                buf->time_freed = 0;
 
798
# endif
 
799
                DRM_DEBUG( "buffer %d @ %p\n",
 
800
                           entry->buf_count, buf->address );
 
801
 
 
802
                offset += alignment;
 
803
                entry->buf_count++;
 
804
                byte_count += PAGE_SIZE << page_order;
 
805
        }
 
806
 
 
807
        DRM_DEBUG( "byte_count: %d\n", byte_count );
 
808
 
 
809
        temp_buflist = DRM(realloc)( dma->buflist,
 
810
                                     dma->buf_count * sizeof(*dma->buflist),
 
811
                                     (dma->buf_count + entry->buf_count)
 
812
                                     * sizeof(*dma->buflist),
 
813
                                     DRM_MEM_BUFS );
 
814
        if(!temp_buflist) {
 
815
                /* Free the entry because it isn't valid */
 
816
                DRM(cleanup_buf_error)(entry);
 
817
                up( &dev->struct_sem );
 
818
                atomic_dec( &dev->buf_alloc );
 
819
                return -ENOMEM;
 
820
        }
 
821
        dma->buflist = temp_buflist;
 
822
 
 
823
        for ( i = 0 ; i < entry->buf_count ; i++ ) {
 
824
                dma->buflist[i + dma->buf_count] = &entry->buflist[i];
 
825
        }
 
826
 
 
827
        dma->buf_count += entry->buf_count;
 
828
        dma->byte_count += byte_count;
 
829
 
 
830
        DRM_DEBUG( "dma->buf_count : %d\n", dma->buf_count );
 
831
        DRM_DEBUG( "entry->buf_count : %d\n", entry->buf_count );
 
832
 
 
833
#if __HAVE_DMA_FREELIST
 
834
        DRM(freelist_create)( &entry->freelist, entry->buf_count );
 
835
        for ( i = 0 ; i < entry->buf_count ; i++ ) {
 
836
                DRM(freelist_put)( dev, &entry->freelist, &entry->buflist[i] );
 
837
        }
 
838
#endif
 
839
        up( &dev->struct_sem );
 
840
 
 
841
        request.count = entry->buf_count;
 
842
        request.size = size;
 
843
 
 
844
        if ( copy_to_user( (drm_buf_desc_t *)arg, &request, sizeof(request) ) )
 
845
                return -EFAULT;
 
846
 
 
847
        dma->flags = _DRM_DMA_USE_SG;
 
848
 
 
849
        atomic_dec( &dev->buf_alloc );
 
850
        return 0;
 
851
}
 
852
#endif /* __HAVE_SG */
 
853
 
 
854
int DRM(addbufs)( struct inode *inode, struct file *filp,
 
855
                  unsigned int cmd, unsigned long arg )
 
856
{
 
857
        drm_buf_desc_t request;
 
858
 
 
859
        if ( copy_from_user( &request, (drm_buf_desc_t *)arg,
 
860
                             sizeof(request) ) )
 
861
                return -EFAULT;
 
862
 
 
863
#if __REALLY_HAVE_AGP
 
864
        if ( request.flags & _DRM_AGP_BUFFER )
 
865
                return DRM(addbufs_agp)( inode, filp, cmd, arg );
 
866
        else
 
867
#endif
 
868
#if __HAVE_SG
 
869
        if ( request.flags & _DRM_SG_BUFFER )
 
870
                return DRM(addbufs_sg)( inode, filp, cmd, arg );
 
871
        else
 
872
#endif
 
873
#if __HAVE_PCI_DMA
 
874
                return DRM(addbufs_pci)( inode, filp, cmd, arg );
 
875
#else
 
876
                return -EINVAL;
 
877
#endif
 
878
}
 
879
 
 
880
int DRM(infobufs)( struct inode *inode, struct file *filp,
 
881
                   unsigned int cmd, unsigned long arg )
 
882
{
 
883
        drm_file_t *priv = filp->private_data;
 
884
        drm_device_t *dev = priv->dev;
 
885
        drm_device_dma_t *dma = dev->dma;
 
886
        drm_buf_info_t request;
 
887
        int i;
 
888
        int count;
 
889
 
 
890
        if ( !dma ) return -EINVAL;
 
891
 
 
892
        spin_lock( &dev->count_lock );
 
893
        if ( atomic_read( &dev->buf_alloc ) ) {
 
894
                spin_unlock( &dev->count_lock );
 
895
                return -EBUSY;
 
896
        }
 
897
        ++dev->buf_use;         /* Can't allocate more after this call */
 
898
        spin_unlock( &dev->count_lock );
 
899
 
 
900
        if ( copy_from_user( &request,
 
901
                             (drm_buf_info_t *)arg,
 
902
                             sizeof(request) ) )
 
903
                return -EFAULT;
 
904
 
 
905
        for ( i = 0, count = 0 ; i < DRM_MAX_ORDER + 1 ; i++ ) {
 
906
                if ( dma->bufs[i].buf_count ) ++count;
 
907
        }
 
908
 
 
909
        DRM_DEBUG( "count = %d\n", count );
 
910
 
 
911
        if ( request.count >= count ) {
 
912
                for ( i = 0, count = 0 ; i < DRM_MAX_ORDER + 1 ; i++ ) {
 
913
                        if ( dma->bufs[i].buf_count ) {
 
914
                                drm_buf_desc_t *to = &request.list[count];
 
915
                                drm_buf_entry_t *from = &dma->bufs[i];
 
916
                                drm_freelist_t *list = &dma->bufs[i].freelist;
 
917
                                if ( copy_to_user( &to->count,
 
918
                                                   &from->buf_count,
 
919
                                                   sizeof(from->buf_count) ) ||
 
920
                                     copy_to_user( &to->size,
 
921
                                                   &from->buf_size,
 
922
                                                   sizeof(from->buf_size) ) ||
 
923
                                     copy_to_user( &to->low_mark,
 
924
                                                   &list->low_mark,
 
925
                                                   sizeof(list->low_mark) ) ||
 
926
                                     copy_to_user( &to->high_mark,
 
927
                                                   &list->high_mark,
 
928
                                                   sizeof(list->high_mark) ) )
 
929
                                        return -EFAULT;
 
930
 
 
931
                                DRM_DEBUG( "%d %d %d %d %d\n",
 
932
                                           i,
 
933
                                           dma->bufs[i].buf_count,
 
934
                                           dma->bufs[i].buf_size,
 
935
                                           dma->bufs[i].freelist.low_mark,
 
936
                                           dma->bufs[i].freelist.high_mark );
 
937
                                ++count;
 
938
                        }
 
939
                }
 
940
        }
 
941
        request.count = count;
 
942
 
 
943
        if ( copy_to_user( (drm_buf_info_t *)arg,
 
944
                           &request,
 
945
                           sizeof(request) ) )
 
946
                return -EFAULT;
 
947
 
 
948
        return 0;
 
949
}
 
950
 
 
951
int DRM(markbufs)( struct inode *inode, struct file *filp,
 
952
                   unsigned int cmd, unsigned long arg )
 
953
{
 
954
        drm_file_t *priv = filp->private_data;
 
955
        drm_device_t *dev = priv->dev;
 
956
        drm_device_dma_t *dma = dev->dma;
 
957
        drm_buf_desc_t request;
 
958
        int order;
 
959
        drm_buf_entry_t *entry;
 
960
 
 
961
        if ( !dma ) return -EINVAL;
 
962
 
 
963
        if ( copy_from_user( &request,
 
964
                             (drm_buf_desc_t *)arg,
 
965
                             sizeof(request) ) )
 
966
                return -EFAULT;
 
967
 
 
968
        DRM_DEBUG( "%d, %d, %d\n",
 
969
                   request.size, request.low_mark, request.high_mark );
 
970
        order = DRM(order)( request.size );
 
971
        if ( order < DRM_MIN_ORDER || order > DRM_MAX_ORDER ) return -EINVAL;
 
972
        entry = &dma->bufs[order];
 
973
 
 
974
        if ( request.low_mark < 0 || request.low_mark > entry->buf_count )
 
975
                return -EINVAL;
 
976
        if ( request.high_mark < 0 || request.high_mark > entry->buf_count )
 
977
                return -EINVAL;
 
978
 
 
979
        entry->freelist.low_mark  = request.low_mark;
 
980
        entry->freelist.high_mark = request.high_mark;
 
981
 
 
982
        return 0;
 
983
}
 
984
 
 
985
int DRM(freebufs)( struct inode *inode, struct file *filp,
 
986
                   unsigned int cmd, unsigned long arg )
 
987
{
 
988
        drm_file_t *priv = filp->private_data;
 
989
        drm_device_t *dev = priv->dev;
 
990
        drm_device_dma_t *dma = dev->dma;
 
991
        drm_buf_free_t request;
 
992
        int i;
 
993
        int idx;
 
994
        drm_buf_t *buf;
 
995
 
 
996
        if ( !dma ) return -EINVAL;
 
997
 
 
998
        if ( copy_from_user( &request,
 
999
                             (drm_buf_free_t *)arg,
 
1000
                             sizeof(request) ) )
 
1001
                return -EFAULT;
 
1002
 
 
1003
        DRM_DEBUG( "%d\n", request.count );
 
1004
        for ( i = 0 ; i < request.count ; i++ ) {
 
1005
                if ( copy_from_user( &idx,
 
1006
                                     &request.list[i],
 
1007
                                     sizeof(idx) ) )
 
1008
                        return -EFAULT;
 
1009
                if ( idx < 0 || idx >= dma->buf_count ) {
 
1010
                        DRM_ERROR( "Index %d (of %d max)\n",
 
1011
                                   idx, dma->buf_count - 1 );
 
1012
                        return -EINVAL;
 
1013
                }
 
1014
                buf = dma->buflist[idx];
 
1015
                if ( buf->pid != current->pid ) {
 
1016
                        DRM_ERROR( "Process %d freeing buffer owned by %d\n",
 
1017
                                   current->pid, buf->pid );
 
1018
                        return -EINVAL;
 
1019
                }
 
1020
                DRM(free_buffer)( dev, buf );
 
1021
        }
 
1022
 
 
1023
        return 0;
 
1024
}
 
1025
 
 
1026
int DRM(mapbufs)( struct inode *inode, struct file *filp,
 
1027
                  unsigned int cmd, unsigned long arg )
 
1028
{
 
1029
        drm_file_t *priv = filp->private_data;
 
1030
        drm_device_t *dev = priv->dev;
 
1031
        drm_device_dma_t *dma = dev->dma;
 
1032
        int retcode = 0;
 
1033
        const int zero = 0;
 
1034
        unsigned long virtual;
 
1035
        unsigned long address;
 
1036
        drm_buf_map_t request;
 
1037
        int i;
 
1038
 
 
1039
        if ( !dma ) return -EINVAL;
 
1040
 
 
1041
        spin_lock( &dev->count_lock );
 
1042
        if ( atomic_read( &dev->buf_alloc ) ) {
 
1043
                spin_unlock( &dev->count_lock );
 
1044
                return -EBUSY;
 
1045
        }
 
1046
        dev->buf_use++;         /* Can't allocate more after this call */
 
1047
        spin_unlock( &dev->count_lock );
 
1048
 
 
1049
        if ( copy_from_user( &request, (drm_buf_map_t *)arg,
 
1050
                             sizeof(request) ) )
 
1051
                return -EFAULT;
 
1052
 
 
1053
        if ( request.count >= dma->buf_count ) {
 
1054
                if ( (__HAVE_AGP && (dma->flags & _DRM_DMA_USE_AGP)) ||
 
1055
                     (__HAVE_SG && (dma->flags & _DRM_DMA_USE_SG)) ) {
 
1056
                        drm_map_t *map = DRIVER_AGP_BUFFERS_MAP( dev );
 
1057
 
 
1058
                        if ( !map ) {
 
1059
                                retcode = -EINVAL;
 
1060
                                goto done;
 
1061
                        }
 
1062
 
 
1063
#if LINUX_VERSION_CODE <= 0x020402
 
1064
                        down( &current->mm->mmap_sem );
 
1065
#else
 
1066
                        down_write( &current->mm->mmap_sem );
 
1067
#endif
 
1068
                        virtual = do_mmap( filp, 0, map->size,
 
1069
                                           PROT_READ | PROT_WRITE,
 
1070
                                           MAP_SHARED,
 
1071
                                           (unsigned long)map->offset );
 
1072
#if LINUX_VERSION_CODE <= 0x020402
 
1073
                        up( &current->mm->mmap_sem );
 
1074
#else
 
1075
                        up_write( &current->mm->mmap_sem );
 
1076
#endif
 
1077
                } else {
 
1078
#if LINUX_VERSION_CODE <= 0x020402
 
1079
                        down( &current->mm->mmap_sem );
 
1080
#else
 
1081
                        down_write( &current->mm->mmap_sem );
 
1082
#endif
 
1083
                        virtual = do_mmap( filp, 0, dma->byte_count,
 
1084
                                           PROT_READ | PROT_WRITE,
 
1085
                                           MAP_SHARED, 0 );
 
1086
#if LINUX_VERSION_CODE <= 0x020402
 
1087
                        up( &current->mm->mmap_sem );
 
1088
#else
 
1089
                        up_write( &current->mm->mmap_sem );
 
1090
#endif
 
1091
                }
 
1092
                if ( virtual > -1024UL ) {
 
1093
                        /* Real error */
 
1094
                        retcode = (signed long)virtual;
 
1095
                        goto done;
 
1096
                }
 
1097
                request.virtual = (void *)virtual;
 
1098
 
 
1099
                for ( i = 0 ; i < dma->buf_count ; i++ ) {
 
1100
                        if ( copy_to_user( &request.list[i].idx,
 
1101
                                           &dma->buflist[i]->idx,
 
1102
                                           sizeof(request.list[0].idx) ) ) {
 
1103
                                retcode = -EFAULT;
 
1104
                                goto done;
 
1105
                        }
 
1106
                        if ( copy_to_user( &request.list[i].total,
 
1107
                                           &dma->buflist[i]->total,
 
1108
                                           sizeof(request.list[0].total) ) ) {
 
1109
                                retcode = -EFAULT;
 
1110
                                goto done;
 
1111
                        }
 
1112
                        if ( copy_to_user( &request.list[i].used,
 
1113
                                           &zero,
 
1114
                                           sizeof(zero) ) ) {
 
1115
                                retcode = -EFAULT;
 
1116
                                goto done;
 
1117
                        }
 
1118
                        address = virtual + dma->buflist[i]->offset; /* *** */
 
1119
                        if ( copy_to_user( &request.list[i].address,
 
1120
                                           &address,
 
1121
                                           sizeof(address) ) ) {
 
1122
                                retcode = -EFAULT;
 
1123
                                goto done;
 
1124
                        }
 
1125
                }
 
1126
        }
 
1127
 done:
 
1128
        request.count = dma->buf_count;
 
1129
        DRM_DEBUG( "%d buffers, retcode = %d\n", request.count, retcode );
 
1130
 
 
1131
        if ( copy_to_user( (drm_buf_map_t *)arg, &request, sizeof(request) ) )
 
1132
                return -EFAULT;
 
1133
 
 
1134
        return retcode;
 
1135
}
 
1136
 
 
1137
#endif /* __HAVE_DMA */