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 
state2str(unsigned short state)18 static char *state2str(unsigned short state)
19 {
20 	switch (state) {
21 	case CAPI_CTR_DETECTED:	return "detected";
22 	case CAPI_CTR_LOADING:	return "loading";
23 	case CAPI_CTR_RUNNING:	return "running";
24 	default:	        return "???";
25 	}
26 }
27 
28 // /proc/capi
29 // ===========================================================================
30 
31 // /proc/capi/controller:
32 //      cnr driver cardstate name driverinfo
33 // /proc/capi/contrstats:
34 //      cnr nrecvctlpkt nrecvdatapkt nsentctlpkt nsentdatapkt
35 // ---------------------------------------------------------------------------
36 
controller_start(struct seq_file * seq,loff_t * pos)37 static void *controller_start(struct seq_file *seq, loff_t *pos)
38 	__acquires(capi_controller_lock)
39 {
40 	mutex_lock(&capi_controller_lock);
41 
42 	if (*pos < CAPI_MAXCONTR)
43 		return &capi_controller[*pos];
44 
45 	return NULL;
46 }
47 
controller_next(struct seq_file * seq,void * v,loff_t * pos)48 static void *controller_next(struct seq_file *seq, void *v, loff_t *pos)
49 {
50 	++*pos;
51 	if (*pos < CAPI_MAXCONTR)
52 		return &capi_controller[*pos];
53 
54 	return NULL;
55 }
56 
controller_stop(struct seq_file * seq,void * v)57 static void controller_stop(struct seq_file *seq, void *v)
58 	__releases(capi_controller_lock)
59 {
60 	mutex_unlock(&capi_controller_lock);
61 }
62 
controller_show(struct seq_file * seq,void * v)63 static int controller_show(struct seq_file *seq, void *v)
64 {
65 	struct capi_ctr *ctr = *(struct capi_ctr **) v;
66 
67 	if (!ctr)
68 		return 0;
69 
70 	seq_printf(seq, "%d %-10s %-8s %-16s %s\n",
71 		   ctr->cnr, ctr->driver_name,
72 		   state2str(ctr->state),
73 		   ctr->name,
74 		   ctr->procinfo ?  ctr->procinfo(ctr) : "");
75 
76 	return 0;
77 }
78 
contrstats_show(struct seq_file * seq,void * v)79 static int contrstats_show(struct seq_file *seq, void *v)
80 {
81 	struct capi_ctr *ctr = *(struct capi_ctr **) v;
82 
83 	if (!ctr)
84 		return 0;
85 
86 	seq_printf(seq, "%d %lu %lu %lu %lu\n",
87 		   ctr->cnr,
88 		   ctr->nrecvctlpkt,
89 		   ctr->nrecvdatapkt,
90 		   ctr->nsentctlpkt,
91 		   ctr->nsentdatapkt);
92 
93 	return 0;
94 }
95 
96 static const struct seq_operations seq_controller_ops = {
97 	.start	= controller_start,
98 	.next	= controller_next,
99 	.stop	= controller_stop,
100 	.show	= controller_show,
101 };
102 
103 static const struct seq_operations seq_contrstats_ops = {
104 	.start	= controller_start,
105 	.next	= controller_next,
106 	.stop	= controller_stop,
107 	.show	= contrstats_show,
108 };
109 
seq_controller_open(struct inode * inode,struct file * file)110 static int seq_controller_open(struct inode *inode, struct file *file)
111 {
112 	return seq_open(file, &seq_controller_ops);
113 }
114 
seq_contrstats_open(struct inode * inode,struct file * file)115 static int seq_contrstats_open(struct inode *inode, struct file *file)
116 {
117 	return seq_open(file, &seq_contrstats_ops);
118 }
119 
120 static const struct file_operations proc_controller_ops = {
121 	.owner		= THIS_MODULE,
122 	.open		= seq_controller_open,
123 	.read		= seq_read,
124 	.llseek		= seq_lseek,
125 	.release	= seq_release,
126 };
127 
128 static const struct file_operations proc_contrstats_ops = {
129 	.owner		= THIS_MODULE,
130 	.open		= seq_contrstats_open,
131 	.read		= seq_read,
132 	.llseek		= seq_lseek,
133 	.release	= seq_release,
134 };
135 
136 // /proc/capi/applications:
137 //      applid l3cnt dblkcnt dblklen #ncci recvqueuelen
138 // /proc/capi/applstats:
139 //      applid nrecvctlpkt nrecvdatapkt nsentctlpkt nsentdatapkt
140 // ---------------------------------------------------------------------------
141 
applications_start(struct seq_file * seq,loff_t * pos)142 static void *applications_start(struct seq_file *seq, loff_t *pos)
143 	__acquires(capi_controller_lock)
144 {
145 	mutex_lock(&capi_controller_lock);
146 
147 	if (*pos < CAPI_MAXAPPL)
148 		return &capi_applications[*pos];
149 
150 	return NULL;
151 }
152 
153 static void *
applications_next(struct seq_file * seq,void * v,loff_t * pos)154 applications_next(struct seq_file *seq, void *v, loff_t *pos)
155 {
156 	++*pos;
157 	if (*pos < CAPI_MAXAPPL)
158 		return &capi_applications[*pos];
159 
160 	return NULL;
161 }
162 
applications_stop(struct seq_file * seq,void * v)163 static void applications_stop(struct seq_file *seq, void *v)
164 	__releases(capi_controller_lock)
165 {
166 	mutex_unlock(&capi_controller_lock);
167 }
168 
169 static int
applications_show(struct seq_file * seq,void * v)170 applications_show(struct seq_file *seq, void *v)
171 {
172 	struct capi20_appl *ap = *(struct capi20_appl **) v;
173 
174 	if (!ap)
175 		return 0;
176 
177 	seq_printf(seq, "%u %d %d %d\n",
178 		   ap->applid,
179 		   ap->rparam.level3cnt,
180 		   ap->rparam.datablkcnt,
181 		   ap->rparam.datablklen);
182 
183 	return 0;
184 }
185 
186 static int
applstats_show(struct seq_file * seq,void * v)187 applstats_show(struct seq_file *seq, void *v)
188 {
189 	struct capi20_appl *ap = *(struct capi20_appl **) v;
190 
191 	if (!ap)
192 		return 0;
193 
194 	seq_printf(seq, "%u %lu %lu %lu %lu\n",
195 		   ap->applid,
196 		   ap->nrecvctlpkt,
197 		   ap->nrecvdatapkt,
198 		   ap->nsentctlpkt,
199 		   ap->nsentdatapkt);
200 
201 	return 0;
202 }
203 
204 static const struct seq_operations seq_applications_ops = {
205 	.start	= applications_start,
206 	.next	= applications_next,
207 	.stop	= applications_stop,
208 	.show	= applications_show,
209 };
210 
211 static const struct seq_operations seq_applstats_ops = {
212 	.start	= applications_start,
213 	.next	= applications_next,
214 	.stop	= applications_stop,
215 	.show	= applstats_show,
216 };
217 
218 static int
seq_applications_open(struct inode * inode,struct file * file)219 seq_applications_open(struct inode *inode, struct file *file)
220 {
221 	return seq_open(file, &seq_applications_ops);
222 }
223 
224 static int
seq_applstats_open(struct inode * inode,struct file * file)225 seq_applstats_open(struct inode *inode, struct file *file)
226 {
227 	return seq_open(file, &seq_applstats_ops);
228 }
229 
230 static const struct file_operations proc_applications_ops = {
231 	.owner		= THIS_MODULE,
232 	.open		= seq_applications_open,
233 	.read		= seq_read,
234 	.llseek		= seq_lseek,
235 	.release	= seq_release,
236 };
237 
238 static const struct file_operations proc_applstats_ops = {
239 	.owner		= THIS_MODULE,
240 	.open		= seq_applstats_open,
241 	.read		= seq_read,
242 	.llseek		= seq_lseek,
243 	.release	= seq_release,
244 };
245 
246 // ---------------------------------------------------------------------------
247 
capi_driver_start(struct seq_file * seq,loff_t * pos)248 static void *capi_driver_start(struct seq_file *seq, loff_t *pos)
249 	__acquires(&capi_drivers_lock)
250 {
251 	mutex_lock(&capi_drivers_lock);
252 	return seq_list_start(&capi_drivers, *pos);
253 }
254 
capi_driver_next(struct seq_file * seq,void * v,loff_t * pos)255 static void *capi_driver_next(struct seq_file *seq, void *v, loff_t *pos)
256 {
257 	return seq_list_next(v, &capi_drivers, pos);
258 }
259 
capi_driver_stop(struct seq_file * seq,void * v)260 static void capi_driver_stop(struct seq_file *seq, void *v)
261 	__releases(&capi_drivers_lock)
262 {
263 	mutex_unlock(&capi_drivers_lock);
264 }
265 
capi_driver_show(struct seq_file * seq,void * v)266 static int capi_driver_show(struct seq_file *seq, void *v)
267 {
268 	struct capi_driver *drv = list_entry(v, struct capi_driver, list);
269 
270 	seq_printf(seq, "%-32s %s\n", drv->name, drv->revision);
271 	return 0;
272 }
273 
274 static const struct seq_operations seq_capi_driver_ops = {
275 	.start	= capi_driver_start,
276 	.next	= capi_driver_next,
277 	.stop	= capi_driver_stop,
278 	.show	= capi_driver_show,
279 };
280 
281 static int
seq_capi_driver_open(struct inode * inode,struct file * file)282 seq_capi_driver_open(struct inode *inode, struct file *file)
283 {
284 	int err;
285 	err = seq_open(file, &seq_capi_driver_ops);
286 	return err;
287 }
288 
289 static const struct file_operations proc_driver_ops = {
290 	.owner		= THIS_MODULE,
291 	.open		= seq_capi_driver_open,
292 	.read		= seq_read,
293 	.llseek		= seq_lseek,
294 	.release	= seq_release,
295 };
296 
297 // ---------------------------------------------------------------------------
298 
299 void __init
kcapi_proc_init(void)300 kcapi_proc_init(void)
301 {
302 	proc_mkdir("capi",             NULL);
303 	proc_mkdir("capi/controllers", NULL);
304 	proc_create("capi/controller",   0, NULL, &proc_controller_ops);
305 	proc_create("capi/contrstats",   0, NULL, &proc_contrstats_ops);
306 	proc_create("capi/applications", 0, NULL, &proc_applications_ops);
307 	proc_create("capi/applstats",    0, NULL, &proc_applstats_ops);
308 	proc_create("capi/driver",       0, NULL, &proc_driver_ops);
309 }
310 
311 void __exit
kcapi_proc_exit(void)312 kcapi_proc_exit(void)
313 {
314 	remove_proc_entry("capi/driver",       NULL);
315 	remove_proc_entry("capi/controller",   NULL);
316 	remove_proc_entry("capi/contrstats",   NULL);
317 	remove_proc_entry("capi/applications", NULL);
318 	remove_proc_entry("capi/applstats",    NULL);
319 	remove_proc_entry("capi/controllers",  NULL);
320 	remove_proc_entry("capi",              NULL);
321 }
322