int drm_addbufs_pci( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg )
static int drm_addbufs_pci( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg )
int drm_addbufs_pci( struct inode *inode, struct file *filp,		      unsigned int cmd, unsigned long arg ){   	drm_file_t *priv = filp->private_data;	drm_device_t *dev = priv->head->dev;	drm_device_dma_t *dma = dev->dma;	drm_buf_desc_t request;	int count;	int order;	int size;	int total;	int page_order;	drm_buf_entry_t *entry;	unsigned long page;	drm_buf_t *buf;	int alignment;	unsigned long offset;	int i;	int byte_count;	int page_count;	unsigned long *temp_pagelist;	drm_buf_t **temp_buflist;	drm_buf_desc_t __user *argp = (void __user *)arg;	if (!drm_core_check_feature(dev, DRIVER_PCI_DMA)) return -EINVAL;	if ( !dma ) return -EINVAL;	if ( copy_from_user( &request, argp, sizeof(request) ) )		return -EFAULT;	count = request.count;	order = drm_order( request.size );	size = 1 << order;	DRM_DEBUG( "count=%d, size=%d (%d), order=%d, queue_count=%d\n",		   request.count, request.size, size,		   order, dev->queue_count );	if ( order < DRM_MIN_ORDER || order > DRM_MAX_ORDER ) return -EINVAL;	if ( dev->queue_count ) return -EBUSY; /* Not while in use */	alignment = (request.flags & _DRM_PAGE_ALIGN)		? PAGE_ALIGN(size) : size;	page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;	total = PAGE_SIZE << page_order;	spin_lock( &dev->count_lock );	if ( dev->buf_use ) {		spin_unlock( &dev->count_lock );		return -EBUSY;	}	atomic_inc( &dev->buf_alloc );	spin_unlock( &dev->count_lock );	down( &dev->struct_sem );	entry = &dma->bufs[order];	if ( entry->buf_count ) {		up( &dev->struct_sem );		atomic_dec( &dev->buf_alloc );		return -ENOMEM;	/* May only call once for each order */	}	if (count < 0 || count > 4096) {		up( &dev->struct_sem );		atomic_dec( &dev->buf_alloc );		return -EINVAL;	}	entry->buflist = drm_alloc( count * sizeof(*entry->buflist),				    DRM_MEM_BUFS );	if ( !entry->buflist ) {		up( &dev->struct_sem );		atomic_dec( &dev->buf_alloc );		return -ENOMEM;	}	memset( entry->buflist, 0, count * sizeof(*entry->buflist) );	entry->seglist = drm_alloc( count * sizeof(*entry->seglist),				    DRM_MEM_SEGS );	if ( !entry->seglist ) {		drm_free( entry->buflist,			  count * sizeof(*entry->buflist),			  DRM_MEM_BUFS );		up( &dev->struct_sem );		atomic_dec( &dev->buf_alloc );		return -ENOMEM;	}	memset( entry->seglist, 0, count * sizeof(*entry->seglist) );	/* Keep the original pagelist until we know all the allocations	 * have succeeded	 */	temp_pagelist = drm_alloc( (dma->page_count + (count << page_order))				    * sizeof(*dma->pagelist),				    DRM_MEM_PAGES );	if (!temp_pagelist) {		drm_free( entry->buflist,			   count * sizeof(*entry->buflist),			   DRM_MEM_BUFS );		drm_free( entry->seglist,			   count * sizeof(*entry->seglist),			   DRM_MEM_SEGS );		up( &dev->struct_sem );		atomic_dec( &dev->buf_alloc );		return -ENOMEM;	}	memcpy(temp_pagelist,	       dma->pagelist,	       dma->page_count * sizeof(*dma->pagelist));	DRM_DEBUG( "pagelist: %d entries\n",		   dma->page_count + (count << page_order) );	entry->buf_size	= size;	entry->page_order = page_order;	byte_count = 0;	page_count = 0;	while ( entry->buf_count < count ) {		page = drm_alloc_pages( page_order, DRM_MEM_DMA );		if ( !page ) {			/* Set count correctly so we free the proper amount. */			entry->buf_count = count;			entry->seg_count = count;			drm_cleanup_buf_error(dev, entry);			drm_free( temp_pagelist,				   (dma->page_count + (count << page_order))				   * sizeof(*dma->pagelist),				   DRM_MEM_PAGES );			up( &dev->struct_sem );			atomic_dec( &dev->buf_alloc );			return -ENOMEM;		}		entry->seglist[entry->seg_count++] = page;		for ( i = 0 ; i < (1 << page_order) ; i++ ) {			DRM_DEBUG( "page %d @ 0x%08lx\n",				   dma->page_count + page_count,				   page + PAGE_SIZE * i );			temp_pagelist[dma->page_count + page_count++]				= page + PAGE_SIZE * i;		}		for ( offset = 0 ;		      offset + size <= total && entry->buf_count < count ;		      offset += alignment, ++entry->buf_count ) {			buf	     = &entry->buflist[entry->buf_count];			buf->idx     = dma->buf_count + entry->buf_count;			buf->total   = alignment;			buf->order   = order;			buf->used    = 0;			buf->offset  = (dma->byte_count + byte_count + offset);			buf->address = (void *)(page + offset);			buf->next    = NULL;			buf->waiting = 0;			buf->pending = 0;			init_waitqueue_head( &buf->dma_wait );			buf->filp    = NULL;			buf->dev_priv_size = dev->driver->dev_priv_size;			buf->dev_private = drm_alloc( buf->dev_priv_size,						       DRM_MEM_BUFS );			if(!buf->dev_private) {				/* Set count correctly so we free the proper amount. */				entry->buf_count = count;				entry->seg_count = count;				drm_cleanup_buf_error(dev,entry);				drm_free( temp_pagelist,					   (dma->page_count + (count << page_order))					   * sizeof(*dma->pagelist),					   DRM_MEM_PAGES );				up( &dev->struct_sem );				atomic_dec( &dev->buf_alloc );				return -ENOMEM;			}			memset( buf->dev_private, 0, buf->dev_priv_size );			DRM_DEBUG( "buffer %d @ %p\n",				   entry->buf_count, buf->address );		}		byte_count += PAGE_SIZE << page_order;	}	temp_buflist = drm_realloc( dma->buflist,				     dma->buf_count * sizeof(*dma->buflist),				     (dma->buf_count + entry->buf_count)				     * sizeof(*dma->buflist),				     DRM_MEM_BUFS );	if (!temp_buflist) {		/* Free the entry because it isn't valid */		drm_cleanup_buf_error(dev,entry);		drm_free( temp_pagelist,			   (dma->page_count + (count << page_order))			   * sizeof(*dma->pagelist),			   DRM_MEM_PAGES );		up( &dev->struct_sem );		atomic_dec( &dev->buf_alloc );		return -ENOMEM;	}	dma->buflist = temp_buflist;	for ( i = 0 ; i < entry->buf_count ; i++ ) {		dma->buflist[i + dma->buf_count] = &entry->buflist[i];	}	/* No allocations failed, so now we can replace the orginal pagelist	 * with the new one.	 */	if (dma->page_count) {		drm_free(dma->pagelist,			  dma->page_count * sizeof(*dma->pagelist),			  DRM_MEM_PAGES);	}	dma->pagelist = temp_pagelist;	dma->buf_count += entry->buf_count;	dma->seg_count += entry->seg_count;	dma->page_count += entry->seg_count << page_order;	dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order);	up( &dev->struct_sem );	request.count = entry->buf_count;	request.size = size;	if ( copy_to_user( argp, &request, sizeof(request) ) )		return -EFAULT;	atomic_dec( &dev->buf_alloc );	return 0;}