diff options
Diffstat (limited to 'drivers/telephony/phonedev.c')
-rw-r--r-- | drivers/telephony/phonedev.c | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/drivers/telephony/phonedev.c b/drivers/telephony/phonedev.c new file mode 100644 index 000000000000..3c987f49f6b4 --- /dev/null +++ b/drivers/telephony/phonedev.c | |||
@@ -0,0 +1,170 @@ | |||
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 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/types.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/fs.h> | ||
21 | #include <linux/mm.h> | ||
22 | #include <linux/string.h> | ||
23 | #include <linux/errno.h> | ||
24 | #include <linux/phonedev.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <asm/uaccess.h> | ||
27 | #include <asm/system.h> | ||
28 | |||
29 | #include <linux/kmod.h> | ||
30 | #include <linux/sem.h> | ||
31 | #include <linux/devfs_fs_kernel.h> | ||
32 | |||
33 | #define PHONE_NUM_DEVICES 256 | ||
34 | |||
35 | /* | ||
36 | * Active devices | ||
37 | */ | ||
38 | |||
39 | static struct phone_device *phone_device[PHONE_NUM_DEVICES]; | ||
40 | static DECLARE_MUTEX(phone_lock); | ||
41 | |||
42 | /* | ||
43 | * Open a phone device. | ||
44 | */ | ||
45 | |||
46 | static int phone_open(struct inode *inode, struct file *file) | ||
47 | { | ||
48 | unsigned int minor = iminor(inode); | ||
49 | int err = 0; | ||
50 | struct phone_device *p; | ||
51 | struct file_operations *old_fops, *new_fops = NULL; | ||
52 | |||
53 | if (minor >= PHONE_NUM_DEVICES) | ||
54 | return -ENODEV; | ||
55 | |||
56 | down(&phone_lock); | ||
57 | p = phone_device[minor]; | ||
58 | if (p) | ||
59 | new_fops = fops_get(p->f_op); | ||
60 | if (!new_fops) { | ||
61 | up(&phone_lock); | ||
62 | request_module("char-major-%d-%d", PHONE_MAJOR, minor); | ||
63 | down(&phone_lock); | ||
64 | p = phone_device[minor]; | ||
65 | if (p == NULL || (new_fops = fops_get(p->f_op)) == NULL) | ||
66 | { | ||
67 | err=-ENODEV; | ||
68 | goto end; | ||
69 | } | ||
70 | } | ||
71 | old_fops = file->f_op; | ||
72 | file->f_op = new_fops; | ||
73 | if (p->open) | ||
74 | err = p->open(p, file); /* Tell the device it is open */ | ||
75 | if (err) { | ||
76 | fops_put(file->f_op); | ||
77 | file->f_op = fops_get(old_fops); | ||
78 | } | ||
79 | fops_put(old_fops); | ||
80 | end: | ||
81 | up(&phone_lock); | ||
82 | return err; | ||
83 | } | ||
84 | |||
85 | /* | ||
86 | * Telephony For Linux device drivers request registration here. | ||
87 | */ | ||
88 | |||
89 | int phone_register_device(struct phone_device *p, int unit) | ||
90 | { | ||
91 | int base; | ||
92 | int end; | ||
93 | int i; | ||
94 | |||
95 | base = 0; | ||
96 | end = PHONE_NUM_DEVICES - 1; | ||
97 | |||
98 | if (unit != PHONE_UNIT_ANY) { | ||
99 | base = unit; | ||
100 | end = unit + 1; /* enter the loop at least one time */ | ||
101 | } | ||
102 | |||
103 | down(&phone_lock); | ||
104 | for (i = base; i < end; i++) { | ||
105 | if (phone_device[i] == NULL) { | ||
106 | phone_device[i] = p; | ||
107 | p->minor = i; | ||
108 | devfs_mk_cdev(MKDEV(PHONE_MAJOR,i), | ||
109 | S_IFCHR|S_IRUSR|S_IWUSR, "phone/%d", i); | ||
110 | up(&phone_lock); | ||
111 | return 0; | ||
112 | } | ||
113 | } | ||
114 | up(&phone_lock); | ||
115 | return -ENFILE; | ||
116 | } | ||
117 | |||
118 | /* | ||
119 | * Unregister an unused Telephony for linux device | ||
120 | */ | ||
121 | |||
122 | void phone_unregister_device(struct phone_device *pfd) | ||
123 | { | ||
124 | down(&phone_lock); | ||
125 | if (phone_device[pfd->minor] != pfd) | ||
126 | panic("phone: bad unregister"); | ||
127 | devfs_remove("phone/%d", pfd->minor); | ||
128 | phone_device[pfd->minor] = NULL; | ||
129 | up(&phone_lock); | ||
130 | } | ||
131 | |||
132 | |||
133 | static struct file_operations phone_fops = | ||
134 | { | ||
135 | .owner = THIS_MODULE, | ||
136 | .open = phone_open, | ||
137 | }; | ||
138 | |||
139 | /* | ||
140 | * Board init functions | ||
141 | */ | ||
142 | |||
143 | |||
144 | /* | ||
145 | * Initialise Telephony for linux | ||
146 | */ | ||
147 | |||
148 | static int __init telephony_init(void) | ||
149 | { | ||
150 | printk(KERN_INFO "Linux telephony interface: v1.00\n"); | ||
151 | if (register_chrdev(PHONE_MAJOR, "telephony", &phone_fops)) { | ||
152 | printk("phonedev: unable to get major %d\n", PHONE_MAJOR); | ||
153 | return -EIO; | ||
154 | } | ||
155 | |||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | static void __exit telephony_exit(void) | ||
160 | { | ||
161 | unregister_chrdev(PHONE_MAJOR, "telephony"); | ||
162 | } | ||
163 | |||
164 | module_init(telephony_init); | ||
165 | module_exit(telephony_exit); | ||
166 | |||
167 | MODULE_LICENSE("GPL"); | ||
168 | |||
169 | EXPORT_SYMBOL(phone_register_device); | ||
170 | EXPORT_SYMBOL(phone_unregister_device); | ||