Milind Arun Choudhary's Weblog

http://www.csl.mtu.edu/~machoudh/

Linux kernel 2.4 :: writing IOCTLs for character devices

Posted by milindchoudhary on March 29, 2009

wrote it for 2.4..long time back
should work for 2.6 with minimal changes
one of my first few assignments  with Linux kernel
hence is very precious for me 🙂

and hey this also reminds me how yackssss was my coding style ..LOL [in shame…]

and definitions in the header file.. worse!

#include “MyFirstIOCTL.h”

int Argument1 =0;
char* Argument2 =”Milind”;

MODULE_PARM(Argument1 , “i”);
MODULE_PARM(Argument2 , “s”);

MODULE_PARM_DESC(Argument1 , “This is for future use”);
MODULE_PARM_DESC(Argument2 , “This is for future use”);

static int My_Init_Module(void)
{
EXPORT_NO_SYMBOLS;
printk(KERN_ALERT “\nHi this is \”%s\” ….”,Device_Name);

My_Major = register_chrdev(0 , Device_Name ,&MyFops );

if(My_Major < 0)
{
printk(KERN_ERR “\nSORRY!!! ..Couldn’t register the device.. “);
return FAILURE;
}
printk(KERN_ALERT “\nI got the major number >> %d”,My_Major);

KDEV =kmalloc(sizeof(DEV) , GFP_KERNEL);
if(KDEV == NULL)
return -EINVAL;

memset(KDEV , 0 , sizeof(DEV));

KDEV->BANNER =kmalloc(BUF_SIZE , GFP_KERNEL);

if(KDEV->BANNER == NULL)
return -EINVAL;

KDEV -> BANNER = “My First IOCTL”;

printk(KERN_ALERT “\nSuceesfully Initialized %s\n”,Device_Name);
return SUCCESS;
}

static void My_Cleanup_Module(void)
{
int Return_Value ;

printk(KERN_ALERT “\nLet me Unregister you…….”);

//kfree(KDEV -> BANNER);
kfree(KDEV);

Return_Value = unregister_chrdev(My_Major , Device_Name );
if(Return_Value < 0){
printk(KERN_ERR “\nSORRY!!! ..Couldn’t Unregister the device.. “);
}

printk(KERN_ALERT “\nSuccesfully Unregisterd…….BYE!!!\n”);

}

static int MyOpen(struct inode* pINODE , struct file* pFILE)
{
printk(KERN_ALERT “\nOpening the device ..please wait…\n”);
pFILE ->private_data = KDEV ;

//MOD_INC_USE_COUNT; /*Increment the use count……………*/

printk(KERN_ALERT “\nSuccesfully opened…”);
printk(KERN_ALERT “\nThe Offset = %i.\n”,(int)pFILE -> f_pos);

return SUCCESS;
}

static int MyRelease(struct inode* pINODE , struct file* pFILE)
{
printk(KERN_ALERT “\nReleasing the device ..please wait…\n”);
// MOD_DEC_USE_COUNT; /*Decrement the use count……………*/

printk(KERN_ALERT “\nSuccesfully Released…”);
printk(KERN_ALERT “\nThe Offset = %i.\n”,(int)pFILE -> f_pos);

return SUCCESS;
}

static ssize_t MyRead(struct file * pFILE , char * Buffer,
size_t Length , loff_t *Offset)
{
char * Message ;
int Bytes_Read=0;

printk(KERN_ALERT “\nReading from the device ..please wait…\n”);

/*Get the KDEV struct specific to the device ………………….*/
/*From the file operations structure………………………….*/

Message = ((pDEV) (pFILE -> private_data)) -> BUFFER ;

printk(KERN_ALERT “\nThe data in the device buffer is >>%s”,Message);

/*…………If at the end of message return zero………………*/
if(*Message == 0)
return 0;
/*Read “Length ” bytes from the Message & put them to the ……….*/
/*Buffer in the user space……………………………………*/

printk(“\nLength =%d”,Length);

while(*Message && Bytes_Read < Length)
{
put_user(*(Message++) , Buffer++);
Bytes_Read++;
}

put_user(” , Buffer++);

printk(KERN_ALERT “\n>>Succesfully read %d bytes ..\n”,Bytes_Read);

return 0;
}

