Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
[cascardo/linux.git] / drivers / staging / unisys / visorutil / procobjecttree.c
1 /* procobjecttree.c
2  *
3  * Copyright © 2010 - 2013 UNISYS CORPORATION
4  * All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or (at
9  * your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
14  * NON INFRINGEMENT.  See the GNU General Public License for more
15  * details.
16  */
17
18 #include "procobjecttree.h"
19
20 #define MYDRVNAME "procobjecttree"
21
22
23
24 /** This is context info that we stash in each /proc file entry, which we
25  *  need in order to call the callback function that supplies the /proc read
26  *  info for that file.
27  */
28 typedef struct {
29         void (*show_property)(struct seq_file *, void *, int);
30         MYPROCOBJECT *procObject;
31         int propertyIndex;
32
33 } PROCDIRENTRYCONTEXT;
34
35 /** This describes the attributes of a tree rooted at
36  *  <procDirRoot>/<name[0]>/<name[1]>/...
37  *  Properties for each object of this type will be located under
38  *  <procDirRoot>/<name[0]>/<name[1]>/.../<objectName>/<propertyName>.
39  */
40 struct MYPROCTYPE_Tag {
41         const char **name;  /**< node names for this type, ending with NULL */
42         int nNames;         /**< num of node names in <name> */
43
44         /** root dir for this type tree in /proc */
45         struct proc_dir_entry *procDirRoot;
46
47         struct proc_dir_entry **procDirs;  /**< for each node in <name> */
48
49         /** bottom dir where objects will be rooted; i.e., this is
50          *  <procDirRoot>/<name[0]>/<name[1]>/.../, which is the same as the
51          *  last entry in the <procDirs> array. */
52         struct proc_dir_entry *procDir;
53
54         /** name for each property that objects of this type can have */
55         const char **propertyNames;
56
57         int nProperties;       /**< num of names in <propertyNames> */
58
59         /** Call this, passing MYPROCOBJECT.context and the property index
60          *  whenever someone reads the proc entry */
61         void (*show_property)(struct seq_file *, void *, int);
62 };
63
64
65
66 struct MYPROCOBJECT_Tag {
67         MYPROCTYPE *type;
68
69         /** This is the name of the dir node in /proc under which the
70          *  properties of this object will appear as files. */
71         char *name;
72
73         int namesize;   /**< number of bytes allocated for name */
74         void *context;  /**< passed to MYPROCTYPE.show_property */
75
76         /** <type.procDirRoot>/<type.name[0]>/<type.name[1]>/.../<name> */
77         struct proc_dir_entry *procDir;
78
79         /** a proc dir entry for each of the properties of the object;
80          *  properties are identified in MYPROCTYPE.propertyNames, so each of
81          *  the <procDirProperties> describes a single file like
82          *  <type.procDirRoot>/<type.name[0]>/<type.name[1]>/...
83          *           /<name>/<propertyName>
84          */
85         struct proc_dir_entry **procDirProperties;
86
87         /** this is a holding area for the context information that is needed
88          *  to run the /proc callback function */
89         PROCDIRENTRYCONTEXT *procDirPropertyContexts;
90 };
91
92
93
94 static struct proc_dir_entry *
95 createProcDir(const char *name, struct proc_dir_entry *parent)
96 {
97         struct proc_dir_entry *p = proc_mkdir_mode(name, S_IFDIR, parent);
98         if (p == NULL)
99                 ERRDRV("failed to create /proc directory %s", name);
100         return p;
101 }
102
103 static struct proc_dir_entry *
104 createProcFile(const char *name, struct proc_dir_entry *parent,
105                const struct file_operations *fops, void *data)
106 {
107         struct proc_dir_entry *p = proc_create_data(name, 0, parent,
108                                                     fops, data);
109         if (p == NULL)
110                 ERRDRV("failed to create /proc file %s", name);
111         return p;
112 }
113
114 static int seq_show(struct seq_file *seq, void *offset);
115 static int proc_open(struct inode *inode, struct file *file)
116 {
117         return single_open(file, seq_show, PDE_DATA(inode));
118 }
119
120 static const struct file_operations proc_fops = {
121         .open = proc_open,
122         .read = seq_read,
123         .llseek = seq_lseek,
124         .release = single_release,
125 };
126
127
128
129 MYPROCTYPE *visor_proc_CreateType(struct proc_dir_entry *procDirRoot,
130                                   const char **name,
131                                   const char **propertyNames,
132                                   void (*show_property)(struct seq_file *,
133                                                         void *, int))
134 {
135         int i = 0;
136         MYPROCTYPE *rc = NULL, *type = NULL;
137         struct proc_dir_entry *parent = NULL;
138
139         if (procDirRoot == NULL) {
140                 ERRDRV("procDirRoot cannot be NULL!\n");
141                 goto Away;
142         }
143         if (name == NULL || name[0] == NULL) {
144                 ERRDRV("name must contain at least 1 node name!\n");
145                 goto Away;
146         }
147         type = kzalloc(sizeof(MYPROCTYPE), GFP_KERNEL | __GFP_NORETRY);
148         if (type == NULL) {
149                 ERRDRV("out of memory\n");
150                 goto Away;
151         }
152         type->name = name;
153         type->propertyNames = propertyNames;
154         type->nProperties = 0;
155         type->nNames = 0;
156         type->show_property = show_property;
157         type->procDirRoot = procDirRoot;
158         if (type->propertyNames != NULL)
159                 while (type->propertyNames[type->nProperties] != NULL)
160                         type->nProperties++;
161         while (type->name[type->nNames] != NULL)
162                 type->nNames++;
163         type->procDirs = kzalloc((type->nNames + 1) *
164                                  sizeof(struct proc_dir_entry *),
165                                  GFP_KERNEL | __GFP_NORETRY);
166         if (type->procDirs == NULL) {
167                 ERRDRV("out of memory\n");
168                 goto Away;
169         }
170         parent = procDirRoot;
171         for (i = 0; i < type->nNames; i++) {
172                 type->procDirs[i] = createProcDir(type->name[i], parent);
173                 if (type->procDirs[i] == NULL) {
174                         rc = NULL;
175                         goto Away;
176                 }
177                 parent = type->procDirs[i];
178         }
179         type->procDir = type->procDirs[type->nNames-1];
180         rc = type;
181 Away:
182         if (rc == NULL) {
183                 if (type != NULL) {
184                         visor_proc_DestroyType(type);
185                         type = NULL;
186                 }
187         }
188         return rc;
189 }
190 EXPORT_SYMBOL_GPL(visor_proc_CreateType);
191
192
193
194 void visor_proc_DestroyType(MYPROCTYPE *type)
195 {
196         if (type == NULL)
197                 return;
198         if (type->procDirs != NULL) {
199                 int i = type->nNames-1;
200                 while (i >= 0) {
201                         if (type->procDirs[i] != NULL) {
202                                 struct proc_dir_entry *parent = NULL;
203                                 if (i == 0)
204                                         parent = type->procDirRoot;
205                                 else
206                                         parent = type->procDirs[i-1];
207                                 remove_proc_entry(type->name[i], parent);
208                         }
209                         i--;
210                 }
211                 kfree(type->procDirs);
212                 type->procDirs = NULL;
213         }
214         kfree(type);
215 }
216 EXPORT_SYMBOL_GPL(visor_proc_DestroyType);
217
218
219
220 MYPROCOBJECT *visor_proc_CreateObject(MYPROCTYPE *type,
221                                       const char *name, void *context)
222 {
223         MYPROCOBJECT *obj = NULL, *rc = NULL;
224         int i = 0;
225
226         if (type == NULL) {
227                 ERRDRV("type cannot be NULL\n");
228                 goto Away;
229         }
230         obj = kzalloc(sizeof(MYPROCOBJECT), GFP_KERNEL | __GFP_NORETRY);
231         if (obj == NULL) {
232                 ERRDRV("out of memory\n");
233                 goto Away;
234         }
235         obj->type = type;
236         obj->context = context;
237         if (name == NULL) {
238                 obj->name = NULL;
239                 obj->procDir = type->procDir;
240         } else {
241                 obj->namesize = strlen(name)+1;
242                 obj->name = kmalloc(obj->namesize, GFP_KERNEL | __GFP_NORETRY);
243                 if (obj->name == NULL) {
244                         obj->namesize = 0;
245                         ERRDRV("out of memory\n");
246                         goto Away;
247                 }
248                 strcpy(obj->name, name);
249                 obj->procDir = createProcDir(obj->name, type->procDir);
250                 if (obj->procDir == NULL) {
251                         goto Away;
252                 }
253         }
254         obj->procDirPropertyContexts =
255                 kzalloc((type->nProperties + 1) * sizeof(PROCDIRENTRYCONTEXT),
256                         GFP_KERNEL | __GFP_NORETRY);
257         if (obj->procDirPropertyContexts == NULL) {
258                 ERRDRV("out of memory\n");
259                 goto Away;
260         }
261         obj->procDirProperties =
262                 kzalloc((type->nProperties + 1) * sizeof(struct proc_dir_entry *),
263                         GFP_KERNEL | __GFP_NORETRY);
264         if (obj->procDirProperties == NULL) {
265                 ERRDRV("out of memory\n");
266                 goto Away;
267         }
268         for (i = 0; i < type->nProperties; i++) {
269                 obj->procDirPropertyContexts[i].procObject = obj;
270                 obj->procDirPropertyContexts[i].propertyIndex = i;
271                 obj->procDirPropertyContexts[i].show_property =
272                         type->show_property;
273                 if (type->propertyNames[i][0] != '\0') {
274                         /* only create properties that have names */
275                         obj->procDirProperties[i] =
276                                 createProcFile(type->propertyNames[i],
277                                                obj->procDir, &proc_fops,
278                                                &obj->procDirPropertyContexts[i]);
279                         if (obj->procDirProperties[i] == NULL) {
280                                 rc = NULL;
281                                 goto Away;
282                         }
283                 }
284         }
285         rc = obj;
286 Away:
287         if (rc == NULL) {
288                 if (obj != NULL) {
289                         visor_proc_DestroyObject(obj);
290                         obj = NULL;
291                 }
292         }
293         return rc;
294 }
295 EXPORT_SYMBOL_GPL(visor_proc_CreateObject);
296
297
298
299 void visor_proc_DestroyObject(MYPROCOBJECT *obj)
300 {
301         MYPROCTYPE *type = NULL;
302         if (obj == NULL)
303                 return;
304         type = obj->type;
305         if (type == NULL)
306                 return;
307         if (obj->procDirProperties != NULL) {
308                 int i = 0;
309                 for (i = 0; i < type->nProperties; i++) {
310                         if (obj->procDirProperties[i] != NULL) {
311                                 remove_proc_entry(type->propertyNames[i],
312                                                   obj->procDir);
313                                 obj->procDirProperties[i] = NULL;
314                         }
315                 }
316                 kfree(obj->procDirProperties);
317                 obj->procDirProperties = NULL;
318         }
319         if (obj->procDirPropertyContexts != NULL) {
320                 kfree(obj->procDirPropertyContexts);
321                 obj->procDirPropertyContexts = NULL;
322         }
323         if (obj->procDir != NULL) {
324                 if (obj->name != NULL)
325                         remove_proc_entry(obj->name, type->procDir);
326                 obj->procDir = NULL;
327         }
328         if (obj->name != NULL) {
329                 kfree(obj->name);
330                 obj->name = NULL;
331         }
332         kfree(obj);
333 }
334 EXPORT_SYMBOL_GPL(visor_proc_DestroyObject);
335
336
337
338 static int seq_show(struct seq_file *seq, void *offset)
339 {
340         PROCDIRENTRYCONTEXT *ctx = (PROCDIRENTRYCONTEXT *)(seq->private);
341         if (ctx == NULL) {
342                 ERRDRV("I don't have a freakin' clue...");
343                 return 0;
344         }
345         (*ctx->show_property)(seq, ctx->procObject->context,
346                               ctx->propertyIndex);
347         return 0;
348 }