1

嗨,我已经编写了 char 驱动程序,一切正常,但是当我实现 ioctl 时调用它不起作用。我正在编写代码以通过 ioctl 调用来读写设备。这里是代码。

驱动代码ioctl.c

#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/fs.h> /*this is the file structure, file open read close */
#include<linux/cdev.h> /* this is for character device, makes cdev avilable*/
#include<linux/semaphore.h> /* this is for the semaphore*/
#include<linux/uaccess.h> /*this is for copy_user vice vers*/
#include <linux/errno.h>


#include "cioctl.h" /*my ioctl header file */

int chardev_init(void);
void chardev_exit(void);
static int device_open(struct inode *, struct file *);
static int device_close(struct inode *, struct file *);
static ssize_t device_read(struct file *, char *, size_t, loff_t *);
static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
static loff_t device_lseek(struct file *file, loff_t offset, int orig);
/*had some tough time, in making ioctl calls work. 
int ioctl_funcs(struct inode *inode, struct file *filp,unsigned int cmd, unsigned long arg)
has changed to 
long ioctl(struct file *filp,unsigned int cmd, unsigned long arg)
after 2.6.36*/
long device_ioctl(struct file *file, unsigned int ioctl_num , unsigned long  ioctl_parm);

/*new code*/
#define BUFFER_SIZE 1024
static char device_buffer[BUFFER_SIZE];
struct semaphore sem;
struct cdev *mcdev; /*this is the name of my char driver that i will be registering*/
int major_number; /* will store the major number extracted by dev_t*/
int ret; /*used to return values*/
dev_t dev_num; /*will hold the major number that the kernel gives*/

#define DEVICENAME "megharajchard"

/*inode reffers to the actual file on disk*/
static int device_open(struct inode *inode, struct file *filp) {
    if(down_interruptible(&sem) != 0) {
        printk(KERN_ALERT "megharajchard : the device has been opened by some other device, unable to open lock\n");
        return -1;
    }
    //buff_rptr = buff_wptr = device_buffer;
    printk(KERN_INFO "megharajchard : device opened succesfully\n");
    return 0;
}

static ssize_t device_read(struct file *fp, char *buff, size_t length, loff_t *ppos) {
    int maxbytes; /*maximum bytes that can be read from ppos to BUFFER_SIZE*/
    int bytes_to_read; /* gives the number of bytes to read*/
    int bytes_read;/*number of bytes actually read*/
    maxbytes = BUFFER_SIZE - *ppos;
    if(maxbytes > length) 
        bytes_to_read = length;
    else
        bytes_to_read = maxbytes;
    if(bytes_to_read == 0)
        printk(KERN_INFO "megharajchard : Reached the end of the device\n");
    bytes_read = bytes_to_read - copy_to_user(buff, device_buffer + *ppos, bytes_to_read);
    printk(KERN_INFO "megharajchard : device has been read %d\n",bytes_read);
    *ppos += bytes_read;
    printk(KERN_INFO "megharajchard : device has been read\n");
    return bytes_read;
}

static ssize_t device_write(struct file *fp, const char *buff, size_t length, loff_t *ppos) {
    int maxbytes; /*maximum bytes that can be read from ppos to BUFFER_SIZE*/
    int bytes_to_write; /* gives the number of bytes to write*/
    int bytes_writen;/*number of bytes actually writen*/
    maxbytes = BUFFER_SIZE - *ppos;
    if(maxbytes > length) 
        bytes_to_write = length;
    else
        bytes_to_write = maxbytes;
    bytes_writen = bytes_to_write - copy_from_user(device_buffer + *ppos, buff, bytes_to_write);
    printk(KERN_INFO "megharajchard : device has been written %d\n",bytes_writen);
    *ppos += bytes_writen;
    printk(KERN_INFO "megharajchard : device has been written\n");
    return bytes_writen;
}

static loff_t device_lseek(struct file *file, loff_t offset, int orig) {
    loff_t new_pos = 0;
    printk(KERN_INFO "megharajchard : lseek function in work\n");
    switch(orig) {
        case 0 : /*seek set*/
            new_pos = offset;
            break;
        case 1 : /*seek cur*/
            new_pos = file->f_pos + offset;
            break;
        case 2 : /*seek end*/
            new_pos = BUFFER_SIZE - offset;
            break;
    }
    if(new_pos > BUFFER_SIZE)
        new_pos = BUFFER_SIZE;
    if(new_pos < 0)
        new_pos = 0;
    file->f_pos = new_pos;
    return new_pos;
}

long device_ioctl(struct file* filp ,unsigned int ioctl_num , unsigned long  ioctl_parm) {
    /*dont eve decode wrong command*/
    if(_IOC_TYPE(ioctl_num) != IOCTL_MAGIC_NUMBER) {
        printk(KERN_INFO "megharajchard : ioctl majic number failed\n");
        return -ENOTTY;
    }
    if(_IOC_NR(ioctl_num) != IOCTL_MAGIC_MAX) return -ENOTTY;

    printk(KERN_INFO "megharajchard : ioctl method has been called\n");
    switch(ioctl_num) {
        case IOCTL_READ: 
                device_read(filp,(unsigned char *) ioctl_parm, BUFFER_SIZE, 0);
                    break;
        case IOCTL_WRITE:
                device_write(filp,(unsigned char *) ioctl_parm, BUFFER_SIZE, 0);
                    return -EFAULT;
                return 0;
        case IOCTL_HELLO : 
                printk(KERN_INFO "megharajchard : hello reading through ioctl calls\n");
                break;

    }
    return 0;
}


