如何访问内核函数

时间:2015-04-21 07:49:06

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

我在内核空间编写了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]));  

但是,我想实现一些具有一些参数和返回类型的函数。 我想从用户空间program.Suppose

访问此功能
 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");  

请指导我解决我的问题!

更新 - 在处理@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

请回复我失踪的地方?

UPDATE - 一切正常,没问题!!!&我将很快发布更新的源代码及详细说明!!

拜托,任何人都可以告诉我为什么我会得到-Ve标记!!有没有错误的信息?还是缺了?其他什么?

3 个答案:

答案 0 :(得分: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中使用这些函数来实现读写以外的功能。

答案 1 :(得分:0)

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

  1. 一切都是可见且连贯的 - 您可以使用ls / sys / your-driver并查看可以在此驱动程序上运行的所有操作(例如/ sys / device / system / cpu) - 这是IMO的主要观点。 ioctls没有相应的这个梦幻般的功能
  2. 您可以构建您的操作 - 与波特率相关的所有内容都可以驻留在/ sys / your-driver / baud
  3. 您可以使用流,因为为每个功能创建了一个条目

答案 2 :(得分:0)

我的源代码正常工作请看看。如果任何人受益或看到对他人有帮助,请给出一些+ 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&#34; chardev.h&#34;

#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&#34; ioctl.c&#34;

#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&#34;生成文件&#34;

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