phonedev.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  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 <asm/uaccess.h>
  26. #include <asm/system.h>
  27. #include <linux/kmod.h>
  28. #include <linux/sem.h>
  29. #include <linux/mutex.h>
  30. #define PHONE_NUM_DEVICES 256
  31. /*
  32. * Active devices
  33. */
  34. static struct phone_device *phone_device[PHONE_NUM_DEVICES];
  35. static DEFINE_MUTEX(phone_lock);
  36. /*
  37. * Open a phone device.
  38. */
  39. static int phone_open(struct inode *inode, struct file *file)
  40. {
  41. unsigned int minor = iminor(inode);
  42. int err = 0;
  43. struct phone_device *p;
  44. const struct file_operations *old_fops, *new_fops = NULL;
  45. if (minor >= PHONE_NUM_DEVICES)
  46. return -ENODEV;
  47. mutex_lock(&phone_lock);
  48. p = phone_device[minor];
  49. if (p)
  50. new_fops = fops_get(p->f_op);
  51. if (!new_fops) {
  52. mutex_unlock(&phone_lock);
  53. request_module("char-major-%d-%d", PHONE_MAJOR, minor);
  54. mutex_lock(&phone_lock);
  55. p = phone_device[minor];
  56. if (p == NULL || (new_fops = fops_get(p->f_op)) == NULL)
  57. {
  58. err=-ENODEV;
  59. goto end;
  60. }
  61. }
  62. old_fops = file->f_op;
  63. file->f_op = new_fops;
  64. if (p->open)
  65. err = p->open(p, file); /* Tell the device it is open */
  66. if (err) {
  67. fops_put(file->f_op);
  68. file->f_op = fops_get(old_fops);
  69. }
  70. fops_put(old_fops);
  71. end:
  72. mutex_unlock(&phone_lock);
  73. return err;
  74. }
  75. /*
  76. * Telephony For Linux device drivers request registration here.
  77. */
  78. int phone_register_device(struct phone_device *p, int unit)
  79. {
  80. int base;
  81. int end;
  82. int i;
  83. base = 0;
  84. end = PHONE_NUM_DEVICES - 1;
  85. if (unit != PHONE_UNIT_ANY) {
  86. base = unit;
  87. end = unit + 1; /* enter the loop at least one time */
  88. }
  89. mutex_lock(&phone_lock);
  90. for (i = base; i < end; i++) {
  91. if (phone_device[i] == NULL) {
  92. phone_device[i] = p;
  93. p->minor = i;
  94. mutex_unlock(&phone_lock);
  95. return 0;
  96. }
  97. }
  98. mutex_unlock(&phone_lock);
  99. return -ENFILE;
  100. }
  101. /*
  102. * Unregister an unused Telephony for linux device
  103. */
  104. void phone_unregister_device(struct phone_device *pfd)
  105. {
  106. mutex_lock(&phone_lock);
  107. if (phone_device[pfd->minor] != pfd)
  108. panic("phone: bad unregister");
  109. phone_device[pfd->minor] = NULL;
  110. mutex_unlock(&phone_lock);
  111. }
  112. static const struct file_operations phone_fops =
  113. {
  114. .owner = THIS_MODULE,
  115. .open = phone_open,
  116. };
  117. /*
  118. * Board init functions
  119. */
  120. /*
  121. * Initialise Telephony for linux
  122. */
  123. static int __init telephony_init(void)
  124. {
  125. printk(KERN_INFO "Linux telephony interface: v1.00\n");
  126. if (register_chrdev(PHONE_MAJOR, "telephony", &phone_fops)) {
  127. printk("phonedev: unable to get major %d\n", PHONE_MAJOR);
  128. return -EIO;
  129. }
  130. return 0;
  131. }
  132. static void __exit telephony_exit(void)
  133. {
  134. unregister_chrdev(PHONE_MAJOR, "telephony");
  135. }
  136. module_init(telephony_init);
  137. module_exit(telephony_exit);
  138. MODULE_LICENSE("GPL");
  139. EXPORT_SYMBOL(phone_register_device);
  140. EXPORT_SYMBOL(phone_unregister_device);