嗨,我相信这个问题可以通过我忽略的超级简单的东西来解决。这是我的头文件中的一个片段:
#ifndef COMBLOCKDEV_H
#define COMBLOCKDEV_H
#define BUFF_LEN 256 // depends on CB FIFO and RAM max depth but also available Linux RA
struct user_params{
int len;
int data[BUFF_LEN];
int reg;
};
#define COMBLOCK_IOC_MAGIC 'a'
#define COMBLOCK_IOC_RESET _IO(COMBLOCK_IOC_MAGIC, 0)
#define COMBLOCK_IOC_REG_READ _IOR(COMBLOCK_IOC_MAGIC, 1, struct params *)
#endif
我的内核代码加载和探测都很好。按预期打开和释放工作:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/ioctl.h>
#include <linux/io.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <asm/uaccess.h>
#include "comblock.h"
#define SUCCESS 0
static int device_open(struct inode *inode, struct file *file) {
struct comblock_local * lp;
pr_info("ComBlock_open(%p)n", file);
lp = container_of(inode->i_cdev, struct comblock_local, cdev);
file->private_data = lp;
return SUCCESS;
}
/* This is called whenever a process attempts to release the device file
We release the module and clear the queue entry.for asynchronous notifications.
*/
static int device_release(struct inode *inode, struct file *file) {
struct comblock_local * lp = (struct comblock_local*) file->private_data;
pr_info("ComBlock_release(%p,%p)n", inode, file);
if(!lp->async_queue)
device_fasync(-1, file, 0);
return SUCCESS;
}
static long int device_ioctl(struct file *file, unsigned int cmd, unsigned long ioctl_param) {
int ret = SUCCESS;
struct comblock_local * lp = file->private_data;
struct user_params params;
printk(KERN_INFO "Comblock: IOCTL command %d", cmd);
printk(KERN_INFO "Comblock: IOCTL command magic %c", COMBLOCK_IOC_MAGIC);
printk(KERN_INFO "Comblock: IOCTL command max %d", COMBLOCK_IOC_MAXNR);
printk(KERN_INFO "Comblock: IOCTL command dir %d", _IOC_DIR(cmd));
if (_IOC_TYPE(cmd) != COMBLOCK_IOC_MAGIC)
return -ENOTTY;
if (_IOC_NR(cmd) > COMBLOCK_IOC_MAXNR)
return -ENOTTY;
if(_IOC_DIR(cmd) & _IOC_READ)
ret = !access_ok((void __user*) ioctl_param, _IOC_SIZE(cmd));
else if(_IOC_DIR(cmd) & _IOC_WRITE)
ret = !access_ok((void __user*) ioctl_param, _IOC_SIZE(cmd));
if(ret)
return -EFAULT;
if(down_interruptible(&lp->sem))
return -ERESTARTSYS;
printk(KERN_INFO "Comblock: Command %d", cmd);
/* Switch according to the ioctl called */
switch (cmd) {
case COMBLOCK_IOC_RESET:
break;
}
return ret;
}
测试应用程序如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include "comblock.h"
int main() {
struct params test;
int ret, i;
int dev = open("/dev/comblock_dev0", O_RDWR);
if(dev == -1) {
printf("Opening was not possible! error: %dn",dev);
return -1;
}
printf("Trying to reset the CB: %d", ioctl(dev, COMBLOCK_IOC_RESET));
return 0;
}
测试应用程序和内核模块使用相同的头,所以我认为IOCTL命令是有效的。问题是测试应用程序中的ioctl()
总是返回-1,并且内核日志中不会打印来自内核模块的printk。因此,在一次测试后,dmesg
显示:
[11936.248350] Start ComBlock. ver.0.01
[11936.248589] comblock_dev 80000000.comblock: Device Tree Probing
[11936.248632] comblock_dev 80000000.comblock: Registering cdev.
[11936.248681] comblock_dev 80000000.comblock: ComBlock allocate cdev 510 0
[11936.248828] comblock_dev 80000000.comblock: Comblock detected with the following parameters:
[11936.248835] comblock_dev 80000000.comblock: Enables: OReg 1, IReg 1, IFIFO 1, OFIFO 1, RAM 1
[11936.248840] comblock_dev 80000000.comblock: Length: OReg 4, IReg 4, IFIFO 1024, OFIFO 1024, RAM 100
[11938.005460] ComBlock_open(00000000abab92a2)
[11938.005741] ComBlock_release(000000001d0f0893,00000000abab92a2)
我可以确认打开和释放工作,但IOCTL被忽略了。我怀疑中间部分有一个问题,但我真的不明白如何调试它
编辑:添加了file_operations结构、platform_driver、of_device_id和模块初始化函数
static struct file_operations comblock_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = device_ioctl,
.open = device_open,
.release = device_release,
.fasync = device_fasync
};
static int comblock_init(void) {
printk(KERN_INFO "Start ComBlock. ver.0.01");
return platform_driver_register(&comblock_driver);
}
#ifdef CONFIG_OF
static struct of_device_id comblock_of_match[] __devinitdata = {
{ .compatible = "ictp,comblock-1.0" },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, comblock_of_match);
#else
#define comblock_of_match
#endif
static struct platform_driver comblock_driver = {
.driver = {
.name = DEVICE_NAME,
.owner = THIS_MODULE,
.of_match_table = comblock_of_match,
},
.probe = device_probe,
.remove = device_remove,
};
模块和设备在启动后加载,这里是探针功能:
/* Probe device tree to retrieve parameters */
static int device_probe(struct platform_device *pdev) {
struct resource *axi_l, *axi_f; /* IO mem resources */
struct device *dev = &pdev->dev;
struct comblock_local *lp = NULL;
unsigned int reg_in_enable;
unsigned int reg_in_width;
unsigned int reg_in_length;
unsigned int reg_out_enable;
unsigned int reg_out_width;
unsigned int reg_out_length;
unsigned int fifo_in_enable;
unsigned int fifo_in_length;
unsigned int fifo_in_width;
unsigned int fifo_out_enable;
unsigned int fifo_out_length;
unsigned int fifo_out_width;
unsigned int ram_enable;
unsigned int ram_length;
unsigned int ram_width;
int ret = 0;
int mem_index = 0;
/////////////////////////// Probing Device Tree ///////////////////////////////////////
dev_info(dev, "Device Tree Probingn");
// load parameters into the structure
{
ret = device_property_count_u32(dev, "reg-in-enable");
if (ret <= 0) {
dev_err(dev, "init property missing or empty");
return ret ? ret : -ENODATA;
}
ret = device_property_read_u32(dev, "reg-in-enable", ®_in_enable);
if (ret)
return ret;
ret = device_property_count_u32(dev, "reg-in-length");
if (ret <= 0) {
dev_err(dev, "init property missing or empty");
return ret ? ret : -ENODATA;
}
ret = device_property_read_u32(dev, "reg-in-length", ®_in_length);
if (ret)
return ret;
ret = device_property_count_u32(dev, "reg-in-width");
if (ret <= 0) {
dev_err(dev, "init property missing or empty");
return ret ? ret : -ENODATA;
}
ret = device_property_read_u32(dev, "reg-in-width", ®_in_width);
if (ret)
return ret;
ret = device_property_count_u32(dev, "reg-out-enable");
if (ret <= 0) {
dev_err(dev, "init property missing or empty");
return ret ? ret : -ENODATA;
}
ret = device_property_read_u32(dev, "reg-out-enable", ®_out_enable);
if (ret)
return ret;
ret = device_property_count_u32(dev, "reg-out-length");
if (ret <= 0) {
dev_err(dev, "init property missing or empty");
return ret ? ret : -ENODATA;
}
ret = device_property_read_u32(dev, "reg-out-length", ®_out_length);
if (ret)
return ret;
ret = device_property_count_u32(dev, "reg-out-width");
if (ret <= 0) {
dev_err(dev, "init property missing or empty");
return ret ? ret : -ENODATA;
}
ret = device_property_read_u32(dev, "reg-out-width", ®_out_width);
if (ret)
return ret;
ret = device_property_count_u32(dev, "fifo-in-enable");
if (ret <= 0) {
dev_err(dev, "init property missing or empty");
return ret ? ret : -ENODATA;
}
ret = device_property_read_u32(dev, "fifo-in-enable", &fifo_in_enable);
if (ret)
return ret;
ret = device_property_count_u32(dev, "fifo-in-length");
if (ret <= 0) {
dev_err(dev, "init property missing or empty");
return ret ? ret : -ENODATA;
}
ret = device_property_read_u32(dev, "fifo-in-length", &fifo_in_length);
if (ret)
return ret;
ret = device_property_count_u32(dev, "fifo-in-width");
if (ret <= 0) {
dev_err(dev, "init property missing or empty");
return ret ? ret : -ENODATA;
}
ret = device_property_read_u32(dev, "fifo-in-width", &fifo_in_width);
if (ret)
return ret;
ret = device_property_count_u32(dev, "fifo-out-enable");
if (ret <= 0) {
dev_err(dev, "init property missing or empty");
return ret ? ret : -ENODATA;
}
ret = device_property_read_u32(dev, "fifo-out-enable", &fifo_out_enable);
if (ret)
return ret;
ret = device_property_count_u32(dev, "fifo-out-length");
if (ret <= 0) {
dev_err(dev, "init property missing or empty");
return ret ? ret : -ENODATA;
}
ret = device_property_read_u32(dev, "fifo-out-length", &fifo_out_length);
if (ret)
return ret;
ret = device_property_count_u32(dev, "fifo-out-width");
if (ret <= 0) {
dev_err(dev, "init property missing or empty");
return ret ? ret : -ENODATA;
}
ret = device_property_read_u32(dev, "fifo-out-width", &fifo_out_width);
if (ret)
return ret;
ret = device_property_count_u32(dev, "ram-enable");
if (ret <= 0) {
dev_err(dev, "init property missing or empty");
return ret ? ret : -ENODATA;
}
ret = device_property_read_u32(dev, "ram-enable", &ram_enable);
if (ret)
return ret;
ret = device_property_count_u32(dev, "ram-length");
if (ret <= 0) {
dev_err(dev, "init property missing or empty");
return ret ? ret : -ENODATA;
}
ret = device_property_read_u32(dev, "ram-length", &ram_length);
if(ret)
return ret;
ret = device_property_count_u32(dev, "ram-width");
if (ret <= 0) {
dev_err(dev, "init property missing or empty");
return ret ? ret : -ENODATA;
}
ret = device_property_read_u32(dev, "ram-width", &ram_width);
if (ret)
return ret;
}
////////////////////////// allocating local data structure /////////////////////////////
lp = (struct comblock_local *) kzalloc(sizeof(struct comblock_local), GFP_KERNEL);
if (!lp) {
dev_err(dev, "Cound not allocate comblock devicen");
return -ENOMEM;
}
lp->reg_in_enable = reg_in_enable;
lp->reg_in_length = reg_in_length;
lp->reg_in_width = reg_in_width;
lp->reg_out_enable = reg_out_enable;
lp->reg_out_length = reg_out_length;
lp->reg_out_width = reg_out_width;
lp->fifo_in_enable = fifo_in_enable;
lp->fifo_in_length = fifo_in_length;
lp->fifo_in_width = fifo_in_width;
lp->fifo_out_enable = fifo_out_enable;
lp->fifo_out_length = fifo_out_length;
lp->fifo_out_width = fifo_out_width;
lp->ram_enable = ram_enable;
lp->ram_length = ram_length;
lp->ram_width = ram_width;
/* register the device memory */
if(lp->reg_in_enable || lp->reg_out_enable || lp->fifo_in_enable || lp->fifo_out_enable) {
axi_l = platform_get_resource(pdev, IORESOURCE_MEM, mem_index);
mem_index++;
if(!axi_l) {
ret= -ENOMEM;
goto out_free_local;
}else if(!request_mem_region(axi_l->start, axi_l->end - axi_l->start + 1, DEVICE_NAME)) {
dev_err(dev, "Couldn't lock memory region at %llun", axi_l->start);
ret = -EBUSY;
goto out_free_local;
}
lp->axi_l = axi_l;
lp->axi_l_base_addr = ioremap(axi_l->start, axi_l->end - axi_l->start + 1);
}
if(lp->ram_enable) {
axi_f = platform_get_resource(pdev, IORESOURCE_MEM, mem_index);
if(!axi_f) {
ret= -ENOMEM;
goto out_free_local;
}else if(!request_mem_region(axi_f->start, axi_f->end - axi_f->start + 1, DEVICE_NAME)) {
dev_err(dev, "Couldn't lock memory region at %llun", axi_f->start);
ret = -EBUSY;
goto out_free_local;
}
lp->axi_f = axi_f;
lp->axi_f_base_addr = ioremap(axi_f->start, axi_f->end - axi_f->start + 1);
}
dev_set_drvdata(dev, lp);
if(!lp->axi_l_base_addr && !lp->axi_f_base_addr) {
dev_err(dev, "Could not allocate iomemn");
ret = -EIO;
goto out_free_mem_region;
}
///////////////////////// initializing char device /////////////////////////////////
ret = comblock_cdev_init(dev, lp);
if(ret < 0) {
dev_err(dev, "Could not create cdev n");
goto out_free_iomap;
}
sema_init(&lp->sem, 1);
dev_info(dev, "Comblock detected with the following parameters: n");
dev_info(dev, "Enables: OReg %d, IReg %d, IFIFO %d, OFIFO %d, RAM %d n", lp->reg_in_enable, lp->reg_out_enable, lp->fifo_in_enable, lp->fifo_out_enable, lp->ram_enable);
dev_info(dev, "Length: OReg %d, IReg %d, IFIFO %d, OFIFO %d, RAM %d n", lp->reg_in_length, lp->reg_out_length, lp->fifo_in_length, lp->fifo_out_length, lp->ram_length);
return 0;
out_free_iomap:
if(lp->axi_l_base_addr)
iounmap(lp->axi_l_base_addr);
if(lp->axi_f_base_addr)
iounmap(lp->axi_f_base_addr);
out_free_mem_region:
if(axi_l)
release_mem_region(axi_l->start, axi_l->end - axi_l->start + 1);
if(axi_f)
release_mem_region(axi_f->start, axi_f->end - axi_f->start + 1);
out_free_local:
kfree(lp);
dev_set_drvdata(dev, NULL);
return ret;
}
以下是chardev:的初始化
/*Initialize the chardevice*/
static int comblock_cdev_init(struct device * dev, struct comblock_local * lp) {
dev_t devno;
int ret = 0;
struct device *device = NULL;
dev_info(dev, "Registering cdev.");
if(lp->major) {
devno = MKDEV(lp->major, lp->minor);
ret = register_chrdev_region(devno, comblock_nr_devs, DEVICE_NAME);
} else {
ret = alloc_chrdev_region(&devno, lp->minor, comblock_nr_devs, DEVICE_NAME);
lp->major = MAJOR(devno);
}
dev_info(dev, "ComBlock allocate cdev %d %d", lp->major, lp->minor);
if(ret < 0) {
dev_warn(dev, " can't get major %dn", lp->major);
return ret;
}
cdev_init(&lp->cdev, &comblock_fops);
lp->cdev.owner = THIS_MODULE;
ret = cdev_add(&lp->cdev, devno, 1);
if(ret) {
dev_notice(dev, "Error %d adding %s%d", ret, DEVICE_NAME, 0);
goto out_creg;
}
comblock_class = class_create(THIS_MODULE, DEVICE_NAME);
if (IS_ERR(comblock_class)) {
ret = PTR_ERR(comblock_class);
goto out_cadd;
}
device = device_create(comblock_class, NULL, /* no parent device */
devno, NULL, /* no additional data */
DEVICE_NAME "%d", lp->minor);
if (IS_ERR(device)) {
ret = PTR_ERR(device);
printk(KERN_WARNING "[target] Error %d while trying to create %s%d", ret, DEVICE_NAME, lp->minor);
goto out_class;
}
return 0;
out_class:
class_destroy(comblock_class);
out_cadd:
cdev_del(&lp->cdev);
out_creg:
unregister_chrdev_region(MKDEV(lp->major, lp->minor), comblock_nr_devs);
return ret;
}
第2版:在ioctl调用后,添加了解码测试应用程序中问题的错误。
ioctl: Inappropriate ioctl for device
我想这可能意味着我的标题中的神奇数字可能是重复的?我目前正在测试COMBLOCK_IOC_RESET参数,它不接受参数,所以它应该排除参数格式错误的可能性,对吗?
第三版:多亏了@racid-k,我们确定问题出在一个有32位用户空间的64内核上。只需检查内核的uname-m和用户空间的getconf LONG_BIT?最后,通过将unlocked_octl更改为compat_iotl解决了这个问题。
现在我已经成功地获得了一个分段错误。新错误意味着进步。非常感谢:(
Edit3:多亏了@racid-k,我们确定问题是64位内核而不是32位用户空间。
只需检查内核的uname -m
和用户空间的getconf LONG_BIT
。
通过将unlocked_ioctl
更改为compat_ioctl
解决了该问题。
现在我已经成功地获得了一个分段错误。新错误意味着进步。非常感谢:(