Home | History | Annotate | Download | only in kernel_space
      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