现在的位置: 首页 > 综合 > 正文

2008 May 12th Monday (五月 十二日 月曜日)

2014年03月12日 ⁄ 综合 ⁄ 共 8308字 ⁄ 字号 评论关闭
There is a example of talking with ioctl().

/*
* chardev.c - Create an input/output character device
*/
#include <linux/kernel.h> /*We're doing kernel work*/
#include <linux/module.h> /*Specifically, a module*/
#include <linux/fs.h>
#include <asm/uaccess.h> /*for get_user and put_user*/
#include "chardev.h"

#define SUCCESS 0
#define DEVICE_NAME "char_dev"
#define BUF_LEN 80

/*
* Is the device open right now? Usedtoprevent
* 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 is called whenever a process attempts to open the device file
*/
static int device_open(struct inode *inode, struct file *file){
#ifdefDEBUG
    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;
       
    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){
#ifdefDEBUG
    printk("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, /*seeinclude/linux/fs.h */
    char__user *buffer, /*buffer to be filled with data*/
    size_t length, /*length of the buffer */
    loff_t *offset)
{
    /*
    * Number of bytes actually written to the buffer
    */
    int bytes_read=0;
#ifdefDEBUG
    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, assignmentwouldn'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++;
    }
#ifdefDEBUG
    printk("Read%dbytes,%dleft/n",bytes_read,length);
#endif

    /*
    * Read functions are supposed to return the number
    * of bytes actually insertedintothebuffer
    */
    return bytes_read;
}

/*
* This function is called when somebody tries to
* write into our device file.
*/
staticssize_t device_write(struct file *file,
    const char__user *buffer, size_t length, loff_t *offset)
{
    int i;
#ifdefDEBUG
    printk("device_write(%p,%s,%d)",file,buffer,length);
#endif

    for(i=0;i<length && i<BUF_LEN;i++)
        get_user(Message[i],buffer+i);
   
    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 outputofthisfunction.
*
*/
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 givento
        * 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 a 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;
}

/*
* This structure will hold the functions to be called
* when a process does something to the device we
* created. Since a pointer to this structureiskeptin
* the devices table, it can't be local to
* init_module. NULL is for unimplemented functions.
*/
struct file_operationsFops={
    .read=device_read,
    .write=device_write,
    .ioctl=device_ioctl,
    .open= device_open,
    .release=device_release, /*a.k.a.close*/
};

int init_module()
{
    int ret_val;
    /*
    * Register the character device (atleast try)
    */
    ret_val=register_chrdev(MAJOR_NUM,DEVICE_NAME,&Fops);
    /*
    * Negative values signify an error
    */
    if(ret_val<0){
        printk("%sfailedwith%d/n",
        "Sorry,registeringthecharacterdevice",ret_val);
        return ret_val;
    }
    printk("%sThe major device number is%d./n", "Registerationisasuccess",MAJOR_NUM);
    printk("If you want to talk to the device driver,/n");
    printk("you'llhavetocreateadevicefile. /n");
    printk("We suggest you use:/n");
    printk("mknod%s c%d0/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;
}

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("Error in module_unregister_chrdev:%d/n",ret);
}

/*
* 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
* (inchardev.c)and the process calling ioctl(ioctl.c)
*/

#ifndef 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_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 */

#include "chardev.h"
#include <fcntl.h> /*open*/
#include <unistd.h> /*exit*/
#include <sys/ioctl.h> /*ioctl*/

ioctl_set_msg(intfile_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(intfile_desc)
{
    int ret_val;
    char message[100];
    /*
    * Warning - this is dangerous because wedon't tell
    * the kernel how far it's allowed to write, so it
    * might overflow the buffer. Inarealproduction
    * program, we would have used two ioctls - onetotell
    * 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(intfile_desc)
{
    int i;
    char c;
   
    printf("get_nth_bytemessage:");
   
    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()
{
    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);
}

抱歉!评论已关闭.