| /* Module Declarations *************************** */ 
/* This structure will hold the functions to be called 
* when a process does something to the device we 
* created. Since a pointer to this structure is kept in 
* the devices table, it cant be local to 
* init_module. NULL is for unimplemented functions. */ 
struct file_operations Fops = { 
NULL, /* seek */ 
device_read, 
device_write, 
NULL, /* readdir */ 
NULL, /* 0select */ 
device_ioctl, /* ioctl */ 
NULL, /* mmap */ 
device_open, 
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) 
NULL, /* flush */ 
#endif 
device_release /* a.k.a. close */ 
}. 
/* Initialize the module - Register the character device */ 
int init_module() 
{ 
int ret_val. 
/* Register the character device (atleast try) */ 
ret_val = module_register_chrdev(MAJOR_NUM, 
DEVICE_NAME, 
&.Fops). 
/* Negative values signify an error */ 
if (ret_val < 0) { 
printk ("%s failed with %d\n", 
"Sorry, registering the character device ", 
ret_val). 
return ret_val. 
} 
printk ("%s The major device number is %d.\n", 
"Registeration is a success", 
MAJOR_NUM). 
printk ("If you want to talk to the device driver,\n"). 
printk ("youll have to create a device file. \n"). 
printk ("We suggest you use:\n"). 
printk ("mknod %s c %d 0\n", DEVICE_FILE_NAME, 
MAJOR_NUM). 
printk ("The device file name is important, because\n"). 
printk ("the ioctl program assumes thats the\n"). 
printk ("file youll use.\n"). 
return 0. 
} 
/* Cleanup - unregister the appropriate file from /proc */ 
void cleanup_module() 
{ 
int ret. 
/* Unregister the device */ 
ret = module_unregister_chrdev(MAJOR_NUM, DEVICE_NAME). 
/* If theres an error, report it */ 
if (ret < 0) 
printk("Error in module_unregister_chrdev: %d\n", ret). 
} 
ex chardev.h 
/* chardev.h - the header file with the ioctl definitions. 
* 
* The declarations here have to be in a header file, 
* because they need to be known both to the kernel 
* module (in chardev.c) and the process calling ioctl 
* (ioctl.c) 
*/ 
#ifndef CHARDEV_H 
#define CHARDEV_H 
#include 
/* The major device number. We cant rely on dynamic 
* registration any more, because ioctls need to know 
* it. */ 
#define MAJOR_NUM 100 
/* Set the message of the device driver */ 
#define IOCTL_SET_MSG _IOR(MAJOR_NUM, 0, char *) 
/* _IOR means that were creating an ioctl command 
* number for passing information from a user process 
* to the kernel module. 
* 
* The first arguments, MAJOR_NUM, is the major device 
* number were using. 
* 
* The second argument is the number of the command 
* (there could be several with different meanings). 
* 
* The third argument is the type we want to get from 
* the process to the kernel. 
*/ 
/* Get the message of the device driver */ 
#define IOCTL_GET_MSG _IOR(MAJOR_NUM, 1, char *) 
/* This IOCTL is used for output, to get the message 
* of the device driver. However, we still need the 
* buffer to place the message in to be input, 
* as it is allocated by the process. 
*/ 
/* Get the nth byte of the message */ 
#define IOCTL_GET_NTH_BYTE _IOWR(MAJOR_NUM, 2, int) 
/* The IOCTL is used for both input and output. It 
* receives from the user a number, n, and returns 
* Message[n]. */ 
/* The name of the device file */ 
#define DEVICE_FILE_NAME "char_dev" 
#endif 
ex ioctl.c 
/* ioctl.c - the process to use ioctls to control the 
* kernel module 
* 
* Until now we could have used cat for input and 
* output. But now we need to do ioctls, which require 
* writing our own process. 
*/ 
/* Copyright (C) 1998 by Ori Pomerantz */ 
/* device specifics, such as ioctl numbers and the 
* major device file. */ 
#include "chardev.h" 
#include /* open */ 
#include /* exit */ 
#include /* ioctl */ 
/* Functions for the ioctl calls */ 
ioctl_set_msg(int file_desc, char *message) 
{ 
int ret_val. 
ret_val = ioctl(file_desc, IOCTL_SET_MSG, message). 
if (ret_val < 0) { 
printf ("ioctl_set_msg failed:%d\n", ret_val). 
exit(-1). 
} 
} 
ioctl_get_msg(int file_desc) 
{ 
int ret_val. 
char message[100]. 
/* Warning - this is dangerous because we dont tell 
* the kernel how far its allowed to write, so it 
* might overflow the buffer. In a real production 
* program, we would have used two ioctls - one to tell 
* the kernel the buffer length and another to give 
* it the buffer to fill 
*/ 
ret_val = ioctl(file_desc, IOCTL_GET_MSG, message). 
if (ret_val < 0) { 
printf ("ioctl_get_msg failed:%d\n", ret_val). 
exit(-1). 
} 
printf("get_msg message:%s\n", message). 
} 
ioctl_get_nth_byte(int file_desc) 
{ 
int i. 
char c. 
printf("get_nth_byte message:"). 
i = 0. 
while (c != 0) { 
c = ioctl(file_desc, IOCTL_GET_NTH_BYTE, i  ). 
if (c < 0) { 
printf( 
"ioctl_get_nth_byte failed at the %dth byte:\n", i). 
exit(-1). 
} 
putchar(c). 
} 
putchar(\n). 
} 
/* Main - Call the ioctl functions */ 
main() 
{ 
int file_desc, ret_val. 
char *msg = "Message passed by ioctl\n". 
file_desc = open(DEVICE_FILE_NAME, 0). 
if (file_desc < 0) { 
printf ("Cant open device file: %s\n", 
DEVICE_FILE_NAME). 
exit(-1). 
} 
ioctl_get_nth_byte(file_desc). 
ioctl_get_msg(file_desc). 
ioctl_set_msg(file_desc, msg). 
close(file_desc). 
} |