diff options
Diffstat (limited to 'drivers/isdn/capi/kcapi_proc.c')
-rw-r--r-- | drivers/isdn/capi/kcapi_proc.c | 336 |
1 files changed, 336 insertions, 0 deletions
diff --git a/drivers/isdn/capi/kcapi_proc.c b/drivers/isdn/capi/kcapi_proc.c new file mode 100644 index 000000000000..16dc5418ff41 --- /dev/null +++ b/drivers/isdn/capi/kcapi_proc.c | |||
@@ -0,0 +1,336 @@ | |||
1 | /* | ||
2 | * Kernel CAPI 2.0 Module - /proc/capi handling | ||
3 | * | ||
4 | * Copyright 1999 by Carsten Paeth <calle@calle.de> | ||
5 | * Copyright 2002 by Kai Germaschewski <kai@germaschewski.name> | ||
6 | * | ||
7 | * This software may be used and distributed according to the terms | ||
8 | * of the GNU General Public License, incorporated herein by reference. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | |||
13 | #include "kcapi.h" | ||
14 | #include <linux/proc_fs.h> | ||
15 | #include <linux/seq_file.h> | ||
16 | #include <linux/init.h> | ||
17 | |||
18 | static char * | ||
19 | cardstate2str(unsigned short cardstate) | ||
20 | { | ||
21 | switch (cardstate) { | ||
22 | case CARD_DETECTED: return "detected"; | ||
23 | case CARD_LOADING: return "loading"; | ||
24 | case CARD_RUNNING: return "running"; | ||
25 | default: return "???"; | ||
26 | } | ||
27 | } | ||
28 | |||
29 | // /proc/capi | ||
30 | // =========================================================================== | ||
31 | |||
32 | // /proc/capi/controller: | ||
33 | // cnr driver cardstate name driverinfo | ||
34 | // /proc/capi/contrstats: | ||
35 | // cnr nrecvctlpkt nrecvdatapkt nsentctlpkt nsentdatapkt | ||
36 | // --------------------------------------------------------------------------- | ||
37 | |||
38 | static void *controller_start(struct seq_file *seq, loff_t *pos) | ||
39 | { | ||
40 | if (*pos < CAPI_MAXCONTR) | ||
41 | return &capi_cards[*pos]; | ||
42 | |||
43 | return NULL; | ||
44 | } | ||
45 | |||
46 | static void *controller_next(struct seq_file *seq, void *v, loff_t *pos) | ||
47 | { | ||
48 | ++*pos; | ||
49 | if (*pos < CAPI_MAXCONTR) | ||
50 | return &capi_cards[*pos]; | ||
51 | |||
52 | return NULL; | ||
53 | } | ||
54 | |||
55 | static void controller_stop(struct seq_file *seq, void *v) | ||
56 | { | ||
57 | } | ||
58 | |||
59 | static int controller_show(struct seq_file *seq, void *v) | ||
60 | { | ||
61 | struct capi_ctr *ctr = *(struct capi_ctr **) v; | ||
62 | |||
63 | if (!ctr) | ||
64 | return 0; | ||
65 | |||
66 | seq_printf(seq, "%d %-10s %-8s %-16s %s\n", | ||
67 | ctr->cnr, ctr->driver_name, | ||
68 | cardstate2str(ctr->cardstate), | ||
69 | ctr->name, | ||
70 | ctr->procinfo ? ctr->procinfo(ctr) : ""); | ||
71 | |||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | static int contrstats_show(struct seq_file *seq, void *v) | ||
76 | { | ||
77 | struct capi_ctr *ctr = *(struct capi_ctr **) v; | ||
78 | |||
79 | if (!ctr) | ||
80 | return 0; | ||
81 | |||
82 | seq_printf(seq, "%d %lu %lu %lu %lu\n", | ||
83 | ctr->cnr, | ||
84 | ctr->nrecvctlpkt, | ||
85 | ctr->nrecvdatapkt, | ||
86 | ctr->nsentctlpkt, | ||
87 | ctr->nsentdatapkt); | ||
88 | |||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | struct seq_operations seq_controller_ops = { | ||
93 | .start = controller_start, | ||
94 | .next = controller_next, | ||
95 | .stop = controller_stop, | ||
96 | .show = controller_show, | ||
97 | }; | ||
98 | |||
99 | struct seq_operations seq_contrstats_ops = { | ||
100 | .start = controller_start, | ||
101 | .next = controller_next, | ||
102 | .stop = controller_stop, | ||
103 | .show = contrstats_show, | ||
104 | }; | ||
105 | |||
106 | static int seq_controller_open(struct inode *inode, struct file *file) | ||
107 | { | ||
108 | return seq_open(file, &seq_controller_ops); | ||
109 | } | ||
110 | |||
111 | static int seq_contrstats_open(struct inode *inode, struct file *file) | ||
112 | { | ||
113 | return seq_open(file, &seq_contrstats_ops); | ||
114 | } | ||
115 | |||
116 | static struct file_operations proc_controller_ops = { | ||
117 | .open = seq_controller_open, | ||
118 | .read = seq_read, | ||
119 | .llseek = seq_lseek, | ||
120 | .release = seq_release, | ||
121 | }; | ||
122 | |||
123 | static struct file_operations proc_contrstats_ops = { | ||
124 | .open = seq_contrstats_open, | ||
125 | .read = seq_read, | ||
126 | .llseek = seq_lseek, | ||
127 | .release = seq_release, | ||
128 | }; | ||
129 | |||
130 | // /proc/capi/applications: | ||
131 | // applid l3cnt dblkcnt dblklen #ncci recvqueuelen | ||
132 | // /proc/capi/applstats: | ||
133 | // applid nrecvctlpkt nrecvdatapkt nsentctlpkt nsentdatapkt | ||
134 | // --------------------------------------------------------------------------- | ||
135 | |||
136 | static void * | ||
137 | applications_start(struct seq_file *seq, loff_t *pos) | ||
138 | { | ||
139 | if (*pos < CAPI_MAXAPPL) | ||
140 | return &capi_applications[*pos]; | ||
141 | |||
142 | return NULL; | ||
143 | } | ||
144 | |||
145 | static void * | ||
146 | applications_next(struct seq_file *seq, void *v, loff_t *pos) | ||
147 | { | ||
148 | ++*pos; | ||
149 | if (*pos < CAPI_MAXAPPL) | ||
150 | return &capi_applications[*pos]; | ||
151 | |||
152 | return NULL; | ||
153 | } | ||
154 | |||
155 | static void | ||
156 | applications_stop(struct seq_file *seq, void *v) | ||
157 | { | ||
158 | } | ||
159 | |||
160 | static int | ||
161 | applications_show(struct seq_file *seq, void *v) | ||
162 | { | ||
163 | struct capi20_appl *ap = *(struct capi20_appl **) v; | ||
164 | |||
165 | if (!ap) | ||
166 | return 0; | ||
167 | |||
168 | seq_printf(seq, "%u %d %d %d\n", | ||
169 | ap->applid, | ||
170 | ap->rparam.level3cnt, | ||
171 | ap->rparam.datablkcnt, | ||
172 | ap->rparam.datablklen); | ||
173 | |||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | static int | ||
178 | applstats_show(struct seq_file *seq, void *v) | ||
179 | { | ||
180 | struct capi20_appl *ap = *(struct capi20_appl **) v; | ||
181 | |||
182 | if (!ap) | ||
183 | return 0; | ||
184 | |||
185 | seq_printf(seq, "%u %lu %lu %lu %lu\n", | ||
186 | ap->applid, | ||
187 | ap->nrecvctlpkt, | ||
188 | ap->nrecvdatapkt, | ||
189 | ap->nsentctlpkt, | ||
190 | ap->nsentdatapkt); | ||
191 | |||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | struct seq_operations seq_applications_ops = { | ||
196 | .start = applications_start, | ||
197 | .next = applications_next, | ||
198 | .stop = applications_stop, | ||
199 | .show = applications_show, | ||
200 | }; | ||
201 | |||
202 | struct seq_operations seq_applstats_ops = { | ||
203 | .start = applications_start, | ||
204 | .next = applications_next, | ||
205 | .stop = applications_stop, | ||
206 | .show = applstats_show, | ||
207 | }; | ||
208 | |||
209 | static int | ||
210 | seq_applications_open(struct inode *inode, struct file *file) | ||
211 | { | ||
212 | return seq_open(file, &seq_applications_ops); | ||
213 | } | ||
214 | |||
215 | static int | ||
216 | seq_applstats_open(struct inode *inode, struct file *file) | ||
217 | { | ||
218 | return seq_open(file, &seq_applstats_ops); | ||
219 | } | ||
220 | |||
221 | static struct file_operations proc_applications_ops = { | ||
222 | .open = seq_applications_open, | ||
223 | .read = seq_read, | ||
224 | .llseek = seq_lseek, | ||
225 | .release = seq_release, | ||
226 | }; | ||
227 | |||
228 | static struct file_operations proc_applstats_ops = { | ||
229 | .open = seq_applstats_open, | ||
230 | .read = seq_read, | ||
231 | .llseek = seq_lseek, | ||
232 | .release = seq_release, | ||
233 | }; | ||
234 | |||
235 | static void | ||
236 | create_seq_entry(char *name, mode_t mode, struct file_operations *f) | ||
237 | { | ||
238 | struct proc_dir_entry *entry; | ||
239 | entry = create_proc_entry(name, mode, NULL); | ||
240 | if (entry) | ||
241 | entry->proc_fops = f; | ||
242 | } | ||
243 | |||
244 | // --------------------------------------------------------------------------- | ||
245 | |||
246 | |||
247 | static __inline__ struct capi_driver *capi_driver_get_idx(loff_t pos) | ||
248 | { | ||
249 | struct capi_driver *drv = NULL; | ||
250 | struct list_head *l; | ||
251 | loff_t i; | ||
252 | |||
253 | i = 0; | ||
254 | list_for_each(l, &capi_drivers) { | ||
255 | drv = list_entry(l, struct capi_driver, list); | ||
256 | if (i++ == pos) | ||
257 | return drv; | ||
258 | } | ||
259 | return NULL; | ||
260 | } | ||
261 | |||
262 | static void *capi_driver_start(struct seq_file *seq, loff_t *pos) | ||
263 | { | ||
264 | struct capi_driver *drv; | ||
265 | read_lock(&capi_drivers_list_lock); | ||
266 | drv = capi_driver_get_idx(*pos); | ||
267 | return drv; | ||
268 | } | ||
269 | |||
270 | static void *capi_driver_next(struct seq_file *seq, void *v, loff_t *pos) | ||
271 | { | ||
272 | struct capi_driver *drv = (struct capi_driver *)v; | ||
273 | ++*pos; | ||
274 | if (drv->list.next == &capi_drivers) return NULL; | ||
275 | return list_entry(drv->list.next, struct capi_driver, list); | ||
276 | } | ||
277 | |||
278 | static void capi_driver_stop(struct seq_file *seq, void *v) | ||
279 | { | ||
280 | read_unlock(&capi_drivers_list_lock); | ||
281 | } | ||
282 | |||
283 | static int capi_driver_show(struct seq_file *seq, void *v) | ||
284 | { | ||
285 | struct capi_driver *drv = (struct capi_driver *)v; | ||
286 | seq_printf(seq, "%-32s %s\n", drv->name, drv->revision); | ||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | struct seq_operations seq_capi_driver_ops = { | ||
291 | .start = capi_driver_start, | ||
292 | .next = capi_driver_next, | ||
293 | .stop = capi_driver_stop, | ||
294 | .show = capi_driver_show, | ||
295 | }; | ||
296 | |||
297 | static int | ||
298 | seq_capi_driver_open(struct inode *inode, struct file *file) | ||
299 | { | ||
300 | int err; | ||
301 | err = seq_open(file, &seq_capi_driver_ops); | ||
302 | return err; | ||
303 | } | ||
304 | |||
305 | static struct file_operations proc_driver_ops = { | ||
306 | .open = seq_capi_driver_open, | ||
307 | .read = seq_read, | ||
308 | .llseek = seq_lseek, | ||
309 | .release = seq_release, | ||
310 | }; | ||
311 | |||
312 | // --------------------------------------------------------------------------- | ||
313 | |||
314 | void __init | ||
315 | kcapi_proc_init(void) | ||
316 | { | ||
317 | proc_mkdir("capi", NULL); | ||
318 | proc_mkdir("capi/controllers", NULL); | ||
319 | create_seq_entry("capi/controller", 0, &proc_controller_ops); | ||
320 | create_seq_entry("capi/contrstats", 0, &proc_contrstats_ops); | ||
321 | create_seq_entry("capi/applications", 0, &proc_applications_ops); | ||
322 | create_seq_entry("capi/applstats", 0, &proc_applstats_ops); | ||
323 | create_seq_entry("capi/driver", 0, &proc_driver_ops); | ||
324 | } | ||
325 | |||
326 | void __exit | ||
327 | kcapi_proc_exit(void) | ||
328 | { | ||
329 | remove_proc_entry("capi/driver", NULL); | ||
330 | remove_proc_entry("capi/controller", NULL); | ||
331 | remove_proc_entry("capi/contrstats", NULL); | ||
332 | remove_proc_entry("capi/applications", NULL); | ||
333 | remove_proc_entry("capi/applstats", NULL); | ||
334 | remove_proc_entry("capi/controllers", NULL); | ||
335 | remove_proc_entry("capi", NULL); | ||
336 | } | ||