]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/unisys/visorutil/easyproc.c
Merge remote-tracking branch 'usb-gadget/next'
[karo-tx-linux.git] / drivers / staging / unisys / visorutil / easyproc.c
1 /* Copyright (C) 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
65         if (p == NULL)
66                 ERRDRV("failed to create /proc directory %s", name);
67         return p;
68 }
69
70 static int seq_show_driver(struct seq_file *seq, void *offset);
71 static int proc_open_driver(struct inode *inode, struct file *file)
72 {
73         return single_open(file, seq_show_driver, PDE_DATA(inode));
74 }
75 static const struct file_operations proc_fops_driver = {
76         .open = proc_open_driver,
77         .read = seq_read,
78         .write = proc_write_driver,
79         .llseek = seq_lseek,
80         .release = single_release,
81 };
82
83 static int seq_show_device(struct seq_file *seq, void *offset);
84 static int seq_show_device_property(struct seq_file *seq, void *offset);
85 static int proc_open_device(struct inode *inode, struct file *file)
86 {
87         return single_open(file, seq_show_device, PDE_DATA(inode));
88 }
89 static const struct file_operations proc_fops_device = {
90         .open = proc_open_device,
91         .read = seq_read,
92         .write = proc_write_device,
93         .llseek = seq_lseek,
94         .release = single_release,
95 };
96 static int proc_open_device_property(struct inode *inode, struct file *file)
97 {
98         return single_open(file, seq_show_device_property, PDE_DATA(inode));
99 }
100 static const struct file_operations proc_fops_device_property = {
101         .open = proc_open_device_property,
102         .read = seq_read,
103         .llseek = seq_lseek,
104         .release = single_release,
105 };
106
107
108
109 void visor_easyproc_InitDriver(struct easyproc_driver_info *pdriver,
110                                char *procId,
111                                void (*show_driver_info)(struct seq_file *),
112                                void (*show_device_info)(struct seq_file *,
113                                                         void *))
114 {
115         memset(pdriver, 0, sizeof(struct easyproc_driver_info));
116         pdriver->ProcId = procId;
117         if (pdriver->ProcId == NULL)
118                 ERRDRV("ProcId cannot be NULL (trouble ahead)!");
119         pdriver->Show_driver_info = show_driver_info;
120         pdriver->Show_device_info = show_device_info;
121         if (pdriver->ProcDir == NULL)
122                 pdriver->ProcDir = createProcDir(pdriver->ProcId, NULL);
123         if ((pdriver->ProcDir != NULL) && (pdriver->ProcDriverDir == NULL))
124                 pdriver->ProcDriverDir = createProcDir("driver",
125                                                        pdriver->ProcDir);
126         if ((pdriver->ProcDir != NULL) && (pdriver->ProcDeviceDir == NULL))
127                 pdriver->ProcDeviceDir = createProcDir("device",
128                                                        pdriver->ProcDir);
129         if ((pdriver->ProcDriverDir != NULL) &&
130             (pdriver->ProcDriverDiagFile == NULL)) {
131                 pdriver->ProcDriverDiagFile =
132                         proc_create_data("diag", 0,
133                                          pdriver->ProcDriverDir,
134                                          &proc_fops_driver, pdriver);
135                 if (pdriver->ProcDriverDiagFile == NULL)
136                         ERRDRV("failed to register /proc/%s/driver/diag entry",
137                                pdriver->ProcId);
138         }
139 }
140 EXPORT_SYMBOL_GPL(visor_easyproc_InitDriver);
141
142
143
144 void visor_easyproc_InitDriverEx(struct easyproc_driver_info *pdriver,
145                                  char *procId,
146                                  void (*show_driver_info)(struct seq_file *),
147                                  void (*show_device_info)(struct seq_file *,
148                                                           void *),
149                                  void (*write_driver_info)(char *buf,
150                                                            size_t count,
151                                                            loff_t *ppos),
152                                  void (*write_device_info)(char *buf,
153                                                            size_t count,
154                                                            loff_t *ppos,
155                                                            void *p))
156 {
157         visor_easyproc_InitDriver(pdriver, procId,
158                                   show_driver_info, show_device_info);
159         pdriver->Write_driver_info = write_driver_info;
160         pdriver->Write_device_info = write_device_info;
161 }
162 EXPORT_SYMBOL_GPL(visor_easyproc_InitDriverEx);
163
164
165
166 void visor_easyproc_DeInitDriver(struct easyproc_driver_info *pdriver)
167 {
168         if (pdriver->ProcDriverDiagFile != NULL) {
169                 remove_proc_entry("diag", pdriver->ProcDriverDir);
170                 pdriver->ProcDriverDiagFile = NULL;
171         }
172         if (pdriver->ProcDriverDir != NULL) {
173                 remove_proc_entry("driver", pdriver->ProcDir);
174                 pdriver->ProcDriverDir = NULL;
175         }
176         if (pdriver->ProcDeviceDir != NULL) {
177                 remove_proc_entry("device", pdriver->ProcDir);
178                 pdriver->ProcDeviceDir = NULL;
179         }
180         if (pdriver->ProcDir != NULL) {
181                 remove_proc_entry(pdriver->ProcId, NULL);
182                 pdriver->ProcDir = NULL;
183         }
184         pdriver->ProcId = NULL;
185         pdriver->Show_driver_info = NULL;
186         pdriver->Show_device_info = NULL;
187         pdriver->Write_driver_info = NULL;
188         pdriver->Write_device_info = NULL;
189 }
190 EXPORT_SYMBOL_GPL(visor_easyproc_DeInitDriver);
191
192
193
194 void visor_easyproc_InitDevice(struct easyproc_driver_info *pdriver,
195                                struct easyproc_device_info *p, int devno,
196                                void *devdata)
197 {
198         if ((pdriver->ProcDeviceDir != NULL) && (p->procDevicexDir == NULL)) {
199                 char s[29];
200
201                 sprintf(s, "%d", devno);
202                 p->procDevicexDir = createProcDir(s, pdriver->ProcDeviceDir);
203                 p->devno = devno;
204         }
205         p->devdata = devdata;
206         p->pdriver = pdriver;
207         p->devno = devno;
208         if ((p->procDevicexDir != NULL) && (p->procDevicexDiagFile == NULL)) {
209                 p->procDevicexDiagFile =
210                         proc_create_data("diag", 0, p->procDevicexDir,
211                                          &proc_fops_device, p);
212                 if (p->procDevicexDiagFile == NULL)
213                         ERRDEVX(devno, "failed to register /proc/%s/device/%d/diag entry",
214                                 pdriver->ProcId, devno
215                                );
216         }
217         memset(&(p->device_property_info[0]), 0,
218                sizeof(p->device_property_info));
219 }
220 EXPORT_SYMBOL_GPL(visor_easyproc_InitDevice);
221
222
223
224 void visor_easyproc_CreateDeviceProperty(struct easyproc_device_info *p,
225                                          void (*show_property_info)
226                                          (struct seq_file *, void *),
227                                          char *property_name)
228 {
229         size_t i;
230         struct easyproc_device_property_info *px = NULL;
231
232         if (p->procDevicexDir == NULL) {
233                 ERRDRV("state error");
234                 return;
235         }
236         for (i = 0; i < ARRAY_SIZE(p->device_property_info); i++) {
237                 if (p->device_property_info[i].procEntry == NULL) {
238                         px = &(p->device_property_info[i]);
239                         break;
240                 }
241         }
242         if (!px) {
243                 ERRDEVX(p->devno, "too many device properties");
244                 return;
245         }
246         px->devdata = p->devdata;
247         px->pdriver = p->pdriver;
248         px->procEntry = proc_create_data(property_name, 0, p->procDevicexDir,
249                                          &proc_fops_device_property, px);
250         if (strlen(property_name)+1 > sizeof(px->property_name)) {
251                 ERRDEVX(p->devno, "device property name %s too long",
252                         property_name);
253                 return;
254         }
255         strcpy(px->property_name, property_name);
256         if (px->procEntry == NULL) {
257                 ERRDEVX(p->devno,
258                         "failed to register /proc/%s/device/%d/%s entry",
259                         p->pdriver->ProcId, p->devno, property_name);
260                 return;
261         }
262         px->show_device_property_info = show_property_info;
263 }
264 EXPORT_SYMBOL_GPL(visor_easyproc_CreateDeviceProperty);
265
266
267
268 void visor_easyproc_DeInitDevice(struct easyproc_driver_info *pdriver,
269                                  struct easyproc_device_info *p, int devno)
270 {
271         size_t i;
272
273         for (i = 0; i < ARRAY_SIZE(p->device_property_info); i++) {
274                 if (p->device_property_info[i].procEntry != NULL) {
275                         struct easyproc_device_property_info *px =
276                                 &(p->device_property_info[i]);
277                         remove_proc_entry(px->property_name, p->procDevicexDir);
278                         px->procEntry = NULL;
279                 }
280         }
281         if (p->procDevicexDiagFile != NULL) {
282                 remove_proc_entry("diag", p->procDevicexDir);
283                 p->procDevicexDiagFile = NULL;
284         }
285         if (p->procDevicexDir != NULL) {
286                 char s[29];
287
288                 sprintf(s, "%d", devno);
289                 remove_proc_entry(s, pdriver->ProcDeviceDir);
290                 p->procDevicexDir = NULL;
291         }
292         p->devdata = NULL;
293         p->pdriver = NULL;
294 }
295 EXPORT_SYMBOL_GPL(visor_easyproc_DeInitDevice);
296
297
298
299 static int seq_show_driver(struct seq_file *seq, void *offset)
300 {
301         struct easyproc_driver_info *p =
302                 (struct easyproc_driver_info *)(seq->private);
303         if (!p)
304                 return 0;
305         (*(p->Show_driver_info))(seq);
306         return 0;
307 }
308
309
310
311 static int seq_show_device(struct seq_file *seq, void *offset)
312 {
313         struct easyproc_device_info *p =
314                 (struct easyproc_device_info *)(seq->private);
315         if ((!p) || (!(p->pdriver)))
316                 return 0;
317         (*(p->pdriver->Show_device_info))(seq, p->devdata);
318         return 0;
319 }
320
321
322
323 static int seq_show_device_property(struct seq_file *seq, void *offset)
324 {
325         struct easyproc_device_property_info *p =
326                 (struct easyproc_device_property_info *)(seq->private);
327         if ((!p) || (!(p->show_device_property_info)))
328                 return 0;
329         (*(p->show_device_property_info))(seq, p->devdata);
330         return 0;
331 }
332
333
334
335 static ssize_t proc_write_driver(struct file *file, const char __user *buffer,
336                                  size_t count, loff_t *ppos)
337 {
338         struct seq_file *seq = (struct seq_file *)file->private_data;
339         struct easyproc_driver_info *p = NULL;
340         char local_buf[256];
341
342         if (seq == NULL)
343                 return 0;
344         p = (struct easyproc_driver_info *)(seq->private);
345         if ((!p) || (!(p->Write_driver_info)))
346                 return 0;
347         if (count >= sizeof(local_buf))
348                 return -ENOMEM;
349         if (copy_from_user(local_buf, buffer, count))
350                 return -EFAULT;
351         local_buf[count] = '\0';  /* be friendly */
352         (*(p->Write_driver_info))(local_buf, count, ppos);
353         return count;
354 }
355
356
357
358 static ssize_t proc_write_device(struct file *file, const char __user *buffer,
359                                  size_t count, loff_t *ppos)
360 {
361         struct seq_file *seq = (struct seq_file *)file->private_data;
362         struct easyproc_device_info *p = NULL;
363         char local_buf[256];
364
365         if (seq == NULL)
366                 return 0;
367         p = (struct easyproc_device_info *)(seq->private);
368         if ((!p) || (!(p->pdriver)) || (!(p->pdriver->Write_device_info)))
369                 return 0;
370         if (count >= sizeof(local_buf))
371                 return -ENOMEM;
372         if (copy_from_user(local_buf, buffer, count))
373                 return -EFAULT;
374         local_buf[count] = '\0';  /* be friendly */
375         (*(p->pdriver->Write_device_info))(local_buf, count, ppos, p->devdata);
376         return count;
377 }