[Linuxpps] [PATCH] procfs source entries

Rodolfo Giometti giometti at linux.it
Fri May 26 21:08:16 CEST 2006


Hello,

here a proposal patch to implement a better procfs support.

With this patch you can get in /proc/pps dir one new dir for each PPS source
as follow:

   giometti at jeeg:~$ ls /proc/pps/
   00/  01/  02/  03/  04/  sources
   giometti at jeeg:~$ cat /proc/pps/sources 
   id	mode	echo	name			path
   ----	------	----	----------------	----------------
   00	1133	no	pps_8250_0		/dev/ttyS0
   01	1133	no	pps_8250_1		/dev/ttyS1
   02	1133	no	pps_8250_2		/dev/ttyS2
   03	1133	no	pps_8250_3		/dev/ttyS3
   04	1151	yes	ktimer		
      
Then in each dir you have two (or one) new files where you can read
assert/clear events time and number sequence:

   giometti at jeeg:~$ cat /proc/pps/04/assert 
   1148670312.391012000 #166
   giometti at jeeg:~$ cat /proc/pps/04/assert 
   1148670313.391071000 #167
   giometti at jeeg:~$ cat /proc/pps/04/assert 
   1148670313.391071000 #167
   giometti at jeeg:~$ cat /proc/pps/04/assert 
   1148670314.391138000 #168
   giometti at jeeg:~$ cat /proc/pps/04/assert 
   1148670314.391138000 #168
   giometti at jeeg:~$ cat /proc/pps/04/assert 
   1148670315.391247000 #169

Please test ot and report possible bugs/problems.

Ciao,

Rodolfo

-- 