static int device_close(struct inode *inode, struct file *filp) {
    up(&sem);
    printk(KERN_INFO "megharajchard : device has been closed\n");
    return ret;
}

struct file_operations fops = { /* these are the file operations provided by our driver */
    .owner = THIS_MODULE, /*prevents unloading when operations are in use*/
    .open = device_open,  /*to open the device*/
    .write = device_write, /*to write to the device*/
    .read = device_read, /*to read the device*/
    .release = device_close, /*to close the device*/
    .llseek = device_lseek,/* to see the device*/
    .unlocked_ioctl = device_ioctl,/* to implement ioctl calls*/
};


int chardev_init(void) 
{
    /* we will get the major number dynamically this is recommended please read ldd3*/
    ret = alloc_chrdev_region(&dev_num,0,1,DEVICENAME);
    if(ret < 0) {
        printk(KERN_ALERT " megharajchard : failed to allocate major number\n");
        return ret;
    }
    else
        printk(KERN_INFO " megharajchard : mjor number allocated succesful\n");
    major_number = MAJOR(dev_num);
    printk(KERN_INFO "megharajchard : major number of our device is %d\n",major_number);
    printk(KERN_INFO "megharajchard : to use mknod /dev/%s c %d 0\n",DEVICENAME,major_number);

    mcdev = cdev_alloc(); /*create, allocate and initialize our cdev structure*/
    mcdev->ops = &fops;   /*fops stand for our file operations*/
    mcdev->owner = THIS_MODULE;

    /*we have created and initialized our cdev structure now we need to add it to the kernel*/
    ret = cdev_add(mcdev,dev_num,1);
    if(ret < 0) {
        printk(KERN_ALERT "megharajchard : device adding to the kerknel failed\n");
        return ret;
    }
    else
        printk(KERN_INFO "megharajchard : device additin to the kernel succesful\n");
    sema_init(&sem,1);  /* initial value to one*/

    return 0;
}

void chardev_exit(void)
{
    cdev_del(mcdev); /*removing the structure that we added previously*/
    printk(KERN_INFO " megharajchard : removed the mcdev from kernel\n");

    unregister_chrdev_region(dev_num,1);
    printk(KERN_INFO "megharajchard : unregistered the device numbers\n");
    printk(KERN_ALERT " megharajchard : character driver is exiting\n");
}
//MODULE_LICENCE("GPL");    
MODULE_AUTHOR("A G MEGHARAJ(agmegharaj@gmail.com)");
MODULE_DESCRIPTION("A BASIC CHAR DRIVER");

module_init(chardev_init);
module_exit(chardev_exit);

制作文件

obj-m   := ioctl.o

KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD       := $(shell pwd)

all:
    $(MAKE) -C $(KERNELDIR) M=$(PWD)

clean:
    rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions

加载脚本确保主编号正确,否则进行相应的更改。

#!/bin/sh

sudo insmod ioctl.ko
sudo mknod /dev/megharajchard c 250 0
sudo chmod 777 /dev/megharajchard

卸载脚本

#!/bin/sh

sudo rmmod ioctl
sudo rm /dev/megharajchard

ioctl 头文件 cioctl.h

#ifndef IOCTL_H
#define IOCTL_H
#include<linux/ioctl.h>

#define IOCTL_MAGIC_NUMBER 100
#define IOCTL_READ _IOR(IOCTL_MAGIC_NUMBER, 0, char *)
#define IOCTL_WRITE _IOW(IOCTL_MAGIC_NUMBER, 1, char *)
#define IOCTL_HELLO _IO(IOCTL_MAGIC_NUMBER, 2)

#define IOCTL_MAGIC_MAX 2

#endif

一个简单的c cppliaction看ioctl调用的操作

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>      /* open */
#include <unistd.h>     /* exit */
#include <sys/ioctl.h>      /* ioctl */
#include"cioctl.h"
#define DEVICE "/dev/megharajchard"

    int main()
    {
        int file_desc, ret_val;
        char *message = "My name is megharaj i am the owner of this device\n";
        char *answer;
        file_desc = open(DEVICE, O_RDWR);
        if(file_desc < 0)
            printf("failed to open the device \n");

        ret_val = ioctl(file_desc, IOCTL_WRITE, message);
        if(ret_val < 0)
            printf("failed to write the device \n");
        ret_val = ioctl(file_desc, IOCTL_READ,answer);
        if(ret_val < 0)
            printf("failed to write the device \n");
            printf("message read is %s  \n",answer);
        ret_val = ioctl(file_desc, IOCTL_HELLO,answer); /* only this command works*/
        close(file_desc);
        return 0;
    }

只有 IOCTL_HELLO 工作其他两个调用读取和写入设备缓冲区不工作

4

1 回答 1

4

这一行在device_ioctl()

if(_IOC_NR(ioctl_num) != IOCTL_MAGIC_MAX) return -ENOTTY;

正在测试您的 ioctl 幻数是否等于 IOCTL_MAGIC_MAX,这恰好仅适用于 IOCTL_HELLO。但是,如果您只是添加了更多调试语句来缩小确切的故障位置,您自己就会看到这一点。

编辑:读取调用中的另一个错误:您将未初始化的指针传递answer给读取 ioctl。 answer需要指向内核端的有效缓冲区copy_to_user()

于 2013-09-23T17:54:08.413 回答