- 论坛徽章:
- 0
|
哦,
这是头文件 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 proces calling ioctl (ioctl.c)
*/
#ifdef CHARDEV_H
#define CHARDEV_H
#include <linux/ioctl.h>
/*
* 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_MEG _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
这是主文件 chardev.c
/*
* chardev.c-- Create an input/output character device
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include "chardev.h"
#define SUCCESS 0
#define DEVICE_ANME "char_dev"
#define BUF_LEN 80
/*
* Is the device open right now ?
* Used to prevent concurrent access into the same device
*/
static int Device_Open = 0;
/*
* The message the device will given 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 is called whenever a process attempts to open the device file
*/
static int device_open(struct inode * inode, struct file * file)
{
#ifdef DEBUG
printk(KERN_INFO "devcie_open(%p)\n", file);
#endif
/*
* We don't want to talk to two processes at the same time
*/
if (Device_Open)
return -EBUSY;
Device_Open ++;
/*
* Initialize the message
*/
Message_Ptr = Message;
try_module_get(THIS_MODULE);
return SUCCESS;
}
static int device_release (struct inode *inode, struct file * file)
{
#ifdef DEBUG
printk(KERN_INFO "device_release (%p,%p)\n", inode, file);
#endif
/*
* We're now ready for our next caller
*/
Device_Open--;
module_put(THIS_MODULE);
return SUCCESS;
}
/*
* This function is called whenever a process which has already opened the
* device file attempts to read from it.
*/
static ssize_t device_read(struct file *file, /* see include /linux/fs.h */
char __user * buffer, /* buffer to be filled with data */
size_t length, /* length of the buffer */
ioff_t * offset)
{
/*
* Number of bytes actually written to the buffer
*/
int bytes_read = 0;
#ifdef DEBUG
printk(KERN_INFO "device_read(%p,%p,%d)\n", file, buffer, length);
#endif
/*
* If we're at the end of the message, return 0
* (whichd signifies end of the 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 would'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(KERN_INFO "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 devcie
* file
*/
static ssize_t
device_write(struct file *file,
const char __user * buffer, size_t length, loff_t * offset)
{
int i;
#ifdef DEBUG
printk(KERN_INFO "device_write(%p,%s,%d)", file, buffer, length)
#endif
for (i=0; i < length && i< BUF_LEN; i++)
get_user(Message, buffer + i);
Message_Ptr = Message;
/*
* Again, return the number of input charactres 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
* structure, which all device function get): the number of the ioctl called
* and the parameter given to the ioctl funciton.
*
* 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 , /* see include/linux/fs.h*/
struct file *file, /* ditto */
unsigned int ioctl_num, /* number and param for ioctl*/
unsigned long ioctl_param)
{
int i;
char *temp;
char ch;
/*
* 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
*/
get_user(ch, temp);
for (i=0; ch && i< BUF_LEN; i++, temp++)
get_user(ch, temp);
device_write(file, (char *)ioctl_param, i, 0);
break;
case IOCTL_GET_MSG:
/*
* Give the current message to the calling process-
* the parameter we got is pointer, fill it.
*/
i = device_read(file, (char *)ioctl_param, 99, 0);
/*
* 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
* device table, it can't be ioctl to
* init_module. NULL is for unimplemented functions.
*/
struct file_operations Fops = {
.read = device_read,
.write = device_write,
.ioctl = device_ioctl,
.open = device_open,
.release = device_release, /* a.k.a close*/
};
/*
* Initialize the moduel - Register the character device
*/
int init_module()
{
int ret_val;
/*
* Register the character device (at least try )
*/
ret_val = register_chrdev(MAJOR_NUM, DEVICE_NAME, & Fops);
/*
* Negative values signify an error
*/
if (ret_val < 0) {
printk(KERN_ALERT "%s failed with %d \n",
"Sorry, registering the character device", ret_val);
return ret_val;
}
printk(KERN_INFO "%s The major device number is %d.\n",
"Registeration is a success",MAJOR_NUM);
printk(KERN_INFO "If you want to talk to the device driver, \n");
printk(KERN_INFO "you'll have to create a device file.\n");
printk(KERN_INFO "we suggest you use:\n");
printk(KERN_INFO "mknod %s c %d 0 \n", DEVICE_FILE_NAME, MAJOR_NUM);
printk(KERN_INFO "The device file name is important, because \n");
printk(KERN_INFO "file you'll use.\n");
return 0;
}
/*
* Clean up -unregister the appropriater file from /proc
*/
void cleanup_module()
{
int ret;
/*
* Unregister the device
*/
ret = unregister_chrdev(MAJOR_NUM, DEVICE_NAME);
/*
* If there's an error, report it
*/
if (ret < 0)
printk(KERN_INFO "Error: unregister_chrdev: %d\n", ret);
}
这是Makefile
obj-m :=chardev.o
default:
$(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
$(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean |
|