phonedev.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /*
  2. * Telephony registration for Linux
  3. *
  4. * (c) Copyright 1999 Red Hat Software Inc.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version
  9. * 2 of the License, or (at your option) any later version.
  10. *
  11. * Author: Alan Cox, <alan@redhat.com>
  12. *
  13. * Fixes: Mar 01 2000 Thomas Sparr, <thomas.l.sparr@telia.com>
  14. * phone_register_device now works with unit!=PHONE_UNIT_ANY
  15. */
  16. #include <linux/module.h>
  17. #include <linux/types.h>
  18. #include <linux/kernel.h>
  19. #include <linux/fs.h>
  20. #include <linux/mm.h>
  21. #include <linux/string.h>
  22. #include <linux/errno.h>
  23. #include <linux/phonedev.h>
  24. #include <linux/init.h>
  25. #include <linux/smp_lock.h>
  26. #include <asm/uaccess.h>
  27. #include <asm/system.h>
  28. #include <linux/kmod.h>
  29. #include <linux/sem.h>
  30. #include <linux/mutex.h>
  31. #define PHONE_NUM_DEVICES 256
  32. /*
  33. * Active devices
  34. */
  35. static struct phone_device *phone_device[PHONE_NUM_DEVICES];
  36. static DEFINE_MUTEX(phone_lock);
  37. /*
  38. * Open a phone device.
  39. */
  40. static int phone_open(struct inode *inode, struct file *file)
  41. {
  42. unsigned int minor = iminor(inode);
  43. int err = 0;
  44. struct phone_device *p;
  45. const struct file_operations *old_fops, *new_fops = NULL;
  46. if (minor >= PHONE_NUM_DEVICES)
  47. return -ENODEV;
  48. lock_kernel();
  49. mutex_lock(&phone_lock);
  50. p = phone_device[minor];
  51. if (p)
  52. new_fops = fops_get(p->f_op);
  53. if (!new_fops) {
  54. mutex_unlock(&phone_lock);
  55. request_module("char-major-%d-%d", PHONE_MAJOR, minor);
  56. mutex_lock(&phone_lock);
  57. p = phone_device[minor];
  58. if (p == NULL || (new_fops = fops_get(p->f_op)) == NULL)
  59. {
  60. err=-ENODEV;
  61. goto end;
  62. }
  63. }
  64. old_fops = file->f_op;
  65. file->f_op = new_fops;
  66. if (p->open)
  67. err = p->open(p, file); /* Tell the device it is open */
  68. if (err) {
  69. fops_put(file->f_op);
  70. file->f_op = fops_get(old_fops);
  71. }
  72. fops_put(old_fops);
  73. end:
  74. mutex_unlock(&phone_lock);
  75. unlock_kernel();
  76. return err;
  77. }
  78. /*
  79. * Telephony For Linux device drivers request registration here.
  80. */
  81. int phone_register_device(struct phone_device *p, int unit)
  82. {
  83. int base;
  84. int end;
  85. int i;
  86. base = 0;
  87. end = PHONE_NUM_DEVICES - 1;
  88. if (unit != PHONE_UNIT_ANY) {
  89. base = unit;
  90. end = unit + 1; /* enter the loop at least one time */
  91. }
  92. mutex_lock(&phone_lock);
  93. for (i = base; i < end; i++) {
  94. if (phone_device[i] == NULL) {
  95. phone_device[i] = p;
  96. p->minor = i;
  97. mutex_unlock(&phone_lock);
  98. return 0;
  99. }
  100. }
  101. mutex_unlock(&phone_lock);
  102. return -ENFILE;
  103. }
  104. /*
  105. * Unregister an unused Telephony for linux device
  106. */
  107. void phone_unregister_device(struct phone_device *pfd)
  108. {
  109. mutex_lock(&phone_lock);
  110. if (likely(phone_device[pfd->minor] == pfd))
  111. phone_device[pfd->minor] = NULL;
  112. mutex_unlock(&phone_lock);
  113. }
  114. static const struct file_operations phone_fops =
  115. {
  116. .owner = THIS_MODULE,
  117. .open = phone_open,
  118. };
  119. /*
  120. * Board init functions
  121. */
  122. /*
  123. * Initialise Telephony for linux
  124. */
  125. static int __init telephony_init(void)
  126. {
  127. printk(KERN_INFO "Linux telephony interface: v1.00\n");
  128. if (register_chrdev(PHONE_MAJOR, "telephony", &phone_fops)) {
  129. printk("phonedev: unable to get major %d\n", PHONE_MAJOR);
  130. return -EIO;
  131. }
  132. return 0;
  133. }
  134. static void __exit telephony_exit(void)
  135. {
  136. unregister_chrdev(PHONE_MAJOR, "telephony");
  137. }
  138. module_init(telephony_init);
  139. module_exit(telephony_exit);
  140. MODULE_LICENSE("GPL");
  141. EXPORT_SYMBOL(phone_register_device);
  142. EXPORT_SYMBOL(phone_unregister_device);