GNU/Linux Solutions                  e-mail:    giometti at enneenne.com
Linux Device Driver                             giometti at gnudd.com
Embedded Systems                     		giometti at linux.it
UNIX programming                     phone:     +39 349 2432127
-------------- next part --------------
diff --git a/drivers/pps/kapi.c b/drivers/pps/kapi.c
index 4f334b9..71177bd 100644
--- a/drivers/pps/kapi.c
+++ b/drivers/pps/kapi.c
@@ -51,7 +51,7 @@ static void linuxpps_add_offeset(struct 
 
 int linuxpps_register_source(struct linuxpps_source_info_s *info, int default_params, int try_id)
 {
-	int i;
+	int i, ret;
 
 	if (try_id >= 0) {
 		if (linuxpps_is_allocated(try_id)) {
@@ -91,6 +91,10 @@ int linuxpps_register_source(struct linu
 	linuxpps_source[i].params.mode = default_params;
 	init_waitqueue_head(&linuxpps_source[i].queue);
 
+	ret = linuxpps_procfs_create_source_entry(info, i);
+	if (ret < 0)
+		err("unable to create procfs entry for source %d", i);
+
 	return i;
 }
 
@@ -108,6 +112,7 @@ void linuxpps_unregister_source(struct l
 	}
 
 	/* Deallocate the PPS source */
+	linuxpps_procfs_remove_source_entry(info, i);
 	linuxpps_source[i].info = NULL; 
 } 
 
diff --git a/drivers/pps/procfs.c b/drivers/pps/procfs.c
index ae6eb1b..49452c5 100644
--- a/drivers/pps/procfs.c
+++ b/drivers/pps/procfs.c
@@ -22,13 +22,44 @@
 
 #include <linux/proc_fs.h>
 #include <linux/module.h>
+#include <linux/string.h>
 
 #include <linux/timepps.h>
 #include <linux/pps.h>
 
 #ifdef CONFIG_PPS_PROCFS
+/* ----- Global variables --------------------------------------------- */
+
+struct proc_dir_entry *procfs_root_dir;
+
 /* ----- Private functions -------------------------------------------- */
 
+static int linuxpps_procfs_assert_read(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	int len = 0;
+	int id = (int) data;
+	len += sprintf(page+len, "%ld.%ld #%ld\n",
+			linuxpps_source[id].assert_tu.tspec.tv_sec,
+			linuxpps_source[id].assert_tu.tspec.tv_nsec,
+			linuxpps_source[id].assert_sequence);
+
+	*eof = 1;
+	return len;
+}
+
+static int linuxpps_procfs_clear_read(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	int len = 0;
+	int id = (int) data;
+	len += sprintf(page+len, "%ld.%ld #%ld\n",
+			linuxpps_source[id].clear_tu.tspec.tv_sec,
+			linuxpps_source[id].clear_tu.tspec.tv_nsec,
+			linuxpps_source[id].clear_sequence);
+
+	*eof = 1;
+	return len;
+}
+
 static int linuxpps_sources_read(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	int i;
@@ -38,7 +69,7 @@ static int linuxpps_sources_read(char *p
 	len += sprintf(page+len, "----\t------\t----\t----------------\t----------------\n");
 	for (i = 0; i < LINUXPPS_MAX_SOURCES; i++)
 		if (linuxpps_is_allocated(i))
-			len += sprintf(page+len, "%2d\t%4x\t%s\t%s\t\t%s\n",
+			len += sprintf(page+len, "%.02d\t%4x\t%s\t%s\t\t%s\n",
 					i,
 					linuxpps_source[i].info->mode,
 					linuxpps_source[i].info->echo ? "yes" : "no",
@@ -51,6 +82,57 @@ static int linuxpps_sources_read(char *p
 
 /* ----- Public functions --------------------------------------------- */
 
+void linuxpps_procfs_remove_source_entry(struct linuxpps_source_info_s *info, int id) {
+	char buf[32];
+
+	/* Sanity checks */
+	if (info == NULL || info->dir == NULL || id >= LINUXPPS_MAX_SOURCES)
+		return;
+
+	remove_proc_entry("clear", info->dir);	
+	remove_proc_entry("assert", info->dir);	
+	sprintf(buf, "%.02d", id);
+	remove_proc_entry(buf, procfs_root_dir);	
+}
+
+int linuxpps_procfs_create_source_entry(struct linuxpps_source_info_s *info, int id) {
+	struct proc_dir_entry *procfs_file;
+	char buf[32];
+
+	/* Sanity checks */
+	if (info == NULL || id >= LINUXPPS_MAX_SOURCES)
+		return -EINVAL;
+
+	/* Create dir "/proc/pps/<id>" */
+	sprintf(buf, "%.02d", id);
+	info->dir = proc_mkdir(buf, procfs_root_dir);
+	if (info->dir == NULL)
+		return -ENOMEM;
+
+	/* Create file "assert" and "clear" according to source capability */
+	if (info->mode&PPS_CAPTUREASSERT) {
+		procfs_file = create_proc_entry("assert", S_IRUGO|S_IWUSR, info->dir);
+		if (procfs_file == NULL)
+			goto exit;
+		procfs_file->read_proc = linuxpps_procfs_assert_read;
+		procfs_file->data = (void *) id;
+	}
+	if (info->mode&PPS_CAPTURECLEAR) {
+		procfs_file = create_proc_entry("clear", S_IRUGO|S_IWUSR, info->dir);
+		if (procfs_file == NULL)
+			goto exit;
+		procfs_file->read_proc = linuxpps_procfs_clear_read;
+		procfs_file->data = (void *) id;
+	}
+
+	return 0;
+
+exit :
+	linuxpps_procfs_remove_source_entry(info, id);
+
+	return -ENOMEM;
+}
+
 void linuxpps_procfs_unregister(void)
 {
 	remove_proc_entry("pps/sources", NULL);
@@ -61,15 +143,15 @@ void linuxpps_procfs_unregister(void)
 
 int linuxpps_procfs_register(void)
 {
-	struct proc_dir_entry *root_dir, *procfs_file;
+	struct proc_dir_entry *procfs_file;
 
 	/* The root dir in /proc */
-	root_dir = proc_mkdir("pps", NULL);
-	if (root_dir == NULL)
+	procfs_root_dir = proc_mkdir("pps", NULL);
+	if (procfs_root_dir == NULL)
 		return -ENOMEM;
 
 	/* The file "sources" */
-	procfs_file = create_proc_entry("sources", S_IRUGO|S_IWUSR, root_dir);
+	procfs_file = create_proc_entry("sources", S_IRUGO|S_IWUSR, procfs_root_dir);
 	if (procfs_file == NULL) {
 		linuxpps_procfs_unregister();
 		return -ENOMEM;
diff --git a/include/linux/pps.h b/include/linux/pps.h
index 414da07..f6adea0 100644
--- a/include/linux/pps.h
+++ b/include/linux/pps.h
@@ -51,6 +51,9 @@ struct linuxpps_source_info_s {
 	int mode;					/* PPS's allowed mode */
 
 	void (*echo)(int source, int event);		/* the PPS echo function */
+
+	/* procfs section */
+	struct proc_dir_entry *dir;
 };
 
 /* The main struct */
@@ -84,5 +87,7 @@ extern int linuxpps_register_source(stru
 extern void linuxpps_unregister_source(struct linuxpps_source_info_s *info);
 extern void linuxpps_event(int source, int event);
 
+extern int linuxpps_procfs_create_source_entry(struct linuxpps_source_info_s *info, int id);
+extern void linuxpps_procfs_remove_source_entry(struct linuxpps_source_info_s *info, int id);
 extern int linuxpps_procfs_register(void);
 extern void linuxpps_procfs_unregister(void);


More information about the LinuxPPS mailing list