пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ. пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅ пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ, пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅ пїЅпїЅпїЅпїЅ, пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ. пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ, пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅ пїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅ пїЅпїЅ, пїЅпїЅпїЅ пїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅ. пїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ, пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ device_write.

пїЅпїЅпїЅпїЅпїЅ пїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ. пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ, пїЅпїЅпїЅ пїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅ, пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ (пїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅ пїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ, пїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅ пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ CPU пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅ, пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ, пїЅпїЅпїЅ пїЅпїЅпїЅ пїЅпїЅ пїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ). пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ, пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ, пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ пїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ, пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ. пїЅпїЅпїЅпїЅпїЅпїЅ, пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅ пїЅпїЅпїЅ пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ, пїЅпїЅпїЅпїЅпїЅ пїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ, пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅ пїЅпїЅпїЅпїЅпїЅпїЅ.

пїЅпїЅпїЅпїЅпїЅ пїЅ Unix пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ, пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ ioctl (пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅ input output control). пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ ioctl, пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ ioctl (пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅ), пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ ioctl (пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ), пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅ пїЅпїЅ пїЅпїЅпїЅпїЅ пїЅпїЅ пїЅпїЅпїЅ. пїЅпїЅпїЅпїЅпїЅпїЅпїЅ ioctl пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅ пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ: пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ, ioctl пїЅпїЅпїЅпїЅпїЅ, пїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ, пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅ long, пїЅпїЅпїЅ пїЅпїЅпїЅ пїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ, пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅ-пїЅпїЅпїЅпїЅпїЅпїЅ.

Ioctl пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ, пїЅпїЅпїЅ ioctl пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅ пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ. пїЅпїЅпїЅпїЅ ioctl пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ (_IO, _IOR, _IOW пїЅпїЅпїЅ _IOWR: пїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅ пїЅпїЅпїЅпїЅ) пїЅ пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ. пїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ #include пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ, пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ ioctl пїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ (пїЅпїЅпїЅ пїЅпїЅпїЅ пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ ioctl). пїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅ, пїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ chardev.h пїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ, пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅ ioctl.c.

