mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-09-04 20:19:47 +08:00 
			
		
		
		
	 1da177e4c3
			
		
	
	
		1da177e4c3
		
	
	
	
	
		
			
			Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
		
			
				
	
	
		
			225 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			225 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * procfs_example.c: an example proc interface
 | |
|  *
 | |
|  * Copyright (C) 2001, Erik Mouw (J.A.K.Mouw@its.tudelft.nl)
 | |
|  *
 | |
|  * This file accompanies the procfs-guide in the Linux kernel
 | |
|  * source. Its main use is to demonstrate the concepts and
 | |
|  * functions described in the guide.
 | |
|  *
 | |
|  * This software has been developed while working on the LART
 | |
|  * computing board (http://www.lart.tudelft.nl/), which is
 | |
|  * sponsored by the Mobile Multi-media Communications
 | |
|  * (http://www.mmc.tudelft.nl/) and Ubiquitous Communications 
 | |
|  * (http://www.ubicom.tudelft.nl/) projects.
 | |
|  *
 | |
|  * The author can be reached at:
 | |
|  *
 | |
|  *  Erik Mouw
 | |
|  *  Information and Communication Theory Group
 | |
|  *  Faculty of Information Technology and Systems
 | |
|  *  Delft University of Technology
 | |
|  *  P.O. Box 5031
 | |
|  *  2600 GA Delft
 | |
|  *  The Netherlands
 | |
|  *
 | |
|  *
 | |
|  * This program is free software; you can redistribute
 | |
|  * it and/or modify it under the terms of the GNU General
 | |
|  * Public License as published by the Free Software
 | |
|  * Foundation; either version 2 of the License, or (at your
 | |
|  * option) any later version.
 | |
|  *
 | |
|  * This program is distributed in the hope that it will be
 | |
|  * useful, but WITHOUT ANY WARRANTY; without even the implied
 | |
|  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 | |
|  * PURPOSE.  See the GNU General Public License for more
 | |
|  * details.
 | |
|  * 
 | |
|  * You should have received a copy of the GNU General Public
 | |
|  * License along with this program; if not, write to the
 | |
|  * Free Software Foundation, Inc., 59 Temple Place,
 | |
|  * Suite 330, Boston, MA  02111-1307  USA
 | |
|  *
 | |
|  */
 | |
| 
 | |
| #include <linux/module.h>
 | |
| #include <linux/kernel.h>
 | |
| #include <linux/init.h>
 | |
| #include <linux/proc_fs.h>
 | |
| #include <linux/jiffies.h>
 | |
| #include <asm/uaccess.h>
 | |
| 
 | |
| 
 | |
| #define MODULE_VERS "1.0"
 | |
| #define MODULE_NAME "procfs_example"
 | |
| 
 | |
| #define FOOBAR_LEN 8
 | |
| 
 | |
| struct fb_data_t {
 | |
| 	char name[FOOBAR_LEN + 1];
 | |
| 	char value[FOOBAR_LEN + 1];
 | |
| };
 | |
| 
 | |
| 
 | |
| static struct proc_dir_entry *example_dir, *foo_file,
 | |
| 	*bar_file, *jiffies_file, *symlink;
 | |
| 
 | |
| 
 | |
| struct fb_data_t foo_data, bar_data;
 | |
| 
 | |
| 
 | |
| static int proc_read_jiffies(char *page, char **start,
 | |
| 			     off_t off, int count,
 | |
| 			     int *eof, void *data)
 | |
| {
 | |
| 	int len;
 | |
| 
 | |
| 	len = sprintf(page, "jiffies = %ld\n",
 | |
|                       jiffies);
 | |
| 
 | |
| 	return len;
 | |
| }
 | |
| 
 | |
| 
 | |
| static int proc_read_foobar(char *page, char **start,
 | |
| 			    off_t off, int count, 
 | |
| 			    int *eof, void *data)
 | |
| {
 | |
| 	int len;
 | |
| 	struct fb_data_t *fb_data = (struct fb_data_t *)data;
 | |
| 
 | |
| 	/* DON'T DO THAT - buffer overruns are bad */
 | |
| 	len = sprintf(page, "%s = '%s'\n", 
 | |
| 		      fb_data->name, fb_data->value);
 | |
| 
 | |
| 	return len;
 | |
| }
 | |
| 
 | |
| 
 | |
| static int proc_write_foobar(struct file *file,
 | |
| 			     const char *buffer,
 | |
| 			     unsigned long count, 
 | |
| 			     void *data)
 | |
| {
 | |
| 	int len;
 | |
| 	struct fb_data_t *fb_data = (struct fb_data_t *)data;
 | |
| 
 | |
| 	if(count > FOOBAR_LEN)
 | |
| 		len = FOOBAR_LEN;
 | |
| 	else
 | |
| 		len = count;
 | |
| 
 | |
| 	if(copy_from_user(fb_data->value, buffer, len))
 | |
| 		return -EFAULT;
 | |
| 
 | |
| 	fb_data->value[len] = '\0';
 | |
| 
 | |
| 	return len;
 | |
| }
 | |
| 
 | |
| 
 | |
| static int __init init_procfs_example(void)
 | |
| {
 | |
| 	int rv = 0;
 | |
| 
 | |
| 	/* create directory */
 | |
| 	example_dir = proc_mkdir(MODULE_NAME, NULL);
 | |
| 	if(example_dir == NULL) {
 | |
| 		rv = -ENOMEM;
 | |
| 		goto out;
 | |
| 	}
 | |
| 	
 | |
| 	example_dir->owner = THIS_MODULE;
 | |
| 	
 | |
| 	/* create jiffies using convenience function */
 | |
| 	jiffies_file = create_proc_read_entry("jiffies", 
 | |
| 					      0444, example_dir, 
 | |
| 					      proc_read_jiffies,
 | |
| 					      NULL);
 | |
| 	if(jiffies_file == NULL) {
 | |
| 		rv  = -ENOMEM;
 | |
| 		goto no_jiffies;
 | |
| 	}
 | |
| 
 | |
| 	jiffies_file->owner = THIS_MODULE;
 | |
| 
 | |
| 	/* create foo and bar files using same callback
 | |
| 	 * functions 
 | |
| 	 */
 | |
| 	foo_file = create_proc_entry("foo", 0644, example_dir);
 | |
| 	if(foo_file == NULL) {
 | |
| 		rv = -ENOMEM;
 | |
| 		goto no_foo;
 | |
| 	}
 | |
| 
 | |
| 	strcpy(foo_data.name, "foo");
 | |
| 	strcpy(foo_data.value, "foo");
 | |
| 	foo_file->data = &foo_data;
 | |
| 	foo_file->read_proc = proc_read_foobar;
 | |
| 	foo_file->write_proc = proc_write_foobar;
 | |
| 	foo_file->owner = THIS_MODULE;
 | |
| 		
 | |
| 	bar_file = create_proc_entry("bar", 0644, example_dir);
 | |
| 	if(bar_file == NULL) {
 | |
| 		rv = -ENOMEM;
 | |
| 		goto no_bar;
 | |
| 	}
 | |
| 
 | |
| 	strcpy(bar_data.name, "bar");
 | |
| 	strcpy(bar_data.value, "bar");
 | |
| 	bar_file->data = &bar_data;
 | |
| 	bar_file->read_proc = proc_read_foobar;
 | |
| 	bar_file->write_proc = proc_write_foobar;
 | |
| 	bar_file->owner = THIS_MODULE;
 | |
| 		
 | |
| 	/* create symlink */
 | |
| 	symlink = proc_symlink("jiffies_too", example_dir, 
 | |
| 			       "jiffies");
 | |
| 	if(symlink == NULL) {
 | |
| 		rv = -ENOMEM;
 | |
| 		goto no_symlink;
 | |
| 	}
 | |
| 
 | |
| 	symlink->owner = THIS_MODULE;
 | |
| 
 | |
| 	/* everything OK */
 | |
| 	printk(KERN_INFO "%s %s initialised\n",
 | |
| 	       MODULE_NAME, MODULE_VERS);
 | |
| 	return 0;
 | |
| 
 | |
| no_symlink:
 | |
| 	remove_proc_entry("tty", example_dir);
 | |
| no_tty:
 | |
| 	remove_proc_entry("bar", example_dir);
 | |
| no_bar:
 | |
| 	remove_proc_entry("foo", example_dir);
 | |
| no_foo:
 | |
| 	remove_proc_entry("jiffies", example_dir);
 | |
| no_jiffies:			      
 | |
| 	remove_proc_entry(MODULE_NAME, NULL);
 | |
| out:
 | |
| 	return rv;
 | |
| }
 | |
| 
 | |
| 
 | |
| static void __exit cleanup_procfs_example(void)
 | |
| {
 | |
| 	remove_proc_entry("jiffies_too", example_dir);
 | |
| 	remove_proc_entry("tty", example_dir);
 | |
| 	remove_proc_entry("bar", example_dir);
 | |
| 	remove_proc_entry("foo", example_dir);
 | |
| 	remove_proc_entry("jiffies", example_dir);
 | |
| 	remove_proc_entry(MODULE_NAME, NULL);
 | |
| 
 | |
| 	printk(KERN_INFO "%s %s removed\n",
 | |
| 	       MODULE_NAME, MODULE_VERS);
 | |
| }
 | |
| 
 | |
| 
 | |
| module_init(init_procfs_example);
 | |
| module_exit(cleanup_procfs_example);
 | |
| 
 | |
| MODULE_AUTHOR("Erik Mouw");
 | |
| MODULE_DESCRIPTION("procfs examples");
 |