bufs.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:14k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /* bufs.c -- IOCTLs to manage buffers -*- linux-c -*-
  2.  * Created: Tue Feb  2 08:37:54 1999 by faith@precisioninsight.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.  * PRECISION INSIGHT 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 OTHER
  25.  * DEALINGS IN THE SOFTWARE.
  26.  * 
  27.  * Authors:
  28.  *    Rickard E. (Rik) Faith <faith@valinux.com>
  29.  *
  30.  */
  31. #define __NO_VERSION__
  32. #include <linux/config.h>
  33. #include "drmP.h"
  34. #include "linux/un.h"
  35. /* Compute order.  Can be made faster. */
  36. int drm_order(unsigned long size)
  37. {
  38. int       order;
  39. unsigned long tmp;
  40. for (order = 0, tmp = size; tmp >>= 1; ++order);
  41. if (size & ~(1 << order)) ++order;
  42. return order;
  43. }
  44. int drm_addmap(struct inode *inode, struct file *filp, unsigned int cmd,
  45.        unsigned long arg)
  46. {
  47. drm_file_t *priv = filp->private_data;
  48. drm_device_t *dev = priv->dev;
  49. drm_map_t *map;
  50. if (!(filp->f_mode & 3)) return -EACCES; /* Require read/write */
  51. map      = drm_alloc(sizeof(*map), DRM_MEM_MAPS);
  52. if (!map) return -ENOMEM;
  53. if (copy_from_user(map, (drm_map_t *)arg, sizeof(*map))) {
  54. drm_free(map, sizeof(*map), DRM_MEM_MAPS);
  55. return -EFAULT;
  56. }
  57. DRM_DEBUG("offset = 0x%08lx, size = 0x%08lx, type = %dn",
  58.   map->offset, map->size, map->type);
  59. if ((map->offset & (~PAGE_MASK)) || (map->size & (~PAGE_MASK))) {
  60. drm_free(map, sizeof(*map), DRM_MEM_MAPS);
  61. return -EINVAL;
  62. }
  63. map->mtrr   = -1;
  64. map->handle = 0;
  65. switch (map->type) {
  66. case _DRM_REGISTERS:
  67. case _DRM_FRAME_BUFFER:
  68. #ifndef __sparc__
  69. if (map->offset + map->size < map->offset
  70.     || map->offset < virt_to_phys(high_memory)) {
  71. drm_free(map, sizeof(*map), DRM_MEM_MAPS);
  72. return -EINVAL;
  73. }
  74. #endif
  75. #ifdef CONFIG_MTRR
  76. if (map->type == _DRM_FRAME_BUFFER
  77.     || (map->flags & _DRM_WRITE_COMBINING)) {
  78. map->mtrr = mtrr_add(map->offset, map->size,
  79.      MTRR_TYPE_WRCOMB, 1);
  80. }
  81. #endif
  82. map->handle = drm_ioremap(map->offset, map->size);
  83. break;
  84. case _DRM_SHM:
  85. map->handle = (void *)drm_alloc_pages(drm_order(map->size)
  86.       - PAGE_SHIFT,
  87.       DRM_MEM_SAREA);
  88. DRM_DEBUG("%ld %d %pn", map->size, drm_order(map->size),
  89.   map->handle);
  90. if (!map->handle) {
  91. drm_free(map, sizeof(*map), DRM_MEM_MAPS);
  92. return -ENOMEM;
  93. }
  94. map->offset = (unsigned long)map->handle;
  95. if (map->flags & _DRM_CONTAINS_LOCK) {
  96. dev->lock.hw_lock = map->handle; /* Pointer to lock */
  97. }
  98. break;
  99. #if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
  100. case _DRM_AGP:
  101. map->offset = map->offset + dev->agp->base;
  102. break;
  103. #endif
  104. default:
  105. drm_free(map, sizeof(*map), DRM_MEM_MAPS);
  106. return -EINVAL;
  107. }
  108. down(&dev->struct_sem);
  109. if (dev->maplist) {
  110. ++dev->map_count;
  111. dev->maplist = drm_realloc(dev->maplist,
  112.    (dev->map_count-1)
  113.    * sizeof(*dev->maplist),
  114.    dev->map_count
  115.    * sizeof(*dev->maplist),
  116.    DRM_MEM_MAPS);
  117. } else {
  118. dev->map_count = 1;
  119. dev->maplist = drm_alloc(dev->map_count*sizeof(*dev->maplist),
  120.  DRM_MEM_MAPS);
  121. }
  122. dev->maplist[dev->map_count-1] = map;
  123. up(&dev->struct_sem);
  124. if (copy_to_user((drm_map_t *)arg, map, sizeof(*map)))
  125. return -EFAULT;
  126. if (map->type != _DRM_SHM) {
  127. if (copy_to_user(&((drm_map_t *)arg)->handle,
  128.  &map->offset,
  129.  sizeof(map->offset)))
  130. return -EFAULT;
  131. }
  132. return 0;
  133. }
  134. int drm_addbufs(struct inode *inode, struct file *filp, unsigned int cmd,
  135. unsigned long arg)
  136. {
  137. drm_file_t  *priv  = filp->private_data;
  138. drm_device_t  *dev  = priv->dev;
  139. drm_device_dma_t *dma  = dev->dma;
  140. drm_buf_desc_t  request;
  141. int  count;
  142. int  order;
  143. int  size;
  144. int  total;
  145. int  page_order;
  146. drm_buf_entry_t  *entry;
  147. unsigned long  page;
  148. drm_buf_t  *buf;
  149. int  alignment;
  150. unsigned long  offset;
  151. int  i;
  152. int  byte_count;
  153. int  page_count;
  154. if (!dma) return -EINVAL;
  155. if (copy_from_user(&request,
  156.    (drm_buf_desc_t *)arg,
  157.    sizeof(request)))
  158. return -EFAULT;
  159. count    = request.count;
  160. order    = drm_order(request.size);
  161. size    = 1 << order;
  162. DRM_DEBUG("count = %d, size = %d (%d), order = %d, queue_count = %dn",
  163.   request.count, request.size, size, order, dev->queue_count);
  164. if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL;
  165. if (dev->queue_count) return -EBUSY; /* Not while in use */
  166. alignment  = (request.flags & _DRM_PAGE_ALIGN) ? PAGE_ALIGN(size):size;
  167. page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
  168. total    = PAGE_SIZE << page_order;
  169. spin_lock(&dev->count_lock);
  170. if (dev->buf_use) {
  171. spin_unlock(&dev->count_lock);
  172. return -EBUSY;
  173. }
  174. atomic_inc(&dev->buf_alloc);
  175. spin_unlock(&dev->count_lock);
  176. down(&dev->struct_sem);
  177. entry = &dma->bufs[order];
  178. if (entry->buf_count) {
  179. up(&dev->struct_sem);
  180. atomic_dec(&dev->buf_alloc);
  181. return -ENOMEM; /* May only call once for each order */
  182. }
  183. if(count < 0 || count > 4096)
  184. {
  185. up(&dev->struct_sem);
  186. return -EINVAL;
  187. }
  188. entry->buflist = drm_alloc(count * sizeof(*entry->buflist),
  189.    DRM_MEM_BUFS);
  190. if (!entry->buflist) {
  191. up(&dev->struct_sem);
  192. atomic_dec(&dev->buf_alloc);
  193. return -ENOMEM;
  194. }
  195. memset(entry->buflist, 0, count * sizeof(*entry->buflist));
  196. entry->seglist = drm_alloc(count * sizeof(*entry->seglist),
  197.    DRM_MEM_SEGS);
  198. if (!entry->seglist) {
  199. drm_free(entry->buflist,
  200.  count * sizeof(*entry->buflist),
  201.  DRM_MEM_BUFS);
  202. up(&dev->struct_sem);
  203. atomic_dec(&dev->buf_alloc);
  204. return -ENOMEM;
  205. }
  206. memset(entry->seglist, 0, count * sizeof(*entry->seglist));
  207. dma->pagelist = drm_realloc(dma->pagelist,
  208.     dma->page_count * sizeof(*dma->pagelist),
  209.     (dma->page_count + (count << page_order))
  210.     * sizeof(*dma->pagelist),
  211.     DRM_MEM_PAGES);
  212. DRM_DEBUG("pagelist: %d entriesn",
  213.   dma->page_count + (count << page_order));
  214. entry->buf_size   = size;
  215. entry->page_order = page_order;
  216. byte_count   = 0;
  217. page_count   = 0;
  218. while (entry->buf_count < count) {
  219. if (!(page = drm_alloc_pages(page_order, DRM_MEM_DMA))) break;
  220. entry->seglist[entry->seg_count++] = page;
  221. for (i = 0; i < (1 << page_order); i++) {
  222. DRM_DEBUG("page %d @ 0x%08lxn",
  223.   dma->page_count + page_count,
  224.   page + PAGE_SIZE * i);
  225. dma->pagelist[dma->page_count + page_count++]
  226. = page + PAGE_SIZE * i;
  227. }
  228. for (offset = 0;
  229.      offset + size <= total && entry->buf_count < count;
  230.      offset += alignment, ++entry->buf_count) {
  231. buf      = &entry->buflist[entry->buf_count];
  232. buf->idx     = dma->buf_count + entry->buf_count;
  233. buf->total   = alignment;
  234. buf->order   = order;
  235. buf->used    = 0;
  236. buf->offset  = (dma->byte_count + byte_count + offset);
  237. buf->address = (void *)(page + offset);
  238. buf->next    = NULL;
  239. buf->waiting = 0;
  240. buf->pending = 0;
  241. init_waitqueue_head(&buf->dma_wait);
  242. buf->pid     = 0;
  243. #if DRM_DMA_HISTOGRAM
  244. buf->time_queued     = 0;
  245. buf->time_dispatched = 0;
  246. buf->time_completed  = 0;
  247. buf->time_freed      = 0;
  248. #endif
  249. DRM_DEBUG("buffer %d @ %pn",
  250.   entry->buf_count, buf->address);
  251. }
  252. byte_count += PAGE_SIZE << page_order;
  253. }
  254. dma->buflist = drm_realloc(dma->buflist,
  255.    dma->buf_count * sizeof(*dma->buflist),
  256.    (dma->buf_count + entry->buf_count)
  257.    * sizeof(*dma->buflist),
  258.    DRM_MEM_BUFS);
  259. for (i = dma->buf_count; i < dma->buf_count + entry->buf_count; i++)
  260. dma->buflist[i] = &entry->buflist[i - dma->buf_count];
  261. dma->buf_count += entry->buf_count;
  262. dma->seg_count += entry->seg_count;
  263. dma->page_count += entry->seg_count << page_order;
  264. dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order);
  265. drm_freelist_create(&entry->freelist, entry->buf_count);
  266. for (i = 0; i < entry->buf_count; i++) {
  267. drm_freelist_put(dev, &entry->freelist, &entry->buflist[i]);
  268. }
  269. up(&dev->struct_sem);
  270. request.count = entry->buf_count;
  271. request.size  = size;
  272. if (copy_to_user((drm_buf_desc_t *)arg,
  273.  &request,
  274.  sizeof(request)))
  275. return -EFAULT;
  276. atomic_dec(&dev->buf_alloc);
  277. return 0;
  278. }
  279. int drm_infobufs(struct inode *inode, struct file *filp, unsigned int cmd,
  280.  unsigned long arg)
  281. {
  282. drm_file_t  *priv  = filp->private_data;
  283. drm_device_t  *dev  = priv->dev;
  284. drm_device_dma_t *dma  = dev->dma;
  285. drm_buf_info_t  request;
  286. int  i;
  287. int  count;
  288. if (!dma) return -EINVAL;
  289. spin_lock(&dev->count_lock);
  290. if (atomic_read(&dev->buf_alloc)) {
  291. spin_unlock(&dev->count_lock);
  292. return -EBUSY;
  293. }
  294. ++dev->buf_use; /* Can't allocate more after this call */
  295. spin_unlock(&dev->count_lock);
  296. if (copy_from_user(&request,
  297.    (drm_buf_info_t *)arg,
  298.    sizeof(request)))
  299. return -EFAULT;
  300. for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) {
  301. if (dma->bufs[i].buf_count) ++count;
  302. }
  303. DRM_DEBUG("count = %dn", count);
  304. if (request.count >= count) {
  305. for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) {
  306. if (dma->bufs[i].buf_count) {
  307. if (copy_to_user(&request.list[count].count,
  308.  &dma->bufs[i].buf_count,
  309.  sizeof(dma->bufs[0]
  310. .buf_count)) ||
  311.     copy_to_user(&request.list[count].size,
  312.  &dma->bufs[i].buf_size,
  313.  sizeof(dma->bufs[0].buf_size)) ||
  314.     copy_to_user(&request.list[count].low_mark,
  315.  &dma->bufs[i]
  316.  .freelist.low_mark,
  317.  sizeof(dma->bufs[0]
  318. .freelist.low_mark)) ||
  319.     copy_to_user(&request.list[count]
  320.  .high_mark,
  321.  &dma->bufs[i]
  322.  .freelist.high_mark,
  323.  sizeof(dma->bufs[0]
  324. .freelist.high_mark)))
  325. return -EFAULT;
  326. DRM_DEBUG("%d %d %d %d %dn",
  327.   i,
  328.   dma->bufs[i].buf_count,
  329.   dma->bufs[i].buf_size,
  330.   dma->bufs[i].freelist.low_mark,
  331.   dma->bufs[i].freelist.high_mark);
  332. ++count;
  333. }
  334. }
  335. }
  336. request.count = count;
  337. if (copy_to_user((drm_buf_info_t *)arg,
  338.  &request,
  339.  sizeof(request)))
  340. return -EFAULT;
  341. return 0;
  342. }
  343. int drm_markbufs(struct inode *inode, struct file *filp, unsigned int cmd,
  344.  unsigned long arg)
  345. {
  346. drm_file_t  *priv  = filp->private_data;
  347. drm_device_t  *dev  = priv->dev;
  348. drm_device_dma_t *dma  = dev->dma;
  349. drm_buf_desc_t  request;
  350. int  order;
  351. drm_buf_entry_t  *entry;
  352. if (!dma) return -EINVAL;
  353. if (copy_from_user(&request,
  354.    (drm_buf_desc_t *)arg,
  355.    sizeof(request)))
  356. return -EFAULT;
  357. DRM_DEBUG("%d, %d, %dn",
  358.   request.size, request.low_mark, request.high_mark);
  359. order = drm_order(request.size);
  360. if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL;
  361. entry = &dma->bufs[order];
  362. if (request.low_mark < 0 || request.low_mark > entry->buf_count)
  363. return -EINVAL;
  364. if (request.high_mark < 0 || request.high_mark > entry->buf_count)
  365. return -EINVAL;
  366. entry->freelist.low_mark  = request.low_mark;
  367. entry->freelist.high_mark = request.high_mark;
  368. return 0;
  369. }
  370. int drm_freebufs(struct inode *inode, struct file *filp, unsigned int cmd,
  371.  unsigned long arg)
  372. {
  373. drm_file_t  *priv  = filp->private_data;
  374. drm_device_t  *dev  = priv->dev;
  375. drm_device_dma_t *dma  = dev->dma;
  376. drm_buf_free_t  request;
  377. int  i;
  378. int  idx;
  379. drm_buf_t  *buf;
  380. if (!dma) return -EINVAL;
  381. if (copy_from_user(&request,
  382.    (drm_buf_free_t *)arg,
  383.    sizeof(request)))
  384. return -EFAULT;
  385. DRM_DEBUG("%dn", request.count);
  386. for (i = 0; i < request.count; i++) {
  387. if (copy_from_user(&idx,
  388.    &request.list[i],
  389.    sizeof(idx)))
  390. return -EFAULT;
  391. if (idx < 0 || idx >= dma->buf_count) {
  392. DRM_ERROR("Index %d (of %d max)n",
  393.   idx, dma->buf_count - 1);
  394. return -EINVAL;
  395. }
  396. buf = dma->buflist[idx];
  397. if (buf->pid != current->pid) {
  398. DRM_ERROR("Process %d freeing buffer owned by %dn",
  399.   current->pid, buf->pid);
  400. return -EINVAL;
  401. }
  402. drm_free_buffer(dev, buf);
  403. }
  404. return 0;
  405. }
  406. int drm_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd,
  407. unsigned long arg)
  408. {
  409. drm_file_t  *priv  = filp->private_data;
  410. drm_device_t  *dev  = priv->dev;
  411. drm_device_dma_t *dma  = dev->dma;
  412. int  retcode = 0;
  413. const int  zero  = 0;
  414. unsigned long  virtual;
  415. unsigned long  address;
  416. drm_buf_map_t  request;
  417. int  i;
  418. if (!dma) return -EINVAL;
  419. DRM_DEBUG("n");
  420. spin_lock(&dev->count_lock);
  421. if (atomic_read(&dev->buf_alloc)) {
  422. spin_unlock(&dev->count_lock);
  423. return -EBUSY;
  424. }
  425. ++dev->buf_use; /* Can't allocate more after this call */
  426. spin_unlock(&dev->count_lock);
  427. if (copy_from_user(&request,
  428.    (drm_buf_map_t *)arg,
  429.    sizeof(request)))
  430. return -EFAULT;
  431. if (request.count >= dma->buf_count) {
  432. down_write(&current->mm->mmap_sem);
  433. virtual = do_mmap(filp, 0, dma->byte_count,
  434.   PROT_READ|PROT_WRITE, MAP_SHARED, 0);
  435. up_write(&current->mm->mmap_sem);
  436. if (virtual > -1024UL) {
  437. /* Real error */
  438. retcode = (signed long)virtual;
  439. goto done;
  440. }
  441. request.virtual = (void *)virtual;
  442. for (i = 0; i < dma->buf_count; i++) {
  443. if (copy_to_user(&request.list[i].idx,
  444.  &dma->buflist[i]->idx,
  445.  sizeof(request.list[0].idx))) {
  446. retcode = -EFAULT;
  447. goto done;
  448. }
  449. if (copy_to_user(&request.list[i].total,
  450.  &dma->buflist[i]->total,
  451.  sizeof(request.list[0].total))) {
  452. retcode = -EFAULT;
  453. goto done;
  454. }
  455. if (copy_to_user(&request.list[i].used,
  456.  &zero,
  457.  sizeof(zero))) {
  458. retcode = -EFAULT;
  459. goto done;
  460. }
  461. address = virtual + dma->buflist[i]->offset;
  462. if (copy_to_user(&request.list[i].address,
  463.  &address,
  464.  sizeof(address))) {
  465. retcode = -EFAULT;
  466. goto done;
  467. }
  468. }
  469. }
  470. done:
  471. request.count = dma->buf_count;
  472. DRM_DEBUG("%d buffers, retcode = %dn", request.count, retcode);
  473. if (copy_to_user((drm_buf_map_t *)arg,
  474.  &request,
  475.  sizeof(request)))
  476. return -EFAULT;
  477. return retcode;
  478. }