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 *
createProcDir(char * name,struct proc_dir_entry * parent)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);
proc_open_driver(struct inode * inode,struct file * file)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);
proc_open_device(struct inode * inode,struct file * file)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 };
proc_open_device_property(struct inode * inode,struct file * file)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
visor_easyproc_InitDriver(struct easyproc_driver_info * pdriver,char * procId,void (* show_driver_info)(struct seq_file *),void (* show_device_info)(struct seq_file *,void *))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
visor_easyproc_InitDriverEx(struct easyproc_driver_info * pdriver,char * procId,void (* show_driver_info)(struct seq_file *),void (* show_device_info)(struct seq_file *,void *),void (* write_driver_info)(char * buf,size_t count,loff_t * ppos),void (* write_device_info)(char * buf,size_t count,loff_t * ppos,void * p))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
visor_easyproc_DeInitDriver(struct easyproc_driver_info * pdriver)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
visor_easyproc_InitDevice(struct easyproc_driver_info * pdriver,struct easyproc_device_info * p,int devno,void * devdata)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
visor_easyproc_CreateDeviceProperty(struct easyproc_device_info * p,void (* show_property_info)(struct seq_file *,void *),char * property_name)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, "failed to register /proc/%s/device/%d/%s entry",
258 p->pdriver->ProcId, p->devno, property_name
259 );
260 return;
261 }
262 px->show_device_property_info = show_property_info;
263 }
264 EXPORT_SYMBOL_GPL(visor_easyproc_CreateDeviceProperty);
265
266
267
visor_easyproc_DeInitDevice(struct easyproc_driver_info * pdriver,struct easyproc_device_info * p,int devno)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
seq_show_driver(struct seq_file * seq,void * offset)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
seq_show_device(struct seq_file * seq,void * offset)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
seq_show_device_property(struct seq_file * seq,void * offset)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
proc_write_driver(struct file * file,const char __user * buffer,size_t count,loff_t * ppos)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
proc_write_device(struct file * file,const char __user * buffer,size_t count,loff_t * ppos)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 }
378