• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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