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 (at) 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 */ 71 static int tmod_open(struct inode *ino, struct file *f) 72 { 73 return 0; 74 } 75 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 */ 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 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 */ 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 */ 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