嗨,我已经编写了 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 工作其他两个调用读取和写入设备缓冲区不工作