static ssize_t MyWrite(struct file * pFILE , const char * Buffer,
size_t Length , loff_t *Offset)
{
char* Message;
int Bytes_Written=0;

printk(KERN_ALERT “\nWriting to the device ..please wait…\n”);
printk(KERN_ALERT “\nI’m supposed to write >>%s”,Buffer);

/*Get the KDEV struct specific to the device ………………….*/
/*From the file operations structure………………………….*/

Message = ((pDEV) (pFILE -> private_data)) -> BUFFER ;

printk(KERN_ALERT “\nThe data in the device buffer is >>%s”,Message);

/*Read the “Length ” bytes from the Buffer in the user space…….*/
/* & put them to the device buffer……………………………*/

for (Bytes_Written =0 ;
Bytes_Written < Length && Bytes_Written < BUF_SIZE;
Bytes_Written++)

{
get_user(Message[Bytes_Written] , Buffer + Bytes_Written );
}
Message[Bytes_Written]=”;

printk(KERN_ALERT “\n>>Succesfully wrote %d bytes ..”,Bytes_Written);
printk(KERN_ALERT “\nThe data in the device buffer is >>%s\n”,Message);

return Bytes_Written;

}

static int My_IOCTL(struct inode* pINODE , struct file* pFILE,
unsigned int Command ,unsigned long Argument)
{
int i;
char* Message;
char* Buffer;

Buffer =(char*)Argument;
Message = ((pDEV) (pFILE -> private_data)) -> BANNER ;

/*Check for a valid command………………………………….*/
if( _IOC_TYPE(Command) != MY_IOC_MAGIC ){
printk(“\nInvalid Command”);
return -ENOTTY;
}

if( _IOC_NR(Command) > MY_IOC_MAXNR ){
printk(“\nInvalid Command”);
return -ENOTTY;
}
/*To verify that the address passed as an argument is valid or not*/

/*if( _IOC_DIR(Command) & _IOC_READ ){
printk(“\nInvalid Command”);
return -ENOTTY;*/

/*Take specific action depending upon the command number………..*/

switch(Command){
case MY_IOC_RESET_USAGE : break;
case MY_IOC_CLEAR_BUFFER : break;
/*Returns the device banner in the string passed as an argument…….*/
case MY_IOC_GET_BANNER :

// for (i=0 ; i < Length && i< BUF_SIZE; i++)
i=0;
while(*(Message) ){
put_user(*(Message++) , Buffer++);
i++;
}
put_user(” , Buffer);
return i;

/*Sets the device banner to the string passed as an argument…….*/
case MY_IOC_SET_BANNER :

// for (i=0 ; i < Length && i< BUF_SIZE; i++)
i=0;
while(*(Buffer +i)){
get_user(Message[i] , Buffer + i);
i++;
}
Message[i]=”;
return i;

/*Sets the device banner to the string passed as an argument……..*/
/*and returns the device banner in the string passed as an argument..*/
case MY_IOC_SET_GET_BANNER : break;

default : return -ENOTTY;
}//end of switch
return 0;
}

header

#ifndef __KERNEL__
#define __KERNEL__
#endif

#ifndef MODULE
#define MODULE
#endif

#include
#include
#include /*the file operations………………*/
#include /*standard error numbers……………*/
#include /*ssize_t size_t…………………. */
#include /*put_user get_user ……………….*/
#include /*kmalloc kfree……………………*/
#include /*module_init & module_exit…………*/

#define Device_Name “MyFirstIOCTL1” /*Name Of the device supported..*/

#define SUCCESS 0 /*Used for Return values or flags……….*/
#define FAILURE 1

#define BUF_SIZE 80 /*Maximum size of the buffer……………*/

static int My_Init_Module(void);

static void My_Cleanup_Module(void);

static int MyOpen(struct inode* pINODE , struct file* pFILE);

static int MyRelease(struct inode* pINODE , struct file* pFILE);

static ssize_t MyWrite(struct file * pFILE , const char * Buffer,
size_t Length , loff_t *Offset);

static ssize_t MyRead(struct file * pFILE ,char * Buffer,
size_t Length , loff_t *Offset);

static int My_IOCTL(struct inode* pINODE , struct file* pFILE,
unsigned int Command ,unsigned long Argument);

