phonedev.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  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/devfs_fs_kernel.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. mutex_lock(&phone_lock);
  49. p = phone_device[minor];
  50. if (p)
  51. new_fops = fops_get(p->f_op);
  52. if (!new_fops) {
  53. mutex_unlock(&phone_lock);
  54. request_module("char-major-%d-%d", PHONE_MAJOR, minor);
  55. mutex_lock(&phone_lock);
  56. p = phone_device[minor];
  57. if (p == NULL || (new_fops = fops_get(p->f_op)) == NULL)
  58. {
  59. err=-ENODEV;
  60. goto end;
  61. }
  62. }
  63. old_fops = file->f_op;
  64. file->f_op = new_fops;
  65. if (p->open)
  66. err = p->open(p, file); /* Tell the device it is open */
  67. if (err) {
  68. fops_put(file->f_op);
  69. file->f_op = fops_get(old_fops);
  70. }
  71. fops_put(old_fops);
  72. end:
  73. mutex_unlock(&phone_lock);
  74. return err;
  75. }
  76. /*
  77. * Telephony For Linux device drivers request registration here.
  78. */
  79. int phone_register_device(struct phone_device *p, int unit)
  80. {
  81. int base;
  82. int end;
  83. int i;
  84. base = 0;
  85. end = PHONE_NUM_DEVICES - 1;
  86. if (unit != PHONE_UNIT_ANY) {
  87. base = unit;
  88. end = unit + 1; /* enter the loop at least one time */
  89. }
  90. mutex_lock(&phone_lock);
  91. for (i = base; i < end; i++) {
  92. if (phone_device[i] == NULL) {
  93. phone_device[i] = p;
  94. p->minor = i;
  95. devfs_mk_cdev(MKDEV(PHONE_MAJOR,i),
  96. S_IFCHR|S_IRUSR|S_IWUSR, "phone/%d", 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 (phone_device[pfd->minor] != pfd)
  111. panic("phone: bad unregister");
  112. devfs_remove("phone/%d", pfd->minor);
  113. phone_device[pfd->minor] = NULL;
  114. mutex_unlock(&phone_lock);
  115. }
  116. static struct file_operations phone_fops =
  117. {
  118. .owner = THIS_MODULE,
  119. .open = phone_open,
  120. };
  121. /*
  122. * Board init functions
  123. */
  124. /*
  125. * Initialise Telephony for linux
  126. */
  127. static int __init telephony_init(void)
  128. {
  129. printk(KERN_INFO "Linux telephony interface: v1.00\n");
  130. if (register_chrdev(PHONE_MAJOR, "telephony", &phone_fops)) {
  131. printk("phonedev: unable to get major %d\n", PHONE_MAJOR);
  132. return -EIO;
  133. }
  134. return 0;
  135. }
  136. static void __exit telephony_exit(void)
  137. {
  138. unregister_chrdev(PHONE_MAJOR, "telephony");
  139. }
  140. module_init(telephony_init);
  141. module_exit(telephony_exit);
  142. MODULE_LICENSE("GPL");
  143. EXPORT_SYMBOL(phone_register_device);
  144. EXPORT_SYMBOL(phone_unregister_device);