• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  *   Copyright (c) International Business Machines  Corp., 2001
4  *
5  *   This program is free software;  you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation; either version 2 of the License, or
8  *   (at your option) any later version.
9  *
10  *   This program is distributed in the hope that it will be useful,
11  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
13  *   the GNU General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program;  if not, write to the Free Software
17  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  *
19 
20  * This example module shows how a test driver
21  * can be driven through various ioctl calls in
22  * a user space program that has attained the
23  * appropriate file descriptor for this device.
24  *
25  * author: Sean Ruyle
26  * date:   06/11/2003
27  *
28  * module: tmod
29  */
30 
31 #include <linux/types.h>
32 #include <linux/kernel.h>
33 #include <linux/fs.h>
34 #include <linux/ioctl.h>
35 #include <linux/module.h>
36 #include <linux/init.h>
37 #include <asm/uaccess.h>
38 
39 #include "tmod.h"
40 #include "str_mod.h"
41 
42 MODULE_AUTHOR("Sean Ruyle <srruyle@us.ibm.com>");
43 MODULE_DESCRIPTION(TMOD_DRIVER_NAME);
44 MODULE_LICENSE("GPL");
45 
46 static int tmod_ioctl(struct inode *, struct file *, unsigned int,
47 		      unsigned long);
48 static int tmod_open(struct inode *, struct file *);
49 static int tmod_close(struct inode *, struct file *);
50 
51 static int test_option(void);
52 
53 static int Major = TMOD_MAJOR;
54 //static ltpmod_user_t ltp_mod;
55 
56 /*
57  * File operations struct, to use operations find the
58  * correct file descriptor
59  */
60 static struct file_operations tmod_fops = {
61 open:	tmod_open,
62 release:tmod_close,
63 ioctl:	tmod_ioctl,
64 };
65 
66 /*
67  * open and close operations, just return 0 for
68  * your test modules, need them for the file
69  * operations structure
70  */
tmod_open(struct inode * ino,struct file * f)71 static int tmod_open(struct inode *ino, struct file *f)
72 {
73 	return 0;
74 }
75 
tmod_close(struct inode * ino,struct file * f)76 static int tmod_close(struct inode *ino, struct file *f)
77 {
78 	return 0;
79 }
80 
81 /*
82  * tmod_ioctl:
83  *      a user space program can drive the test functions
84  *      through a call to ioctl once the correct file
85  *      descriptor has been attained
86  *
87  * 	in user space the file descriptor that you attain
88  * 	will represent the inode and file pointers in
89  * 	the kernel ioctl function, and only 3 variables
90  *	will be passed in, linux/ioctl.h should be
91  *	included
92  *
93  */
tmod_ioctl(struct inode * ino,struct file * f,unsigned int cmd,unsigned long l)94 static int tmod_ioctl(struct inode *ino, struct file *f,
95 		      unsigned int cmd, unsigned long l)
96 {
97 	int rc;
98 	tmod_interface_t tif;
99 	caddr_t *inparms;
100 	caddr_t *outparms;
101 
102 	printk("Enter tmod_ioctl\n");
103 
104 	inparms = NULL;
105 	outparms = NULL;
106 	rc = 0;
107 
108 	/*
109 	 * the following calls are used to setup the
110 	 * parameters that might need to be passed
111 	 * between user and kernel space, using the tif
112 	 * pointer that is passed in as the last
113 	 * parameter to the ioctl
114 	 *
115 	 */
116 	if (copy_from_user(&tif, (void *)l, sizeof(tif))) {
117 		/* Bad address */
118 		return (-EFAULT);
119 	}
120 
121 	/*
122 	 * Setup inparms and outparms as needed
123 	 */
124 	if (tif.in_len > 0) {
125 		inparms = (caddr_t *) kmalloc(tif.in_len, GFP_KERNEL);
126 		if (!inparms) {
127 			return (-ENOMEM);
128 		}
129 
130 		rc = copy_from_user(inparms, tif.in_data, tif.in_len);
131 		if (rc) {
132 			kfree(inparms);
133 			return (-EFAULT);
134 		}
135 	}
136 	if (tif.out_len > 0) {
137 		outparms = (caddr_t *) kmalloc(tif.out_len, GFP_KERNEL);
138 		if (!outparms) {
139 			kfree(inparms);
140 			return (-ENOMEM);
141 		}
142 	}
143 
144 	/*
145 	 * Use a switch statement to determine which function
146 	 * to call, based on the cmd flag that is specified
147 	 * in user space. Pass in inparms or outparms as
148 	 * needed
149 	 *
150 	 */
151 	switch (cmd) {
152 	case LTP_OPTION1:
153 		rc = test_option();
154 		break;
155 	default:
156 		printk("Mismatching ioctl command\n");
157 		break;
158 	}
159 
160 	/*
161 	 * copy in the test return code, the reason we
162 	 * this is so that in user space we can tell the
163 	 * difference between an error in one of our test
164 	 * calls or an error in the ioctl function
165 	 */
166 	tif.out_rc = rc;
167 	rc = 0;
168 
169 	/*
170 	 * setup the rest of tif pointer for returning to
171 	 * to user space, using copy_to_user if needed
172 	 */
173 
174 	/* if outparms then copy outparms into tif.out_data */
175 	if (outparms) {
176 		if (copy_to_user(tif.out_data, outparms, tif.out_len)) {
177 			printk("tpci: Unsuccessful copy_to_user of outparms\n");
178 			rc = -EFAULT;
179 		}
180 	}
181 
182 	/* copy tif structure into l so that can be used by user program */
183 	if (copy_to_user((void *)l, &tif, sizeof(tif))) {
184 		printk("tpci: Unsuccessful copy_to_user of tif\n");
185 		rc = -EFAULT;
186 	}
187 
188 	/*
189 	 * free inparms and outparms
190 	 */
191 	if (inparms) {
192 		kfree(inparms);
193 	}
194 	if (outparms) {
195 		kfree(outparms);
196 	}
197 
198 	return rc;
199 }
200 
201 /*
202  * test functions can go here or in a seperate file,
203  * remember that the makefile will have to be  modified
204  * as well as the header file will need the function
205  * prototypes if the test calls go in another file
206  *
207  * functions should be static so that they may not
208  * be called by outside functions, in the kernel
209  * if a function is non_static and the symbol is
210  * exported using EXPORT_SYMBOL(function_name)
211  * then other parts of the kernel such as modules
212  * may use that function
213  *
214  */
215 
test_option()216 static int test_option()
217 {
218 
219 	/* setup test parameters and make the call here */
220 
221 	printk("tmod: this is option1 example\n");
222 
223 	/* remember that printk does not show up on the console,
224 	   check /var/log/messages to see your what is printed */
225 
226 	return 0;
227 }
228 
229 /*
230  * tmod_init_module
231  *      set the owner of tmod_fops, register the module
232  *      as a char device, and perform any necessary
233  *      initialization for pci devices
234  */
tmod_init_module(void)235 static int tmod_init_module(void)
236 {
237 	int rc;
238 
239 	SET_MODULE_OWNER(&tmod_fops);
240 
241 	rc = register_chrdev(Major, DEVICE_NAME, &tmod_fops);
242 	if (rc < 0) {
243 		printk("tmod: Failed to register device.\n");
244 		return rc;
245 	}
246 
247 	if (Major == 0)
248 		Major = rc;
249 
250 	/* call any other init functions you might use here */
251 
252 	printk("tmod: Registration success.\n");
253 	return 0;
254 }
255 
256 /*
257  * tmod_exit_module
258  *      unregister the device and any necessary
259  *      operations to close devices
260  */
tmod_exit_module(void)261 static void tmod_exit_module(void)
262 {
263 	int rc;
264 
265 	/* free any pointers still allocated, using kfree */
266 
267 	rc = unregister_chrdev(Major, DEVICE_NAME);
268 	if (rc < 0)
269 		printk("tmod: unregister failed\n");
270 	else
271 		printk("tmod: unregister success\n");
272 
273 }
274 
275 /* specify what that init is run when the module is first
276 loaded and that exit is run when it is removed */
277 
278 module_init(tmod_init_module)
279     module_exit(tmod_exit_module)
280