2013-09-23 99 views
1

嗨我写了字符驱动程序,一切工作正常,但是当我执行ioctl调用它不工作。我正在编写通过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([email protected])"); 
MODULE_DESCRIPTION("A BASIC CHAR DRIVER"); 

module_init(chardev_init); 
module_exit(chardev_exit); 

make文件

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作品另外两个叫做阅读第二写入装置缓冲不在device_ioctl()工作

+3

定义“不工作” – Peter

+0

IOCTL_READ和IOCTL_WRITE我正在调用设备读取和设备写入功能,但没有输出。设备在没有读或写的情况下打开和关闭 – Megharaj

+0

为什么使用'ioctl()'来读写,而不是'read()'和'write()'? –

回答

4

这条线:

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

正在测试,看看你的ioctl幻数等于IOCTL_MAGIC_MAX,这恰好只为IOCTL_HELLO是真实的。但是如果您只是添加了更多的调试语句来缩小确切的故障位置,您会发现自己。

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

+0

是的你是对的。这就是为什么device_read和device_write函数没有被调用的问题。虽然它没有显示出一些错误。我会尝试调试它。 – Megharaj