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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/fs/block_dev.c
  3.  *
  4.  *  Copyright (C) 1991, 1992  Linus Torvalds
  5.  */
  6. #include <linux/config.h>
  7. #include <linux/init.h>
  8. #include <linux/slab.h>
  9. #define HASH_BITS 6
  10. #define HASH_SIZE (1UL << HASH_BITS)
  11. #define HASH_MASK (HASH_SIZE-1)
  12. static struct list_head cdev_hashtable[HASH_SIZE];
  13. static spinlock_t cdev_lock = SPIN_LOCK_UNLOCKED;
  14. static kmem_cache_t * cdev_cachep;
  15. #define alloc_cdev() 
  16.  ((struct char_device *) kmem_cache_alloc(cdev_cachep, SLAB_KERNEL))
  17. #define destroy_cdev(cdev) kmem_cache_free(cdev_cachep, (cdev))
  18. static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
  19. {
  20. struct char_device * cdev = (struct char_device *) foo;
  21. if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
  22.     SLAB_CTOR_CONSTRUCTOR)
  23. {
  24. memset(cdev, 0, sizeof(*cdev));
  25. sema_init(&cdev->sem, 1);
  26. }
  27. }
  28. void __init cdev_cache_init(void)
  29. {
  30. int i;
  31. struct list_head *head = cdev_hashtable;
  32. i = HASH_SIZE;
  33. do {
  34. INIT_LIST_HEAD(head);
  35. head++;
  36. i--;
  37. } while (i);
  38. cdev_cachep = kmem_cache_create("cdev_cache",
  39.  sizeof(struct char_device),
  40.  0, SLAB_HWCACHE_ALIGN, init_once,
  41.  NULL);
  42. if (!cdev_cachep)
  43. panic("Cannot create cdev_cache SLAB cache");
  44. }
  45. /*
  46.  * Most likely _very_ bad one - but then it's hardly critical for small
  47.  * /dev and can be fixed when somebody will need really large one.
  48.  */
  49. static inline unsigned long hash(dev_t dev)
  50. {
  51. unsigned long tmp = dev;
  52. tmp = tmp + (tmp >> HASH_BITS) + (tmp >> HASH_BITS*2);
  53. return tmp & HASH_MASK;
  54. }
  55. static struct char_device *cdfind(dev_t dev, struct list_head *head)
  56. {
  57. struct list_head *p;
  58. struct char_device *cdev;
  59. for (p=head->next; p!=head; p=p->next) {
  60. cdev = list_entry(p, struct char_device, hash);
  61. if (cdev->dev != dev)
  62. continue;
  63. atomic_inc(&cdev->count);
  64. return cdev;
  65. }
  66. return NULL;
  67. }
  68. struct char_device *cdget(dev_t dev)
  69. {
  70. struct list_head * head = cdev_hashtable + hash(dev);
  71. struct char_device *cdev, *new_cdev;
  72. spin_lock(&cdev_lock);
  73. cdev = cdfind(dev, head);
  74. spin_unlock(&cdev_lock);
  75. if (cdev)
  76. return cdev;
  77. new_cdev = alloc_cdev();
  78. if (!new_cdev)
  79. return NULL;
  80. atomic_set(&new_cdev->count,1);
  81. new_cdev->dev = dev;
  82. spin_lock(&cdev_lock);
  83. cdev = cdfind(dev, head);
  84. if (!cdev) {
  85. list_add(&new_cdev->hash, head);
  86. spin_unlock(&cdev_lock);
  87. return new_cdev;
  88. }
  89. spin_unlock(&cdev_lock);
  90. destroy_cdev(new_cdev);
  91. return cdev;
  92. }
  93. void cdput(struct char_device *cdev)
  94. {
  95. if (atomic_dec_and_lock(&cdev->count, &cdev_lock)) {
  96. list_del(&cdev->hash);
  97. spin_unlock(&cdev_lock);
  98. destroy_cdev(cdev);
  99. }
  100. }