пїЅпїЅпїЅпїЅ пїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ ioctl пїЅ пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ, пїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ ioctl пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ, пїЅпїЅпїЅ, пїЅпїЅпїЅпїЅ пїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ ioctl пїЅпїЅпїЅпїЅ-пїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅ, пїЅпїЅпїЅ пїЅпїЅпїЅ-пїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ. пїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ, пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅ пїЅпїЅпїЅпїЅпїЅ `Documentation/ioctl-number.txt' пїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅпїЅ пїЅпїЅпїЅпїЅ.

chardev.cпїЅ

/* chardev.c

*

* Create an input/output character device

*/

/* Copyright (C) 1998-99 by Ori Pomerantz */

/* The necessary header files */

/* Standard in kernel modules */

#include /* We're doing kernel work */

#include /* Specifically, a module */

/* Deal with CONFIG_MODVERSIONS */

#if CONFIG_MODVERSIONS==1

#define MODVERSIONS

#include

#endif

/* For character devices */

/* The character device definitions are here */

#include

/* A wrapper which does next to nothing at

* at present, but may help for compatibility

* with future versions of Linux */

#include

/* Our own ioctl numbers */

#include "chardev.h"

/* In 2.2.3 /usr/include/linux/version.h includes a

* macro for this, but 2.0.35 doesn't - so I add it

* here if necessary. */

#ifndef KERNEL_VERSION

#define KERNEL_VERSION(a,b,c) ((a)*65536+(b)*256+(c))

#endif

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)

#include /* for get_user and put_user */

#endif

#define SUCCESS 0

/* Device Declarations ******************************** */

/* The name for our device, as it will appear inпїЅ/proc/devices */

#define DEVICE_NAME "char_dev"

/* The maximum length of the message for the device */

#define BUF_LEN 80

/* Is the device open right now? Used to preventпїЅconcurent access into the same device */

static int Device_Open = 0;

/* The message the device will give when asked */

static char Message[BUF_LEN];

/* How far did the process reading the message get?

* Useful if the message is larger than the size of the

* buffer we get to fill in device_read. */

static char *Message_Ptr;

/* This function is called whenever a process attemptsпїЅto open the device file */

static int device_open(struct inode *inode, struct file *file) {

#ifdef DEBUG

пїЅprintk("device_open(%p)\n", file);

#endif

пїЅ/* We don't want to talk to two processes at theпїЅ same time */

пїЅif (Device_Open) return -EBUSY;

пїЅ/* If this was a process, we would have had to be

пїЅ* more careful here, because one process might have

пїЅ* checked Device_Open right before the other one

пїЅ* tried to increment it. However, we're in the

пїЅ* kernel, so we're protected against context switches.

пїЅ*

пїЅ* This is NOT the right attitude to take, because we

пїЅ* might be running on an SMP box, but we'll deal with

пїЅ* SMP in a later chapter. */

пїЅDevice_Open++;

пїЅ/* Initialize the message */

пїЅMessage_Ptr = Message;

пїЅMOD_INC_USE_COUNT;

пїЅreturn SUCCESS;

}

/* This function is called when a process closes the

* device file. It doesn't have a return value because

* it cannot fail. Regardless of what else happens, you

* should always be able to close a device (in 2.0, a 2.2

* device file could be impossible to close). */

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)

static int device_release(struct inode *inode, struct file *file)

#else

static void device_release(struct inode *inode, struct file *file)

#endif

{

#ifdef DEBUG

пїЅprintk("device_release(%p,%p)\n", inode, file);

#endif

пїЅ/* We're now ready for our next caller */

пїЅDevice_Open--;

пїЅMOD_DEC_USE_COUNT;

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)

пїЅreturn 0;

#endif

}

/* This function is called whenever a process which

* has already opened the device file attempts toпїЅread from it. */

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)

static ssize_t device_read(

пїЅstruct file *file,

пїЅchar *buffer, /* The buffer to fill with the data */

пїЅsize_t length, /* The length of the buffer */

пїЅloff_t *offset) /* offset to the file */

#else

static int device_read(

пїЅstruct inode *inode,пїЅstruct file *file,

пїЅchar *buffer, /* The buffer to fill with the data */

пїЅint length) /* The length of the bufferпїЅ(mustn't write beyond that!) */

#endif

{

пїЅ/* Number of bytes actually written to the buffer */

пїЅint bytes_read = 0;

#ifdef DEBUG

пїЅprintk("device_read(%p,%p,%d)\n", file, buffer, length);

#endif

пїЅ/* If we're at the end of the message, return 0пїЅ(which signifies end of file) */

пїЅif (*Message_Ptr == 0) return 0;

пїЅ/* Actually put the data into the buffer */

пїЅwhile (length && *Message_Ptr) {

пїЅ /* Because the buffer is in the user data segment,

пїЅпїЅ* not the kernel data segment, assignment wouldn't

пїЅпїЅ* work. Instead, we have to use put_user which

пїЅпїЅ* copies data from the kernel data segment to the

пїЅпїЅ* user data segment. */

пїЅпїЅput_user(*(Message_Ptr++), buffer++);

пїЅпїЅlength--;

пїЅпїЅbytes_read++;

пїЅ}

#ifdef DEBUG

пїЅprintk("Read %d bytes, %d left\n", bytes_read, length);

#endif

пїЅ/* Read functions are supposed to return the number

пїЅ* of bytes actually inserted into the buffer */

пїЅreturn bytes_read;

}

/* This function is called when somebody tries toпїЅwrite into our device file. */

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)

static ssize_t device_write(struct file *file, const char *buffer, size_t length, loff_t *offset)

#else

static int device_write(struct inode *inode, struct file *file, const char *buffer, int length)

#endif

{

пїЅint i;

#ifdef DEBUG

пїЅprintk("device_write(%p,%s,%d)", file, buffer, length);

#endif

пїЅfor(i=0; i

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)

пїЅпїЅget_user(Message[i], buffer+i);

#else

пїЅпїЅMessage[i] = get_user(buffer+i);

#endif

пїЅMessage_Ptr = Message;

пїЅ/* Again, return the number of input characters used */

пїЅreturn i;

}

/* This function is called whenever a process tries to

* do an ioctl on our device file. We get two extra

* parameters (additional to the inode and file

* structures, which all device functions get): the number

* of the ioctl called and the parameter given to theпїЅioctl function.

*

* If the ioctl is write or read/write (meaning output

* is returned to the calling process), the ioctl call

* returns the output of this function. */

int device_ioctl(struct inode *inode, struct file *file,

пїЅunsigned int ioctl_num, /* The number of the ioctl */

пїЅunsigned long ioctl_param) /* The parameter to it */

{

пїЅint i;

пїЅchar *temp;

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)

пїЅchar ch;

#endif

пїЅ/* Switch according to the ioctl called */

пїЅswitch (ioctl_num) {

пїЅcase IOCTL_SET_MSG:

пїЅ /* Receive a pointer to a message (in user space)

пїЅпїЅ* and set that to be the device's message. */

пїЅпїЅ/* Get the parameter given to ioctl by the process */

пїЅпїЅtemp = (char*)ioctl_param;

пїЅпїЅ/* Find the length of the message */

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)

пїЅпїЅget_user(ch, temp);

пїЅпїЅfor (i=0; ch && i

#else

пїЅпїЅfor (i=0; get_user(temp) && i

#endif

пїЅпїЅ/* Don't reinvent the wheel - call device_write */

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)

пїЅпїЅdevice_write(file, (char*)ioctl_param, i, 0);

#else

пїЅ device_write(inode, file, (char*)ioctl_param, i);

#endif

пїЅпїЅbreak;

пїЅcase IOCTL_GET_MSG:

пїЅпїЅ/* Give the current message to the calling

пїЅпїЅ* process - the parameter we got is a pointer,пїЅfill it. */

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)

пїЅпїЅi = device_read(file, (char*)ioctl_param, 99, 0);

#else

пїЅпїЅi = device_read(inode, file, (char*)ioctl_param, 99);

#endif

пїЅпїЅ/* Warning - we assume here the buffer length is

пїЅпїЅ* 100. If it's less than that we might overflow

пїЅпїЅ* the buffer, causing the process to core dump.

пїЅпїЅ*

пїЅпїЅ* The reason we only allow up to 99 characters is

пїЅпїЅ* that the NULL which terminates the string alsoпїЅneeds room. */

пїЅпїЅ/* Put a zero at the end of the buffer, so itпїЅwill be properly terminated */

пїЅпїЅput_user('\0', (char*)ioctl_param+i);

пїЅпїЅbreak;

пїЅcase IOCTL_GET_NTH_BYTE:

пїЅпїЅ/* This ioctl is both input (ioctl_param) and

пїЅпїЅ* output (the return value of this function) */

пїЅпїЅreturn Message[ioctl_param];

пїЅпїЅbreak;

пїЅ}

пїЅreturn SUCCESS;

}

/* 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 can't be local to

* init_module. NULL is for unimplemented functions. */

struct file_operations Fops = {

пїЅNULL, /* seek */

пїЅdevice_read,

пїЅdevice_write,

пїЅNULL, /* readdir */

пїЅNULL, /* select */

пїЅ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 ("you'll 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 that's the\n");

пїЅprintk ("file you'll 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 there's an error, report it */

пїЅif (ret < 0) printk("Error in module_unregister_chrdev: %d\n", ret);

}

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 can't 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 we're 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 we're 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 n'th 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пїЅпїЅ

ioctl.cпїЅ

/* ioctl.c - the process to use ioctl's to control the

* kernel module

*

* Until now we could have used cat for input and

* output. But now we need to do ioctl's, 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 don't tell

пїЅ* the kernel how far it's 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 %d'th 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("Can't 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);

}