phonedev.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  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. #define PHONE_NUM_DEVICES 256
  31. /*
  32. * Active devices
  33. */
  34. static struct phone_device *phone_device[PHONE_NUM_DEVICES];
  35. static DECLARE_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. struct file_operations *old_fops, *new_fops = NULL;
  45. if (minor >= PHONE_NUM_DEVICES)
  46. return -ENODEV;
  47. down(&phone_lock);
  48. p = phone_device[minor];
  49. if (p)
  50. new_fops = fops_get(p->f_op);
  51. if (!new_fops) {
  52. up(&phone_lock);
  53. request_module("char-major-%d-%d", PHONE_MAJOR, minor);
  54. down(&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. up(&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. down(&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. devfs_mk_cdev(MKDEV(PHONE_MAJOR,i),
  95. S_IFCHR|S_IRUSR|S_IWUSR, "phone/%d", i);
  96. up(&phone_lock);
  97. return 0;
  98. }
  99. }
  100. up(&phone_lock);
  101. return -ENFILE;
  102. }
  103. /*
  104. * Unregister an unused Telephony for linux device
  105. */
  106. void phone_unregister_device(struct phone_device *pfd)
  107. {
  108. down(&phone_lock);
  109. if (phone_device[pfd->minor] != pfd)
  110. panic("phone: bad unregister");
  111. devfs_remove("phone/%d", pfd->minor);
  112. phone_device[pfd->minor] = NULL;
  113. up(&phone_lock);
  114. }
  115. static struct file_operations phone_fops =
  116. {
  117. .owner = THIS_MODULE,
  118. .open = phone_open,
  119. };
  120. /*
  121. * Board init functions
  122. */
  123. /*
  124. * Initialise Telephony for linux
  125. */
  126. static int __init telephony_init(void)
  127. {
  128. printk(KERN_INFO "Linux telephony interface: v1.00\n");
  129. if (register_chrdev(PHONE_MAJOR, "telephony", &phone_fops)) {
  130. printk("phonedev: unable to get major %d\n", PHONE_MAJOR);
  131. return -EIO;
  132. }
  133. return 0;
  134. }
  135. static void __exit telephony_exit(void)
  136. {
  137. unregister_chrdev(PHONE_MAJOR, "telephony");
  138. }
  139. module_init(telephony_init);
  140. module_exit(telephony_exit);
  141. MODULE_LICENSE("GPL");
  142. EXPORT_SYMBOL(phone_register_device);
  143. EXPORT_SYMBOL(phone_unregister_device);