Merge branch 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelv...
[cascardo/linux.git] / drivers / staging / unisys / visorutil / easyproc.c
1 /* Copyright © 2010 - 2013 UNISYS CORPORATION
2  * All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or (at
7  * your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
12  * NON INFRINGEMENT.  See the GNU General Public License for more
13  * details.
14  */
15
16 /** @file *********************************************************************
17  *
18  *  Handle procfs-specific tasks.
19  *  Note that this file does not know about any module-specific things, nor
20  *  does it know anything about what information to reveal as part of the proc
21  *  entries.  The 2 functions that take care of displaying device and
22  *  driver specific information are passed as parameters to
23  *  visor_easyproc_InitDriver().
24  *
25  *      void show_device_info(struct seq_file *seq, void *p);
26  *      void show_driver_info(struct seq_file *seq);
27  *
28  *  The second parameter to show_device_info is actually a pointer to the
29  *  device-specific info to show.  It is the context that was originally
30  *  passed to visor_easyproc_InitDevice().
31  *
32  ******************************************************************************
33  */
34
35 #include <linux/proc_fs.h>
36
37 #include "uniklog.h"
38 #include "timskmod.h"
39 #include "easyproc.h"
40
41 #define MYDRVNAME "easyproc"
42
43
44
45 /*
46  *   /proc/<ProcId>                              ProcDir
47  *   /proc/<ProcId>/driver                       ProcDriverDir
48  *   /proc/<ProcId>/driver/diag                  ProcDriverDiagFile
49  *   /proc/<ProcId>/device                       ProcDeviceDir
50  *   /proc/<ProcId>/device/0                     procDevicexDir
51  *   /proc/<ProcId>/device/0/diag                procDevicexDiagFile
52  */
53
54
55 static ssize_t proc_write_device(struct file *file, const char __user *buffer,
56                                  size_t count, loff_t *ppos);
57 static ssize_t proc_write_driver(struct file *file, const char __user *buffer,
58                                  size_t count, loff_t *ppos);
59
60 static struct proc_dir_entry *
61         createProcDir(char *name, struct proc_dir_entry *parent)
62 {
63         struct proc_dir_entry *p = proc_mkdir_mode(name, S_IFDIR, parent);
64         if (p == NULL)
65                 ERRDRV("failed to create /proc directory %s", name);
66         return p;
67 }
68
69 static int seq_show_driver(struct seq_file *seq, void *offset);
70 static int proc_open_driver(struct inode *inode, struct file *file)
71 {
72         return single_open(file, seq_show_driver, PDE_DATA(inode));
73 }
74 static const struct file_operations proc_fops_driver = {
75         .open = proc_open_driver,
76         .read = seq_read,
77         .write = proc_write_driver,
78         .llseek = seq_lseek,
79         .release = single_release,
80 };
81
82 static int seq_show_device(struct seq_file *seq, void *offset);
83 static int seq_show_device_property(struct seq_file *seq, void *offset);
84 static int proc_open_device(struct inode *inode, struct file *file)
85 {
86         return single_open(file, seq_show_device, PDE_DATA(inode));
87 }
88 static const struct file_operations proc_fops_device = {
89         .open = proc_open_device,
90         .read = seq_read,
91         .write = proc_write_device,
92         .llseek = seq_lseek,
93         .release = single_release,
94 };
95 static int proc_open_device_property(struct inode *inode, struct file *file)
96 {
97         return single_open(file, seq_show_device_property, PDE_DATA(inode));
98 }
99 static const struct file_operations proc_fops_device_property = {
100         .open = proc_open_device_property,
101         .read = seq_read,
102         .llseek = seq_lseek,
103         .release = single_release,
104 };
105
106
107
108 void visor_easyproc_InitDriver(struct easyproc_driver_info *pdriver,
109                                char *procId,
110                                void (*show_driver_info)(struct seq_file *),
111                                void (*show_device_info)(struct seq_file *,
112                                                         void *))
113 {
114         memset(pdriver, 0, sizeof(struct easyproc_driver_info));
115         pdriver->ProcId = procId;
116         if (pdriver->ProcId == NULL)
117                 ERRDRV("ProcId cannot be NULL (trouble ahead)!");
118         pdriver->Show_driver_info = show_driver_info;
119         pdriver->Show_device_info = show_device_info;
120         if (pdriver->ProcDir == NULL)
121                 pdriver->ProcDir = createProcDir(pdriver->ProcId, NULL);
122         if ((pdriver->ProcDir != NULL) && (pdriver->ProcDriverDir == NULL))
123                 pdriver->ProcDriverDir = createProcDir("driver",
124                                                        pdriver->ProcDir);
125         if ((pdriver->ProcDir != NULL) && (pdriver->ProcDeviceDir == NULL))
126                 pdriver->ProcDeviceDir = createProcDir("device",
127                                                        pdriver->ProcDir);
128         if ((pdriver->ProcDriverDir != NULL) &&
129             (pdriver->ProcDriverDiagFile == NULL)) {
130                 pdriver->ProcDriverDiagFile =
131                         proc_create_data("diag", 0,
132                                          pdriver->ProcDriverDir,
133                                          &proc_fops_driver, pdriver);
134                 if (pdriver->ProcDriverDiagFile == NULL)
135                         ERRDRV("failed to register /proc/%s/driver/diag entry",
136                                pdriver->ProcId);
137         }
138 }
139 EXPORT_SYMBOL_GPL(visor_easyproc_InitDriver);
140
141
142
143 void visor_easyproc_InitDriverEx(struct easyproc_driver_info *pdriver,
144                                  char *procId,
145                                  void (*show_driver_info)(struct seq_file *),
146                                  void (*show_device_info)(struct seq_file *,
147                                                           void *),
148                                  void (*write_driver_info)(char *buf,
149                                                            size_t count,
150                                                            loff_t *ppos),
151                                  void (*write_device_info)(char *buf,
152                                                            size_t count,
153                                                            loff_t *ppos,
154                                                            void *p))
155 {
156         visor_easyproc_InitDriver(pdriver, procId,
157                                   show_driver_info, show_device_info);
158         pdriver->Write_driver_info = write_driver_info;
159         pdriver->Write_device_info = write_device_info;
160 }
161 EXPORT_SYMBOL_GPL(visor_easyproc_InitDriverEx);
162
163
164
165 void visor_easyproc_DeInitDriver(struct easyproc_driver_info *pdriver)
166 {
167         if (pdriver->ProcDriverDiagFile != NULL) {
168                 remove_proc_entry("diag", pdriver->ProcDriverDir);
169                 pdriver->ProcDriverDiagFile = NULL;
170         }
171         if (pdriver->ProcDriverDir != NULL) {
172                 remove_proc_entry("driver", pdriver->ProcDir);
173                 pdriver->ProcDriverDir = NULL;
174         }
175         if (pdriver->ProcDeviceDir != NULL) {
176                 remove_proc_entry("device", pdriver->ProcDir);
177                 pdriver->ProcDeviceDir = NULL;
178         }
179         if (pdriver->ProcDir != NULL) {
180                 remove_proc_entry(pdriver->ProcId, NULL);
181                 pdriver->ProcDir = NULL;
182         }
183         pdriver->ProcId = NULL;
184         pdriver->Show_driver_info = NULL;
185         pdriver->Show_device_info = NULL;
186         pdriver->Write_driver_info = NULL;
187         pdriver->Write_device_info = NULL;
188 }
189 EXPORT_SYMBOL_GPL(visor_easyproc_DeInitDriver);
190
191
192
193 void visor_easyproc_InitDevice(struct easyproc_driver_info *pdriver,
194                                struct easyproc_device_info *p, int devno,
195                                void *devdata)
196 {
197         if ((pdriver->ProcDeviceDir != NULL) && (p->procDevicexDir == NULL)) {
198                 char s[29];
199                 sprintf(s, "%d", devno);
200                 p->procDevicexDir = createProcDir(s, pdriver->ProcDeviceDir);
201                 p->devno = devno;
202         }
203         p->devdata = devdata;
204         p->pdriver = pdriver;
205         p->devno = devno;
206         if ((p->procDevicexDir != NULL) && (p->procDevicexDiagFile == NULL)) {
207                 p->procDevicexDiagFile =
208                         proc_create_data("diag", 0, p->procDevicexDir,
209                                          &proc_fops_device, p);
210                 if (p->procDevicexDiagFile == NULL)
211                         ERRDEVX(devno, "failed to register /proc/%s/device/%d/diag entry",
212                                 pdriver->ProcId, devno
213                                );
214         }
215         memset(&(p->device_property_info[0]), 0,
216                sizeof(p->device_property_info));
217 }
218 EXPORT_SYMBOL_GPL(visor_easyproc_InitDevice);
219
220
221
222 void visor_easyproc_CreateDeviceProperty(struct easyproc_device_info *p,
223                                          void (*show_property_info)
224                                          (struct seq_file *, void *),
225                                          char *property_name)
226 {
227         size_t i;
228         struct easyproc_device_property_info *px = NULL;
229
230         if (p->procDevicexDir == NULL) {
231                 ERRDRV("state error");
232                 return;
233         }
234         for (i = 0; i < ARRAY_SIZE(p->device_property_info); i++) {
235                 if (p->device_property_info[i].procEntry == NULL) {
236                         px = &(p->device_property_info[i]);
237                         break;
238                 }
239         }
240         if (!px) {
241                 ERRDEVX(p->devno, "too many device properties");
242                 return;
243         }
244         px->devdata = p->devdata;
245         px->pdriver = p->pdriver;
246         px->procEntry = proc_create_data(property_name, 0, p->procDevicexDir,
247                                          &proc_fops_device_property, px);
248         if (strlen(property_name)+1 > sizeof(px->property_name)) {
249                 ERRDEVX(p->devno, "device property name %s too long",
250                         property_name);
251                 return;
252         }
253         strcpy(px->property_name, property_name);
254         if (px->procEntry == NULL) {
255                 ERRDEVX(p->devno, "failed to register /proc/%s/device/%d/%s entry",
256                         p->pdriver->ProcId, p->devno, property_name
257                        );
258                 return;
259         }
260         px->show_device_property_info = show_property_info;
261 }
262 EXPORT_SYMBOL_GPL(visor_easyproc_CreateDeviceProperty);
263
264
265
266 void visor_easyproc_DeInitDevice(struct easyproc_driver_info *pdriver,
267                                  struct easyproc_device_info *p, int devno)
268 {
269         size_t i;
270         for (i = 0; i < ARRAY_SIZE(p->device_property_info); i++) {
271                 if (p->device_property_info[i].procEntry != NULL) {
272                         struct easyproc_device_property_info *px =
273                                 &(p->device_property_info[i]);
274                         remove_proc_entry(px->property_name, p->procDevicexDir);
275                         px->procEntry = NULL;
276                 }
277         }
278         if (p->procDevicexDiagFile != NULL) {
279                 remove_proc_entry("diag", p->procDevicexDir);
280                 p->procDevicexDiagFile = NULL;
281         }
282         if (p->procDevicexDir != NULL) {
283                 char s[29];
284                 sprintf(s, "%d", devno);
285                 remove_proc_entry(s, pdriver->ProcDeviceDir);
286                 p->procDevicexDir = NULL;
287         }
288         p->devdata = NULL;
289         p->pdriver = NULL;
290 }
291 EXPORT_SYMBOL_GPL(visor_easyproc_DeInitDevice);
292
293
294
295 static int seq_show_driver(struct seq_file *seq, void *offset)
296 {
297         struct easyproc_driver_info *p =
298                 (struct easyproc_driver_info *)(seq->private);
299         if (!p)
300                 return 0;
301         (*(p->Show_driver_info))(seq);
302         return 0;
303 }
304
305
306
307 static int seq_show_device(struct seq_file *seq, void *offset)
308 {
309         struct easyproc_device_info *p =
310                 (struct easyproc_device_info *)(seq->private);
311         if ((!p) || (!(p->pdriver)))
312                 return 0;
313         (*(p->pdriver->Show_device_info))(seq, p->devdata);
314         return 0;
315 }
316
317
318
319 static int seq_show_device_property(struct seq_file *seq, void *offset)
320 {
321         struct easyproc_device_property_info *p =
322                 (struct easyproc_device_property_info *)(seq->private);
323         if ((!p) || (!(p->show_device_property_info)))
324                 return 0;
325         (*(p->show_device_property_info))(seq, p->devdata);
326         return 0;
327 }
328
329
330
331 static ssize_t proc_write_driver(struct file *file, const char __user *buffer,
332                                  size_t count, loff_t *ppos)
333 {
334         struct seq_file *seq = (struct seq_file *)file->private_data;
335         struct easyproc_driver_info *p = NULL;
336         char local_buf[256];
337         if (seq == NULL)
338                 return 0;
339         p = (struct easyproc_driver_info *)(seq->private);
340         if ((!p) || (!(p->Write_driver_info)))
341                 return 0;
342         if (count >= sizeof(local_buf))
343                 return -ENOMEM;
344         if (copy_from_user(local_buf, buffer, count))
345                 return -EFAULT;
346         local_buf[count] = '\0';  /* be friendly */
347         (*(p->Write_driver_info))(local_buf, count, ppos);
348         return count;
349 }
350
351
352
353 static ssize_t proc_write_device(struct file *file, const char __user *buffer,
354                                  size_t count, loff_t *ppos)
355 {
356         struct seq_file *seq = (struct seq_file *)file->private_data;
357         struct easyproc_device_info *p = NULL;
358         char local_buf[256];
359         if (seq == NULL)
360                 return 0;
361         p = (struct easyproc_device_info *)(seq->private);
362         if ((!p) || (!(p->pdriver)) || (!(p->pdriver->Write_device_info)))
363                 return 0;
364         if (count >= sizeof(local_buf))
365                 return -ENOMEM;
366         if (copy_from_user(local_buf, buffer, count))
367                 return -EFAULT;
368         local_buf[count] = '\0';  /* be friendly */
369         (*(p->pdriver->Write_device_info))(local_buf, count, ppos, p->devdata);
370         return count;
371 }