/* 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).
} |