module_init(My_Init_Module);
module_exit(My_Cleanup_Module);

MODULE_LICENSE(“GPL”); /*Give the kernel some a*/
MODULE_AUTHOR(“Milind”); /**/
MODULE_DESCRIPTION(“Tests the IOCTLs”);
MODULE_SUPPORTED_DEVICE( Device_Name );

/*Set to zero so that the kernel can allocate one dynamically……*/
int My_Major =0;

/*…………………..The Kdev struct………………………*/
/*………………….Used to simulate the device…………….*/
/*Can be considered as the registers & buffers of the device…….*/

struct dev;
typedef struct dev DEV;
typedef DEV* pDEV;

struct dev{
char* BANNER;
char BUFFER[BUF_SIZE];
}*KDEV,device;

static struct file_operations MyFops = {
owner : THIS_MODULE,
read : MyRead,
write : MyWrite,
open : MyOpen,
release : MyRelease,
ioctl : My_IOCTL,
};

char* BANNER;
#define MY_IOC_MAGIC ‘x’/* Use ‘x’ as magic number…………….*/

#define MY_IOC_RESET_USAGE _IO(MY_IOC_MAGIC , 1 )
#define MY_IOC_CLEAR_BUFFER _IO(MY_IOC_MAGIC , 2 )
#define MY_IOC_GET_BANNER _IOR(MY_IOC_MAGIC , 3 , BANNER )
#define MY_IOC_SET_BANNER _IOW(MY_IOC_MAGIC , 4 , BANNER )
#define MY_IOC_SET_GET_BANNER _IOWR(MY_IOC_MAGIC, 5 , BANNER )

#define MY_IOC_MAXNR 5 /*Number of IOCTLs supported…..*/

user

#include
#include
#include
#include
#include
#include “My_IOCTLS.h”

#define SUCCESS 0
#define FAILURE 1

#define DEVICE_NAME “/dev/MyFirstIOCTL0”
#define MAX_BUF_LEN 80

int main(void )
{
int File_Descriptor ; /**/
int Return_Value ; /*To catch the return value …….*/
char Buffer[MAX_BUF_LEN] ;

/* ……………..Opening the device (Read/Write)…………….*/

printf(“\n\tOpening the device ..please wait…”);
fflush(stdout);

File_Descriptor = open( DEVICE_NAME , O_RDWR );

if( File_Descriptor < 0 ) /*Display a message if any error occures*/
{
fprintf( stderr, “\n\tCould not open device file – Error : %i\n”, File_Descriptor );

return FAILURE ;
}

printf(“\n\tSuccesfully opened the device”);
printf(“\n\tThe file descriptor is >> %d\n”,File_Descriptor );

Return_Value =ioctl( File_Descriptor ,MY_IOC_GET_BANNER, Buffer);

if(Return_Value < 0)
{
fprintf(stderr,”\n\tSORRY!! ioctl failed ..\n”);
return FAILURE;
}
printf(“\n\tThe banner is currently set to %s “,Buffer);

strcpy(Buffer,”Sujit_Milind”); /*banner will be changed to this…..*/

printf(“\n\tChanging the device banner to %s “,Buffer);
fflush(stdout);

Return_Value =ioctl( File_Descriptor ,MY_IOC_SET_BANNER, Buffer);

if(Return_Value < 0)
{
fprintf(stderr,”\n\tSORRY!! ioctl failed ..\n”);
return FAILURE;
}

Return_Value =ioctl( File_Descriptor ,MY_IOC_GET_BANNER, Buffer);

if(Return_Value < 0)
{
fprintf(stderr,”\n\tSORRY!! ioctl failed ..\n”);
return FAILURE;
}
printf(“\n\tThe banner is currently set to %s “,Buffer);

printf(“\n\tReleasing the device ..please wait…”);

fflush(stdout);

Return_Value = close( File_Descriptor);

if( Return_Value < 0 ) /*Display a message if any error occures*/
{
fprintf(stderr,”\n\tSORRY!!! …Could not release device…..”);

return FAILURE ;
}

printf(“\n\tSuccesfully Released the device”);

printf(“\n\tSuccessfully tested the IOCTLs …\n”);
return SUCCESS;
}

Advertisements

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: