【问题标题】:How to Access Kernel Function如何访问内核函数
【发布时间】:2015-04-21 07:49:06
【问题描述】:

我已经在内核空间中编写了 SPI 字符设备驱动程序。我现在可以从用户空间通过以下函数进行通信了。

1.open("/dev/rfk_spi", O_RDWR);    
2.write(fd,buf,sizeof(buf)/sizeof(buf[0]));
3.read(fd,tab,sizeof(tab)/sizeof(tab[0]));  

但是,我想实现更多具有一些参数和返回类型的函数。 我想从用户空间程序访问这个功能。假设

 1.unsigned char function1(unsigned int,unsigned char*);
 2.void function2(struct student record);

那么如何在内核空间/用户空间编写代码来交换数据。

这些是我的内核函数:

  1.static int spi_open(struct inode *inode,struct file *filp) {}  
  2.static int spi_release(struct inode *inode,struct file *filp){}
  3.static ssize_t spi_read(struct file *filp,char __user *buf,size_t count,loff_t *f_ops){}
  4.static ssize_t spi_write(struct file *filp,const char __user *buf,size_t count,loff_t *f_ops){}  
  static const struct file_operations spi_fops =  
  {  
     .owner=THIS_MODULE,  
     .open=spi_open,  
     .read=spi_read,  
     .release=spi_release,  
     .write=spi_write,  
  };  
  static struct miscdevice misc = 
  {  
     .minor = MISC_DYNAMIC_MINOR,  
     .name  = DEVICE_NAME,  
     .fops  = &spi_fops,  
  };  

  6.static int __init spi_init(void){}  
  7.static void __exit spi_exit(void){}   
  module_init(spi_init);  
  module_exit(spi_exit);  

  MODULE_LICENSE("GPL");  

请指导我解决我的问题!

UPDATE- 在处理@jjm 的建议时,现在我收到以下回复:

我已经交叉编译了 chardev.c ,chardev.h 和 make chardev.ko

root@rfk-desktop:# ls
chardev.c  chardev.h  chardev.ko  chardev.mod.c  chardev.mod.o  chardev.o ioctl  ioctl.c  Makefile  modules.order  Module.symvers

root@rfk-desktop:# file chardev.ko 
chardev.ko: ELF 32-bit LSB relocatable, ARM, version 1 (SYSV), not stripped

root@rfk-desktop:# file ioctl
ioctl: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, stripped

我将文件复制到我的开发板并注册

[root@FriendlyARM 2.6.32.2-FriendlyARM]# modprob chardev
[root@FriendlyARM 2.6.32.2-FriendlyARM]# mknod char_dev c 100 0

但是当我运行测试程序时:)

[root@FriendlyARM /mnt]# ./ioctl
Can't open device file: char_dev

请回复我在哪里失踪?

更新- 一切正常,没问题!!!&我将很快发布更新的源代码和详细描述!!

拜托,任何人都可以告诉我为什么我得到 -Ve 标记!有什么信息有误吗?或失踪?还有什么?

【问题讨论】:

  • RFK,要提出任何建议,请将 /dev/dmesg 日志中的 ls -l 日志发送给我们在 insmod chardev.ko 之后

标签: linux-kernel linux-device-driver spi


【解决方案1】:

您可以为此目的使用 IOCTL。您也可以将 ioctl 函数注册到您的文件操作。例如。

static const struct file_operations spi_fops =  
{  
 .owner=THIS_MODULE,  
 .open=spi_open,  
 .read=spi_read,  
 .release=spi_release,  
 .write=spi_write,  
 .unlocked_ioctl=spi_ioctl
};

然后就可以使用了

 copy_from_user 

从用户空间接收参数的函数和

copy_to_user

函数将参数传递给用户空间。在您的 IOCTL 中使用这些函数来实现读写以外的功能。

