[go: nahoru, domu]

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
55static ssize_t proc_write_device(struct file *file, const char __user *buffer,
56				 size_t count, loff_t *ppos);
57static ssize_t proc_write_driver(struct file *file, const char __user *buffer,
58				 size_t count, loff_t *ppos);
59
60static 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
70static int seq_show_driver(struct seq_file *seq, void *offset);
71static int proc_open_driver(struct inode *inode, struct file *file)
72{
73	return single_open(file, seq_show_driver, PDE_DATA(inode));
74}
75static 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
83static int seq_show_device(struct seq_file *seq, void *offset);
84static int seq_show_device_property(struct seq_file *seq, void *offset);
85static int proc_open_device(struct inode *inode, struct file *file)
86{
87	return single_open(file, seq_show_device, PDE_DATA(inode));
88}
89static 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};
96static 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}
100static 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
109void 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}
140EXPORT_SYMBOL_GPL(visor_easyproc_InitDriver);
141
142
143
144void 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}
162EXPORT_SYMBOL_GPL(visor_easyproc_InitDriverEx);
163
164
165
166void 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}
190EXPORT_SYMBOL_GPL(visor_easyproc_DeInitDriver);
191
192
193
194void 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}
220EXPORT_SYMBOL_GPL(visor_easyproc_InitDevice);
221
222
223
224void 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}
264EXPORT_SYMBOL_GPL(visor_easyproc_CreateDeviceProperty);
265
266
267
268void 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}
295EXPORT_SYMBOL_GPL(visor_easyproc_DeInitDevice);
296
297
298
299static 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
311static 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
323static 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
335static 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
358static 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