IOCTL 调用无法写入设备中注册

问题描述 投票:0回答:1

我有内存映射的 Verilog ip,我想通过实现 ioctl 调用来控制它。它由 4 个 LED 组成,当控制寄存器 [BLINK_CTRL_REG] 切换为“1”时,这些 LED 会闪烁。 我正在编写一个简单的代码来通过 ioctl 调用写入设备。这是代码。

驱动程序代码blink.c

/*
# Copyright 2021 Xilinx Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
*/
/*  blink.c - The simplest kernel module.
 */
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>

#include <linux/fs.h>

#include <linux/slab.h>
#include <linux/io.h>
#include <linux/interrupt.h>

#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>

#include <asm/uaccess.h> /* for get_user and put_user */
#include <asm/io.h>
#include "blink.h"
#define SUCCESS 0
#define DEVICE_NAME "/dev/blink_Dev"


#define BLINK_CTRL_REG  0x43C00000
static unsigned long *mmio;
static int major_num;

/*
* Is the device open right now? Used to prevent
* concurent access into the same device
*/
static int Device_Open = 0;


static void set_blink_ctrl(void)
{
    printk("KERNEL PRINT : set_blink_ctrl \n\r");
    *(unsigned int *)mmio = 0x1;
}



static void reset_blink_ctrl(void)
{

    printk("KERNEL PRINT : reset_blink_ctrl \n\r");
    *(unsigned int *)mmio = 0x0;
}
/*
* This is called whenever a process attempts to open the device file
*/
static int device_open(struct inode *inode, struct file *file)
{
    #ifdef DEBUG
        printk(KERN_INFO "MY JONATHAN 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)
{
    #ifdef DEBUG
        printk(KERN_INFO "MY JONATHAN 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, /* see include/linux/fs.h */
                            char __user * buffer, /* buffer to be filled with data */
                            size_t length, /* length of the buffer */
                            loff_t * offset)
{
    return SUCCESS;
}
/*
* This function is called when somebody tries to
* write into our device file.
*/
static ssize_t device_write(struct file *file,
                            const char __user * buffer, 
                            size_t length, 
                            loff_t * offset)
{
    return SUCCESS;
}
/*
* 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 output of this function.
*
*/
long device_ioctl(          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_ON_LED:
        
        temp = (char *)ioctl_param;
        printk("KERNEL PRINT : before call ioctl ON \n\r");
        set_blink_ctrl();
        printk("KERNEL PRINT : after call ioctl ON \n\r");
    break;
    case IOCTL_STOP_LED:
        temp = (char *)ioctl_param;
        reset_blink_ctrl();
    break;
    
    }
    return SUCCESS;
}
/* Module Declarations */
/*
* This structure will hold the functions to be called
* when a process does something to the device we
* created. Since a pointer to this structure is kept in
* the devices table, it can't be local to
* init_module. NULL is for unimplemented functions.
*/
struct file_operations Fops = {
                                .owner = THIS_MODULE,       
                                .read = device_read,
                                .write = device_write,
                                .unlocked_ioctl = device_ioctl,
                                .open = device_open,
                                .release = device_release, /*close */                               
                            };

/* Standard module information, edit as appropriate */
MODULE_LICENSE("GPL");
MODULE_AUTHOR
    ("Xilinx Inc.");
MODULE_DESCRIPTION
    ("blink - loadable module template generated by petalinux-create -t modules");

#define DRIVER_NAME "blink"

/* Simple example of how to receive command line parameters to your module.
   Delete if you don't need them */
unsigned myint = 0xdeadbeef;
char *mystr = "default";

module_param(myint, int, S_IRUGO);
module_param(mystr, charp, S_IRUGO);

struct blink_local {
    int irq;
    unsigned long mem_start;
    unsigned long mem_end;
    void __iomem *base_addr;
};

static irqreturn_t blink_irq(int irq, void *lp)
{
    printk("blink interrupt\n");
    return IRQ_HANDLED;
}

static int blink_probe(struct platform_device *pdev)
{
        int rc = 0;
    struct resource *r_irq; /* Interrupt resources */
    struct resource *r_mem; /* IO mem resources */
    struct device *dev = &pdev->dev;
    struct blink_local *lp = NULL;
     

    dev_info(dev, "Device Tree Probing\n");

    /* Get iospace for the device */
    r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    if (!r_mem) {
        dev_err(dev, "invalid address\n");
        return -ENODEV;
    }
    
    lp = (struct blink_local *) kmalloc(sizeof(struct blink_local), GFP_KERNEL);
    if (!lp) {
        dev_err(dev, "Cound not allocate blink device\n");
        return -ENOMEM;
    }
    
    dev_set_drvdata(dev, lp);
    
    lp->mem_start = r_mem->start;
    lp->mem_end = r_mem->end;

    if (!request_mem_region(lp->mem_start,
                lp->mem_end - lp->mem_start + 1,
                DRIVER_NAME)) {
        dev_err(dev, "Couldn't lock memory region at %p\n",
            (void *)lp->mem_start);
        rc = -EBUSY;
        goto error1;
    }

    lp->base_addr = ioremap(lp->mem_start, lp->mem_end - lp->mem_start + 1);
    if (!lp->base_addr) {
        dev_err(dev, "blink: Could not allocate iomem\n");
        rc = -EIO;
        goto error2;
    }

    /* Get IRQ for the device */
    r_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
    if (!r_irq) {
        dev_info(dev, "no IRQ found\n");
        dev_info(dev, "blink at 0x%08x mapped to 0x%08x\n",
            (unsigned int __force)lp->mem_start,
            (unsigned int __force)lp->base_addr);
        return 0;
    }
    lp->irq = r_irq->start;
    
    rc = request_irq(lp->irq, &blink_irq, 0, DRIVER_NAME, lp);
    if (rc) {
        dev_err(dev, "testmodule: Could not allocate interrupt %d.\n",
            lp->irq);
        goto error3;
    }

    dev_info(dev,"blink at 0x%08x mapped to 0x%08x, irq=%d\n",
        (unsigned int __force)lp->mem_start,
        (unsigned int __force)lp->base_addr,
        lp->irq);
    return 0;
error3:
    free_irq(lp->irq, lp);
error2:
    release_mem_region(lp->mem_start, lp->mem_end - lp->mem_start + 1);
error1:
    kfree(lp);
    dev_set_drvdata(dev, NULL);


    return rc;
}

static int blink_remove(struct platform_device *pdev)
{
    struct device *dev = &pdev->dev;
    struct blink_local *lp = dev_get_drvdata(dev);
    free_irq(lp->irq, lp);
    release_mem_region(lp->mem_start, lp->mem_end - lp->mem_start + 1);
    kfree(lp);
    dev_set_drvdata(dev, NULL);
    return 0;
}

#ifdef CONFIG_OF
static struct of_device_id blink_of_match[] = {
    { .compatible = "vendor,blink", },
    { /* end of list */ },
};
MODULE_DEVICE_TABLE(of, blink_of_match);
#else
# define blink_of_match
#endif


static struct platform_driver blink_driver = {
    .driver = {
        .name = DRIVER_NAME,
        .owner = THIS_MODULE,
        .of_match_table = blink_of_match,
    },
    .probe      = blink_probe,
    .remove     = blink_remove,
};

static int __init blink_init(void)
{
        int rc = 0;
    printk("<1>Hello module world.\n");
    printk("<1>Module parameters were (0x%08x) and \"%s\"\n", myint,mystr);

    /*
    * Register the character device (atleast try)
    */
    major_num = register_chrdev(0,DEVICE_NAME, &Fops);

    /*
    * Negative values signify an error
    */
    if (major_num < 0) 
    {
        printk(KERN_ALERT "%s failed with \n","Sorry, registering the character device ");
    }
    
    mmio = ioremap(BLINK_CTRL_REG,0x100);
        
        printk("%s: Registers mapped to mmio = 0x%x  \n",__FUNCTION__,mmio);
    
        printk(KERN_INFO "%s the major device number is %d.\n","Registeration is a success", major_num);
    printk(KERN_INFO "If you want to talk to the device driver,\n");
    printk(KERN_INFO "create a device file by following command. \n \n");
    printk(KERN_INFO "mknod %s c %d 0\n\n", DEVICE_NAME, major_num);
    printk(KERN_INFO "The device file name is important, because\n");
    printk(KERN_INFO "the ioctl program assumes that's the file you'll use\n");

    rc =  platform_driver_register(&blink_driver);

        return rc;
}


static void __exit blink_exit(void)
{
        unregister_chrdev(major_num,DEVICE_NAME);
    platform_driver_unregister(&blink_driver);
    printk(KERN_ALERT "Goodbye module world.\n");
}

module_init(blink_init);
module_exit(blink_exit);

ioctl头文件blink.h

/*
# Copyright 2021 Xilinx Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
*/

/*
* blink.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
* (in chardev.c) and the process calling ioctl (ioctl.c)
*/
#ifndef BLINK_H
#define BLINK_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 MAGIC_NUM 241
/*
* TURN ON LED ioctl
*/
#define IOCTL_ON_LED _IOR(MAGIC_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, MAGIC_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.
*/
/*
* STOP LED BLINK ioctl
*/
#define IOCTL_STOP_LED _IOR(MAGIC_NUM, 1, char *)

#define DEBUG

#define DEVICE_FILE_NAME "/dev/blink_Dev"
#endif

我写了一个简单的c应用程序

/*
# Copyright 2021 Xilinx Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
*/

/*
* ioctl.c - the process to use ioctl's to control the kernel module
*
* Until now we could have used cat for input and output. But now
* we need to do ioctl's, which require writing our own process.
*/
/*
* device specifics, such as ioctl numbers and the
* major device file.
*/
#include "blink.h"
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h> /* open */
#include <unistd.h> /* exit */
#include <sys/ioctl.h> /* ioctl */
/*
* Functions for the ioctl calls
*/
void ioctl_ON_LED(int file_desc)
{
    int ret_val;
    int buff[0];
    buff[0] = 0x1; 
    ret_val = ioctl(file_desc, IOCTL_ON_LED, NULL);
    
    if (ret_val < 0)
    {
        printf("ioctl_ON_LED failed:%d\n", ret_val);
        exit(-1);
    }
}
void ioctl_OFF_LED(int file_desc)
{
    int ret_val;
    ret_val = ioctl(file_desc, IOCTL_STOP_LED,NULL);
    if (ret_val < 0)
    {
        printf("ioctl_OFF_LED failed:%d\n", ret_val);
        exit(-1);
    }
}
/*
* Main - Call the ioctl functions
*/
int main()
{
    int Choice;
    int exitflag=1;
    int file_desc;


    printf("################################ \n\r");
    printf("      Blink LED Application  \n\r");
    printf("################################ \n\r");
    file_desc = open(DEVICE_FILE_NAME, O_RDWR | O_SYNC);
    if (file_desc < 0)
    {
        printf("Can't open device file: %s\n", DEVICE_FILE_NAME);
        exit(-1);
    }
    while (exitflag)
    {
        printf("************************************************ \n\r");
        printf("Press '1' to Start Blink LED TEST \n\r");
        printf("Press '0' to Stop Blink LED TEST \n\r");
        printf("************************************************ \n\r");
        scanf("%d",&Choice);
        printf("Choice  :: %d \n\r",Choice);
        if(Choice == 1)
        {
            ioctl_ON_LED(file_desc);
            exitflag    = 1;
        }
        else if (0 == Choice )
        {
            ioctl_OFF_LED(file_desc);
            exitflag    = 1;
        }
        else
        {
            exitflag    = 0;

        }
    }

    close(file_desc);
    printf("################################ \n\r");
    printf("      Bye Blink LED Application  \n\r");
    printf("################################ \n\r");
    return 0;
}

这是 bitbake 文件:

SUMMARY = "Recipe for  build an external blink Linux kernel module"
SECTION = "PETALINUX/modules"
LICENSE = "GPLv2"
LIC_FILES_CHKSUM = "file://COPYING;md5=12f884d2ae1ff87c09e5b7ccc2c4ca7e"

inherit module

INHIBIT_PACKAGE_STRIP = "1"

SRC_URI = "file://Makefile \
           file://blink.c \
       file://blink.h \
       file://COPYING \
          "

S = "${WORKDIR}"

这是 Makefile:

obj-m := blink.o

MY_CFLAGS += -g -DDEBUG
ccflags-y += ${MY_CFLAGS}

SRC := $(shell pwd)

all:
    $(MAKE) -C $(KERNEL_SRC) M=$(SRC)

modules_install:
    $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install

clean:
    rm -f *.o *~ core .depend .*.cmd *.ko *.mod.c
    rm -f Module.markers Module.symvers modules.order
    rm -rf .tmp_versions Modules.symvers

Linux启动后,我执行了这些命令:

modprobe blink.ko
mknod /dev/blink_Dev c 244 0

当我将所需位切换为“1”时,我使用“devmem”命令来检查 LED 是否闪烁

但是,当 IOCTL 执行同样的事情时:

ret_val = ioctl(file_desc, IOCTL_ON_LED, NULL);
返回 0,但没有任何反应。

我正在尝试找出原因。

更新:我添加了 BitBake 文件和 Makefile。

makefile kernel-module bitbake petalinux
1个回答
0
投票

看来我找到了根本情况。 在blink.h中MAGIC_NUM定义为241,而我执行'mknod /dev/blink_Dev c 244 0'。 在我将 MAGIC_NUM 更改为 244 后,应用程序按预期运行。

© www.soinside.com 2019 - 2024. All rights reserved.