proc.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:17k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* proc.c -- /proc support for DRM -*- linux-c -*-
  2.  * Created: Mon Jan 11 09:48:47 1999 by faith@precisioninsight.com
  3.  *
  4.  * Copyright 1999 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. #define __NO_VERSION__
  31. #include "drmP.h"
  32. static struct proc_dir_entry *drm_root    = NULL;
  33. static struct proc_dir_entry *drm_dev_root = NULL;
  34. static char      drm_slot_name[64];
  35. static int    drm_name_info(char *buf, char **start, off_t offset,
  36.  int len, int *eof, void *data);
  37. static int    drm_vm_info(char *buf, char **start, off_t offset,
  38.        int len, int *eof, void *data);
  39. static int    drm_clients_info(char *buf, char **start, off_t offset,
  40.     int len, int *eof, void *data);
  41. static int    drm_queues_info(char *buf, char **start, off_t offset,
  42.    int len, int *eof, void *data);
  43. static int    drm_bufs_info(char *buf, char **start, off_t offset,
  44.  int len, int *eof, void *data);
  45. #if DRM_DEBUG_CODE
  46. static int    drm_vma_info(char *buf, char **start, off_t offset,
  47. int len, int *eof, void *data);
  48. #endif
  49. #if DRM_DMA_HISTOGRAM
  50. static int    drm_histo_info(char *buf, char **start, off_t offset,
  51.   int len, int *eof, void *data);
  52. #endif
  53. struct drm_proc_list {
  54. const char *name;
  55. int    (*f)(char *, char **, off_t, int, int *, void *);
  56. } drm_proc_list[] = {
  57. { "name",    drm_name_info    },
  58. { "mem",     drm_mem_info     },
  59. { "vm",      drm_vm_info      },
  60. { "clients", drm_clients_info },
  61. { "queues",  drm_queues_info  },
  62. { "bufs",    drm_bufs_info    },
  63. #if DRM_DEBUG_CODE
  64. { "vma",     drm_vma_info     },
  65. #endif
  66. #if DRM_DMA_HISTOGRAM
  67. { "histo",   drm_histo_info   },
  68. #endif
  69. };
  70. #define DRM_PROC_ENTRIES (sizeof(drm_proc_list)/sizeof(drm_proc_list[0]))
  71. int drm_proc_init(drm_device_t *dev)
  72. {
  73. struct proc_dir_entry *ent;
  74. int       i, j;
  75. drm_root = create_proc_entry("dri", S_IFDIR, NULL);
  76. if (!drm_root) {
  77. DRM_ERROR("Cannot create /proc/drin");
  78. return -1;
  79. }
  80. /* Instead of doing this search, we should
  81.    add some global support for /proc/dri. */
  82. for (i = 0; i < 8; i++) {
  83. sprintf(drm_slot_name, "dri/%d", i);
  84. drm_dev_root = create_proc_entry(drm_slot_name, S_IFDIR, NULL);
  85. if (!drm_dev_root) {
  86. DRM_ERROR("Cannot create /proc/%sn", drm_slot_name);
  87. remove_proc_entry("dri", NULL);
  88. break;
  89. }
  90. if (drm_dev_root->nlink == 2) break;
  91. drm_dev_root = NULL;
  92. }
  93. if (!drm_dev_root) {
  94. DRM_ERROR("Cannot find slot in /proc/drin");
  95. return -1;
  96. }
  97. for (i = 0; i < DRM_PROC_ENTRIES; i++) {
  98. ent = create_proc_entry(drm_proc_list[i].name,
  99. S_IFREG|S_IRUGO, drm_dev_root);
  100. if (!ent) {
  101. DRM_ERROR("Cannot create /proc/%s/%sn",
  102.   drm_slot_name, drm_proc_list[i].name);
  103. for (j = 0; j < i; j++)
  104. remove_proc_entry(drm_proc_list[i].name,
  105.   drm_dev_root);
  106. remove_proc_entry(drm_slot_name, NULL);
  107. remove_proc_entry("dri", NULL);
  108. return -1;
  109. }
  110. ent->read_proc = drm_proc_list[i].f;
  111. ent->data      = dev;
  112. }
  113. return 0;
  114. }
  115. int drm_proc_cleanup(void)
  116. {
  117. int i;
  118. if (drm_root) {
  119. if (drm_dev_root) {
  120. for (i = 0; i < DRM_PROC_ENTRIES; i++) {
  121. remove_proc_entry(drm_proc_list[i].name,
  122.   drm_dev_root);
  123. }
  124. remove_proc_entry(drm_slot_name, NULL);
  125. }
  126. remove_proc_entry("dri", NULL);
  127. remove_proc_entry(DRM_NAME, NULL);
  128. }
  129. drm_root = drm_dev_root = NULL;
  130. return 0;
  131. }
  132. static int drm_name_info(char *buf, char **start, off_t offset, int len,
  133.  int *eof, void *data)
  134. {
  135. drm_device_t *dev = (drm_device_t *)data;
  136. if (offset > 0) return 0; /* no partial requests */
  137. len  = 0;
  138. *eof = 1;
  139. if (dev->unique) {
  140. DRM_PROC_PRINT("%s 0x%x %sn",
  141.        dev->name, dev->device, dev->unique);
  142. } else {
  143. DRM_PROC_PRINT("%s 0x%xn", dev->name, dev->device);
  144. }
  145. return len;
  146. }
  147. static int _drm_vm_info(char *buf, char **start, off_t offset, int len,
  148. int *eof, void *data)
  149. {
  150. drm_device_t *dev = (drm_device_t *)data;
  151. drm_map_t    *map;
  152. /* Hardcoded from _DRM_FRAME_BUFFER,
  153.                                    _DRM_REGISTERS, _DRM_SHM, and
  154.                                    _DRM_AGP. */
  155. const char   *types[] = { "FB", "REG", "SHM", "AGP" };
  156. const char   *type;
  157. int      i;
  158. if (offset > 0) return 0; /* no partial requests */
  159. len  = 0;
  160. *eof = 1;
  161. DRM_PROC_PRINT("slot  offset       size type flags  "
  162.        "address mtrrnn");
  163. for (i = 0; i < dev->map_count; i++) {
  164. map = dev->maplist[i];
  165. if (map->type < 0 || map->type > 3) type = "??";
  166. else     type = types[map->type];
  167. DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s  0x%02x 0x%08lx ",
  168.        i,
  169.        map->offset,
  170.        map->size,
  171.        type,
  172.        map->flags,
  173.        (unsigned long)map->handle);
  174. if (map->mtrr < 0) {
  175. DRM_PROC_PRINT("nonen");
  176. } else {
  177. DRM_PROC_PRINT("%4dn", map->mtrr);
  178. }
  179. }
  180. return len;
  181. }
  182. static int drm_vm_info(char *buf, char **start, off_t offset, int len,
  183.        int *eof, void *data)
  184. {
  185. drm_device_t *dev = (drm_device_t *)data;
  186. int      ret;
  187. down(&dev->struct_sem);
  188. ret = _drm_vm_info(buf, start, offset, len, eof, data);
  189. up(&dev->struct_sem);
  190. return ret;
  191. }
  192. static int _drm_queues_info(char *buf, char **start, off_t offset, int len,
  193.     int *eof, void *data)
  194. {
  195. drm_device_t *dev = (drm_device_t *)data;
  196. int      i;
  197. drm_queue_t  *q;
  198. if (offset > 0) return 0; /* no partial requests */
  199. len  = 0;
  200. *eof = 1;
  201. DRM_PROC_PRINT("  ctx/flags   use   fin"
  202.        "   blk/rw/rwf  wait    flushed    queued"
  203.        "      locksnn");
  204. for (i = 0; i < dev->queue_count; i++) {
  205. q = dev->queuelist[i];
  206. atomic_inc(&q->use_count);
  207. DRM_PROC_PRINT_RET(atomic_dec(&q->use_count),
  208.    "%5d/0x%03x %5d %5d"
  209.    " %5d/%c%c/%c%c%c %5Zd %10d %10d %10dn",
  210.    i,
  211.    q->flags,
  212.    atomic_read(&q->use_count),
  213.    atomic_read(&q->finalization),
  214.    atomic_read(&q->block_count),
  215.    atomic_read(&q->block_read) ? 'r' : '-',
  216.    atomic_read(&q->block_write) ? 'w' : '-',
  217.    waitqueue_active(&q->read_queue) ? 'r':'-',
  218.    waitqueue_active(&q->write_queue) ? 'w':'-',
  219.    waitqueue_active(&q->flush_queue) ? 'f':'-',
  220.    DRM_BUFCOUNT(&q->waitlist),
  221.    atomic_read(&q->total_flushed),
  222.    atomic_read(&q->total_queued),
  223.    atomic_read(&q->total_locks));
  224. atomic_dec(&q->use_count);
  225. }
  226. return len;
  227. }
  228. static int drm_queues_info(char *buf, char **start, off_t offset, int len,
  229.    int *eof, void *data)
  230. {
  231. drm_device_t *dev = (drm_device_t *)data;
  232. int      ret;
  233. down(&dev->struct_sem);
  234. ret = _drm_queues_info(buf, start, offset, len, eof, data);
  235. up(&dev->struct_sem);
  236. return ret;
  237. }
  238. /* drm_bufs_info is called whenever a process reads
  239.    /dev/drm/<dev>/bufs. */
  240. static int _drm_bufs_info(char *buf, char **start, off_t offset, int len,
  241.   int *eof, void *data)
  242. {
  243. drm_device_t  *dev = (drm_device_t *)data;
  244. drm_device_dma_t *dma = dev->dma;
  245. int  i;
  246. if (!dma) return 0;
  247. if (offset > 0) return 0; /* no partial requests */
  248. len  = 0;
  249. *eof = 1;
  250. DRM_PROC_PRINT(" o     size count  free  segs pages    kBnn");
  251. for (i = 0; i <= DRM_MAX_ORDER; i++) {
  252. if (dma->bufs[i].buf_count)
  253. DRM_PROC_PRINT("%2d %8d %5d %5d %5d %5d %5ldn",
  254.        i,
  255.        dma->bufs[i].buf_size,
  256.        dma->bufs[i].buf_count,
  257.        atomic_read(&dma->bufs[i]
  258.    .freelist.count),
  259.        dma->bufs[i].seg_count,
  260.        dma->bufs[i].seg_count
  261.        *(1 << dma->bufs[i].page_order),
  262.        (dma->bufs[i].seg_count
  263. * (1 << dma->bufs[i].page_order))
  264.        * PAGE_SIZE / 1024);
  265. }
  266. DRM_PROC_PRINT("n");
  267. for (i = 0; i < dma->buf_count; i++) {
  268. if (i && !(i%32)) DRM_PROC_PRINT("n");
  269. DRM_PROC_PRINT(" %d", dma->buflist[i]->list);
  270. }
  271. DRM_PROC_PRINT("n");
  272. return len;
  273. }
  274. static int drm_bufs_info(char *buf, char **start, off_t offset, int len,
  275.  int *eof, void *data)
  276. {
  277. drm_device_t *dev = (drm_device_t *)data;
  278. int      ret;
  279. down(&dev->struct_sem);
  280. ret = _drm_bufs_info(buf, start, offset, len, eof, data);
  281. up(&dev->struct_sem);
  282. return ret;
  283. }
  284. static int _drm_clients_info(char *buf, char **start, off_t offset, int len,
  285.      int *eof, void *data)
  286. {
  287. drm_device_t *dev = (drm_device_t *)data;
  288. drm_file_t   *priv;
  289. if (offset > 0) return 0; /* no partial requests */
  290. len  = 0;
  291. *eof = 1;
  292. DRM_PROC_PRINT("a dev pid    uid magic   ioctlsnn");
  293. for (priv = dev->file_first; priv; priv = priv->next) {
  294. DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lun",
  295.        priv->authenticated ? 'y' : 'n',
  296.        priv->minor,
  297.        priv->pid,
  298.        priv->uid,
  299.        priv->magic,
  300.        priv->ioctl_count);
  301. }
  302. return len;
  303. }
  304. static int drm_clients_info(char *buf, char **start, off_t offset, int len,
  305.     int *eof, void *data)
  306. {
  307. drm_device_t *dev = (drm_device_t *)data;
  308. int      ret;
  309. down(&dev->struct_sem);
  310. ret = _drm_clients_info(buf, start, offset, len, eof, data);
  311. up(&dev->struct_sem);
  312. return ret;
  313. }
  314. #if DRM_DEBUG_CODE
  315. #define DRM_VMA_VERBOSE 0
  316. static int _drm_vma_info(char *buf, char **start, off_t offset, int len,
  317.  int *eof, void *data)
  318. {
  319. drm_device_t       *dev = (drm_device_t *)data;
  320. drm_vma_entry_t       *pt;
  321. struct vm_area_struct *vma;
  322. #if DRM_VMA_VERBOSE
  323. unsigned long       i;
  324. unsigned long       address;
  325. pgd_t       *pgd;
  326. pmd_t       *pmd;
  327. pte_t       *pte;
  328. #endif
  329. #if defined(__i386__)
  330. unsigned int       pgprot;
  331. #endif
  332. if (offset > 0) return 0; /* no partial requests */
  333. len  = 0;
  334. *eof = 1;
  335. DRM_PROC_PRINT("vma use count: %d, high_memory = %p, 0x%08lxn",
  336.        atomic_read(&dev->vma_count),
  337.        high_memory, virt_to_phys(high_memory));
  338. for (pt = dev->vmalist; pt; pt = pt->next) {
  339. if (!(vma = pt->vma)) continue;
  340. DRM_PROC_PRINT("n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx",
  341.        pt->pid,
  342.        vma->vm_start,
  343.        vma->vm_end,
  344.        vma->vm_flags & VM_READ    ? 'r' : '-',
  345.        vma->vm_flags & VM_WRITE    ? 'w' : '-',
  346.        vma->vm_flags & VM_EXEC    ? 'x' : '-',
  347.        vma->vm_flags & VM_MAYSHARE ? 's' : 'p',
  348.        vma->vm_flags & VM_LOCKED   ? 'l' : '-',
  349.        vma->vm_flags & VM_IO    ? 'i' : '-',
  350.        VM_OFFSET(vma));
  351. #if defined(__i386__)
  352. pgprot = pgprot_val(vma->vm_page_prot);
  353. DRM_PROC_PRINT(" %c%c%c%c%c%c%c%c%c",
  354.        pgprot & _PAGE_PRESENT  ? 'p' : '-',
  355.        pgprot & _PAGE_RW       ? 'w' : 'r',
  356.        pgprot & _PAGE_USER     ? 'u' : 's',
  357.        pgprot & _PAGE_PWT      ? 't' : 'b',
  358.        pgprot & _PAGE_PCD      ? 'u' : 'c',
  359.        pgprot & _PAGE_ACCESSED ? 'a' : '-',
  360.        pgprot & _PAGE_DIRTY    ? 'd' : '-',
  361.        pgprot & _PAGE_PSE      ? 'm' : 'k',
  362.        pgprot & _PAGE_GLOBAL   ? 'g' : 'l' );
  363. #endif
  364. DRM_PROC_PRINT("n");
  365. #if 0
  366. for (i = vma->vm_start; i < vma->vm_end; i += PAGE_SIZE) {
  367. pgd = pgd_offset(vma->vm_mm, i);
  368. pmd = pmd_offset(pgd, i);
  369. pte = pte_offset(pmd, i);
  370. if (pte_present(*pte)) {
  371. address = __pa(pte_page(*pte))
  372. + (i & (PAGE_SIZE-1));
  373. DRM_PROC_PRINT("      0x%08lx -> 0x%08lx"
  374.        " %c%c%c%c%cn",
  375.        i,
  376.        address,
  377.        pte_read(*pte)  ? 'r' : '-',
  378.        pte_write(*pte) ? 'w' : '-',
  379.        pte_exec(*pte)  ? 'x' : '-',
  380.        pte_dirty(*pte) ? 'd' : '-',
  381.        pte_young(*pte) ? 'a' : '-' );
  382. } else {
  383. DRM_PROC_PRINT("      0x%08lxn", i);
  384. }
  385. }
  386. #endif
  387. }
  388. return len;
  389. }
  390. static int drm_vma_info(char *buf, char **start, off_t offset, int len,
  391. int *eof, void *data)
  392. {
  393. drm_device_t *dev = (drm_device_t *)data;
  394. int      ret;
  395. down(&dev->struct_sem);
  396. ret = _drm_vma_info(buf, start, offset, len, eof, data);
  397. up(&dev->struct_sem);
  398. return ret;
  399. }
  400. #endif
  401. #if DRM_DMA_HISTOGRAM
  402. static int _drm_histo_info(char *buf, char **start, off_t offset, int len,
  403.    int *eof, void *data)
  404. {
  405. drm_device_t  *dev = (drm_device_t *)data;
  406. drm_device_dma_t *dma = dev->dma;
  407. int  i;
  408. unsigned long  slot_value = DRM_DMA_HISTOGRAM_INITIAL;
  409. unsigned long  prev_value = 0;
  410. drm_buf_t  *buffer;
  411. if (offset > 0) return 0; /* no partial requests */
  412. len  = 0;
  413. *eof = 1;
  414. DRM_PROC_PRINT("general statistics:n");
  415. DRM_PROC_PRINT("total  %10un", atomic_read(&dev->histo.total));
  416. DRM_PROC_PRINT("open  %10un", atomic_read(&dev->total_open));
  417. DRM_PROC_PRINT("close  %10un", atomic_read(&dev->total_close));
  418. DRM_PROC_PRINT("ioctl  %10un", atomic_read(&dev->total_ioctl));
  419. DRM_PROC_PRINT("irq  %10un", atomic_read(&dev->total_irq));
  420. DRM_PROC_PRINT("ctx  %10un", atomic_read(&dev->total_ctx));
  421. DRM_PROC_PRINT("nlock statistics:n");
  422. DRM_PROC_PRINT("locks  %10un", atomic_read(&dev->total_locks));
  423. DRM_PROC_PRINT("unlocks  %10un", atomic_read(&dev->total_unlocks));
  424. DRM_PROC_PRINT("contends %10un", atomic_read(&dev->total_contends));
  425. DRM_PROC_PRINT("sleeps  %10un", atomic_read(&dev->total_sleeps));
  426. if (dma) {
  427. DRM_PROC_PRINT("ndma statistics:n");
  428. DRM_PROC_PRINT("prio  %10un",
  429.        atomic_read(&dma->total_prio));
  430. DRM_PROC_PRINT("bytes  %10un",
  431.        atomic_read(&dma->total_bytes));
  432. DRM_PROC_PRINT("dmas  %10un",
  433.        atomic_read(&dma->total_dmas));
  434. DRM_PROC_PRINT("missed:n");
  435. DRM_PROC_PRINT("  dma  %10un",
  436.        atomic_read(&dma->total_missed_dma));
  437. DRM_PROC_PRINT("  lock  %10un",
  438.        atomic_read(&dma->total_missed_lock));
  439. DRM_PROC_PRINT("  free  %10un",
  440.        atomic_read(&dma->total_missed_free));
  441. DRM_PROC_PRINT("  sched  %10un",
  442.        atomic_read(&dma->total_missed_sched));
  443. DRM_PROC_PRINT("tried  %10un",
  444.        atomic_read(&dma->total_tried));
  445. DRM_PROC_PRINT("hit  %10un",
  446.        atomic_read(&dma->total_hit));
  447. DRM_PROC_PRINT("lost  %10un",
  448.        atomic_read(&dma->total_lost));
  449. buffer = dma->next_buffer;
  450. if (buffer) {
  451. DRM_PROC_PRINT("next_buffer %7dn", buffer->idx);
  452. } else {
  453. DRM_PROC_PRINT("next_buffer    nonen");
  454. }
  455. buffer = dma->this_buffer;
  456. if (buffer) {
  457. DRM_PROC_PRINT("this_buffer %7dn", buffer->idx);
  458. } else {
  459. DRM_PROC_PRINT("this_buffer    nonen");
  460. }
  461. }
  462. DRM_PROC_PRINT("nvalues:n");
  463. if (dev->lock.hw_lock) {
  464. DRM_PROC_PRINT("lock        0x%08xn",
  465.        dev->lock.hw_lock->lock);
  466. } else {
  467. DRM_PROC_PRINT("lock      nonen");
  468. }
  469. DRM_PROC_PRINT("context_flag   0x%08lxn", dev->context_flag);
  470. DRM_PROC_PRINT("interrupt_flag 0x%08lxn", dev->interrupt_flag);
  471. DRM_PROC_PRINT("dma_flag       0x%08lxn", dev->dma_flag);
  472. DRM_PROC_PRINT("queue_count    %10dn",  dev->queue_count);
  473. DRM_PROC_PRINT("last_context   %10dn",  dev->last_context);
  474. DRM_PROC_PRINT("last_switch    %10lun", dev->last_switch);
  475. DRM_PROC_PRINT("last_checked   %10dn",  dev->last_checked);
  476. DRM_PROC_PRINT("n        q2d   d2c      c2f"
  477.        " q2c    q2f       dma  sch"
  478.        " ctx   lacq      lhldnn");
  479. for (i = 0; i < DRM_DMA_HISTOGRAM_SLOTS; i++) {
  480. DRM_PROC_PRINT("%s %10lu %10u %10u %10u %10u %10u"
  481.        " %10u %10u %10u %10u %10un",
  482.        i == DRM_DMA_HISTOGRAM_SLOTS - 1 ? ">=" : "< ",
  483.        i == DRM_DMA_HISTOGRAM_SLOTS - 1
  484.        ? prev_value : slot_value ,
  485.        
  486.        atomic_read(&dev->histo
  487.    .queued_to_dispatched[i]),
  488.        atomic_read(&dev->histo
  489.    .dispatched_to_completed[i]),
  490.        atomic_read(&dev->histo
  491.    .completed_to_freed[i]),
  492.        
  493.        atomic_read(&dev->histo
  494.    .queued_to_completed[i]),
  495.        atomic_read(&dev->histo
  496.    .queued_to_freed[i]),
  497.        atomic_read(&dev->histo.dma[i]),
  498.        atomic_read(&dev->histo.schedule[i]),
  499.        atomic_read(&dev->histo.ctx[i]),
  500.        atomic_read(&dev->histo.lacq[i]),
  501.        atomic_read(&dev->histo.lhld[i]));
  502. prev_value = slot_value;
  503. slot_value = DRM_DMA_HISTOGRAM_NEXT(slot_value);
  504. }
  505. return len;
  506. }
  507. static int drm_histo_info(char *buf, char **start, off_t offset, int len,
  508.   int *eof, void *data)
  509. {
  510. drm_device_t *dev = (drm_device_t *)data;
  511. int      ret;
  512. down(&dev->struct_sem);
  513. ret = _drm_histo_info(buf, start, offset, len, eof, data);
  514. up(&dev->struct_sem);
  515. return ret;
  516. }
  517. #endif