【讨论】:

  • 感谢 jjm。我已阅读主题 IOCLT 但无法正确理解我必须添加的代码。您能否发送任何相同的示例链接?
  • RFK,请阅读此链接link。这是关于ioctls的解释,link解释了copy_to_user,并链接到copy_from_user。您可以将结构的地址(使用来自用户的参数)作为 ioctl parm 传递。
  • 嗨,jjm。很抱歉更新了帖子。我的驱动程序正在注册到当前目录,这就是我无法访问的原因。现在我的最初要求满足了。我可以将 mgs 发送到内核,并可以从内核获取 msg。非常感谢。
【解决方案2】:

我会反对 Stackoverflow 上的大众投票,并建议使用 sysfs 有几个原因:

  1. 一切都是可见的和连贯的 - 你可以 ls /sys/your-driver 并查看可以在此驱动程序上运行的所有操作(例如 /sys/device/system/cpu) - 这是 IMO 的重点。 ioctl 没有与此出色功能对应的等价物
  2. 您可以构建您的操作 - 与波特率相关的所有内容都可以位于 /sys/your-driver/baud 下
  3. 您可以使用流,因为会为每个函数创建一个条目

【讨论】:

    【解决方案3】:

    我的源代码运行正常,请看一下。如果任何人受益或看到对其他人有帮助,请给一些+Ve标记。

    另外,请告诉我为什么我在这个问题上得到 -Ve 分数!!

    1."chardev.c"

    #include <linux/kernel.h>   
    #include <linux/module.h>   
    #include <linux/fs.h>
    #include <asm/uaccess.h>    
    #include "./chardev.h"
    #define SUCCESS 0
    #define DEVICE_NAME "char_dev_rfk"
    #define BUF_LEN 80
    static int Device_Open = 0;
    static char Message[BUF_LEN];
    static char *Message_Ptr;
    static int device_open(struct inode *inode, struct file *file)
    {
        printk(KERN_INFO "\n\rdevice_open(%p)\n", file);
    
        if (Device_Open) return -EBUSY;
    
        Device_Open++;
        Message_Ptr = Message;
        try_module_get(THIS_MODULE);
        return SUCCESS;
    }
    
    static int device_release(struct inode *inode, struct file *file)
    {
        printk(KERN_INFO "\n\rdevice_release(%p,%p)\n", inode, file);
        Device_Open--;
        module_put(THIS_MODULE);
        return SUCCESS;
    }
    static ssize_t device_read(struct file *file,char __user * buffer,size_t length, loff_t * offset)
    {
    
        int bytes_read = 0;
        printk(KERN_INFO "\n\rdevice_read(%p,%p,%d)\n", file, buffer, length);
        if (*Message_Ptr == 0)  return 0;
        while (length && *Message_Ptr_k)
        {
            put_user(*(Message_Ptr_k++), buffer++);
            length--;
            bytes_read++;
        }
        printk(KERN_INFO "Read %d bytes, %d left\n", bytes_read, length);
        return bytes_read;
    }
    static ssize_t device_write(struct file *file,const char __user * buffer, size_t length, loff_t * offset)
    {
        int i;
        printk(KERN_INFO "\n\rdevice_write(%p,%s,%d)", file, buffer, length);
        for (i = 0; i < length && i < BUF_LEN; i++)
            get_user(Message[i], buffer + i);
    
        Message_Ptr = Message;
        return i;
    }
    int device_ioctl(struct inode *inode, struct file *file, unsigned int ioctl_num, unsigned long ioctl_param)
    {
        int i;
        char *temp;
        char ch;
    
        switch (ioctl_num) 
        {
            case IOCTL_SET_MSG:     
                temp = (char *)ioctl_param;
                get_user(ch, temp);
                for (i = 0; ch && i < BUF_LEN; i++, temp++)
                    get_user(ch, temp);
    
                device_write(file, (char *)ioctl_param, i, 0);
            break;
    
            case IOCTL_GET_MSG:     
                i = device_read(file, (char *)ioctl_param, 99, 0);
                put_user('\0', (char *)ioctl_param + i);
            break;
    
            case IOCTL_GET_NTH_BYTE:
    
                return Message[ioctl_param];
            break;
        }
        return SUCCESS;
    }
    struct file_operations Fops = 
    {
        .read = device_read,
        .write = device_write,
        .ioctl = device_ioctl,
        .open = device_open,
        .release = device_release,  
    };
    int init_module()
    {
        int ret_val;    
        ret_val = register_chrdev(MAJOR_NUM, DEVICE_NAME, &Fops);
        if (ret_val < 0) 
        {
            printk(KERN_ALERT "%s failed with %d\n","Sorry, registering the character device ", ret_val);
            return ret_val;
        }
        printk(KERN_INFO "%s The major device number is %d.\n","Registeration is a success", MAJOR_NUM);        
    
        return 0;
    }
    void cleanup_module()
    {
    
    }       
    MODULE_LICENSE("GPL");  
    

    2."chardev.h"

    #ifndef CHARDEV_H
    #define CHARDEV_H
    
    #include <linux/ioctl.h>
    #define MAJOR_NUM 100
    #define IOCTL_SET_MSG _IOR(MAJOR_NUM, 0, char *)
    #define IOCTL_GET_MSG _IOR(MAJOR_NUM, 1, char *)
    #define IOCTL_GET_NTH_BYTE _IOWR(MAJOR_NUM, 2, int)
    #define DEVICE_FILE_NAME "char_dev_rfk"
    
    #endif
    

    3."ioctl.c"

    #include "chardev.h"
    #include <stdio.h>
    #include <stdlib.h>
    #include <fcntl.h>      
    #include <unistd.h>     
    #include <sys/ioctl.h>
    ioctl_set_msg(int file_desc, char *message)
    {
        int ret_val;
        printf("\n\rioctl_set_msg():Called\n");
        ret_val = ioctl(file_desc, IOCTL_SET_MSG, message);
    
        if (ret_val < 0) 
        {
            printf("ioctl_set_msg failed:%d\n", ret_val);
            exit(-1);
        }
    
    }
    ioctl_get_msg(int file_desc)
    {
        int ret_val;
        char message[100];
        printf("\n\rioctl_get_msg():Called\n");
        ret_val = ioctl(file_desc, IOCTL_GET_MSG, message);
    
        if (ret_val < 0) 
            {
            printf("ioctl_get_msg failed:%d\n", ret_val);
            exit(-1);
        }
        printf("\n\rget_msg message:%s\n", message);
    }
    
    ioctl_get_nth_byte(int file_desc)
    {
        int i;
        char c;
        printf("\n\rioctl_get_nth_byte():Called\n");
        printf("\n\rget_nth_byte message:");
        i = 0;
        do {
            c = ioctl(file_desc, IOCTL_GET_NTH_BYTE, i++);
            if (c < 0) 
            {
                printf("ioctl_get_nth_byte failed at the %d'th byte:\n",i);
                exit(-1);
            }
            putchar(c);
        } while (c != 0);
        putchar('\n');
    }
    main()
    {
        int file_desc, ret_val;
        char *msg = "Message passed from Uesr:Rofique\n";       
            file_desc = open("./char_dev_rfk", O_RDWR); 
        if (file_desc < 0) 
            {
            printf("Can't open device file: %s\n", DEVICE_FILE_NAME);
            exit(-1);
        }   
        ioctl_set_msg(file_desc, msg);  
        ioctl_get_msg(file_desc);       
        close(file_desc);
    }
    

    我已经为 ARM9 板交叉编译它。所以,制作文件如下。

    4.“生成文件”

    ifneq ($(KERNELRELEASE),)
    obj-m:= chardev.o
    else
    CROSS=arm-linux-
    KDIR := /opt/linux-2.6.32.2/
    all:ioctl
        make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux- 
    ioctl:ioctl.c
        $(CROSS)gcc -o ioctl ioctl.c
        $(CROSS)strip ioctl
    clean:
        rm -f *.ko *.o *.mod.o *.mod.c *symvers modul* ioctl
    endif
    

    【讨论】:

      猜你喜欢
      • 2013-01-21
      • 1970-01-01
      • 2018-01-11
      • 2017-03-18
      • 1970-01-01
      • 2014-02-02
      • 1970-01-01
      • 2015-06-26
      • 2016-03-23
      相关资源
      最近更新 更多