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