2016-04-22 17 views
-3

ユーザランド関数からfread()を使用してバッファを受け取ることができません。ドライバはcopy_to_user()を使用して情報を渡しています。私がこれを実装している途中で何か荒いエラーはありますか?読み取りエラーデバイスドライバ

エラーは、printf( "%s \ n"、バッファ)に表示されます。ユーザランドコードからのステートメント。

ユーザランドコード:

デバイスドライバコード
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 

/* 
## Slave Register Descriptions 
## reset = 0x4 
## en = 0x8 
## input = 0xc 
## outlo = 0x10 
## outhi = 0x14 
*/ 

void readAccelerator(unsigned int * outlo, unsigned int * outhi); 
int writeAccelerator(unsigned int *data, char *address); 


int main (int argc, char *argv[]) 
{ 
    unsigned int *data; 
    unsigned int *result; 
    char * RESET_ADDR = "1"; 
    char * EN_ADDR = "2"; 
    char * INPUT_ADDR = "3"; 
    unsigned int * outlo = 0; 
    unsigned int * outhi = 0; 

    data = 0xFFEF; 

    writeAccelerator(1, RESET_ADDR); 
    writeAccelerator(0, RESET_ADDR); 
    writeAccelerator(data, INPUT_ADDR); 
    writeAccelerator(1, EN_ADDR); 
    writeAccelerator(0, EN_ADDR); 
    readAccelerator(&outlo, &outhi); 

    printf("input:%04x outLo = %02x, outHi = %02x\n", data, outlo, outhi); 

    return 0; 

} 


void readAccelerator(unsigned int * outlo, unsigned int * outhi) 
{ 
    char * buffer[10]; 
    size_t size = 1; 
    size_t nitems = 10; 
    FILE* fp; 

    fp = fopen("/proc/accelerator","r"); 
    if (fp == NULL) 
    { 
     printf("Cannot open for read\n"); 
     return -1; 
    } 
    /* 
    Expect return format: 
    0x00, 0x00 
    */ 
    fread(buffer, size, nitems, fp); 
    fclose(fp); 
    printf("eh?\n"); 
    printf("%s\n",buffer); 
    return; 
} 

int writeAccelerator(unsigned int *data, char *address) 
{ 
    FILE* fp; 
    char str[30]; 

    sprintf(str, "0x%08x ", data); //data 
    strcat(str, address);  //address 

    //printf("input data: %s", str); 

    fp = fopen("/proc/accelerator","w"); 
    if (fp == NULL) 
    { 
     printf("Cannot open for write\n"); 
     return -1; 
    } 

    fputs(str, fp); 
    fclose(fp); 
} 

readAccelerator関数で

#include <linux/kernel.h> 
#include <linux/module.h> 
#include <asm/uaccess.h> /* Needed for copy_from_user */ 
#include <asm/io.h>   /* Needed for IO Read/Write Functions */ 
#include <linux/proc_fs.h> /* Needed for Proc File System Functions */ 
#include <linux/seq_file.h> /* Needed for Sequence File Operations */ 
#include <linux/platform_device.h> /* Needed for Platform Driver Functions */ 
#include <linux/slab.h> /*for kmalloc and kfree */ 
#include <linux/vmalloc.h> 

/* Define Driver Name */ 
#define DRIVER_NAME "accelerator" 


unsigned long *base_addr; /* Vitual Base Address */ 
struct resource *res;  /* Device Resource Structure */ 
unsigned long remap_size; /* Device Memory Size */ 

/* Write operation for /proc/accelerator 
* ----------------------------------- 
* When user cat a string to /proc/accelerator file, the string will be stored in 
* const char __user *buf. This function will copy the string from user 
* space into kernel space, and change it to an unsigned long value. 
* It will then write the value to the register of accelerator controller, 
* and turn on the corresponding LEDs eventually. 
*/ 

static ssize_t proc_accelerator_write(struct file *file, const char __user * buf, 
        size_t count, loff_t * ppos) 
    { 
     //Allocate 
     char * myaddr_phrase; 
     char * pEnd; 
     char *buffer = vzalloc(count); 
     myaddr_phrase = buffer; 
     u32 myaddr_value; 
     u32 myreg_value; 

     //Copy Data 
     if (count < 22) { 
      if (copy_from_user(myaddr_phrase, buf, count)) 
       return -EFAULT; 

     //myaddr_phrase[count] = '\0'; 
    //printk("count = %d\n", count); 
    //printk("%s\n",myaddr_phrase); 
     } 
    // Use strtol to parse input 
    /* http://www.cplusplus.com/reference/cstdlib/strtol/ */ 
     myaddr_value = simple_strtoul(myaddr_phrase, &pEnd, 0); 
    //printk("myaddr_value = %08x\n", myaddr_value); 
    pEnd = strsep(&myaddr_phrase," "); 
    myreg_value = simple_strtoul(myaddr_phrase,&pEnd ,0); 
    //printk("myreg_value = %08x\n", myreg_value); 
    //printk("final_value = %08x\n", (base_addr + (myreg_value))); 
    //printk("mult_val = %08x\n", (myreg_value)); 
    wmb(); 
    iowrite32(myaddr_value, (base_addr + (myreg_value))); 
    printk("WRITE: Reg %d; value 0x%08x\n",myreg_value,myaddr_value); 
    return count; 
} 

static ssize_t proc_accelerator_read(struct file *file, const char __user * buf, 
        size_t count, loff_t * ppos) 
    { 
    printk("READ: "); 
    u32 out_lo; 
    u32 out_hi; 
    int OUTLO_ADDR = 4; 
    int OUTHI_ADDR = 5; 
    u32 len = 10; 
    char * output; 
    //char * buffer; 
    out_lo = ioread32(base_addr+OUTLO_ADDR); 
    out_hi = ioread32(base_addr+OUTHI_ADDR); 
    //seq_printf(p, "0x%02x, 0x%02x", out_lo, out_hi); 
    sprintf(output, "0x%02x, 0x%02x", out_lo, out_hi); // length = 10 
    printk("OUTPUT = %s\n",output); 
    if(copy_to_user(buf, &output, len)) 
     return -EFAULT; 
    // returning total length of 11!!! 
    printk("exiting read...\n"); 
    return 0; 
} 


/* Callback function when opening file /proc/accelerator 
    * ------------------------------------------------------ 
    * Read the register value of accelerator controller, print the value to 
    * the sequence file struct seq_file *p. In file open operation for /proc/accelerator 
    * this callback function will be called first to fill up the seq_file, 
    * and seq_read function will print whatever in seq_file to the terminal. 
    */ 

static int proc_accelerator_show(struct seq_file *p, void *v) 
{ 
    u32 out_lo; 
    u32 out_hi; 
    int OUTLO_ADDR = 4; 
    int OUTHI_ADDR = 5; 
    char * output; 
    char * buffer; 
    out_lo = ioread32(base_addr+OUTLO_ADDR); 
    out_hi = ioread32(base_addr+OUTHI_ADDR); 
    seq_printf(p, "0x%02x, 0x%02x", out_lo, out_hi); 
    sprintf(output, "0x%02x, 0x%02x", out_lo, out_hi); 
    //copy_to_user(*buffer, output, 11); 
    // returning total length of 14!!! 

    return 0; 
} 

/* Open function for /proc/accelerator 
    * ------------------------------------ 
    * When user want to read /proc/accelerator (i.e. cat /proc/accelerator), the open function 
    * will be called first. In the open function, a seq_file will be prepared and the 
    * status of accelerator will be filled into the seq_file by proc_accelerator_show function. 
    * 
    *p 69 
    int (*open) (struct inode *, struct file *); 
    Though this is always the first operation performed on the device file, the driver 
    is not required to declare a corresponding method. If this entry is NULL, opening 
    the device always succeeds, but your driver isn’t notified. 

    Open described on p76 
    */ 
static int proc_accelerator_open(struct inode *inode, struct file *file) 
    { 
     unsigned int size = 16; 
     char *buf; 
     struct seq_file *m; 
     int res; 

     buf = (char *)kmalloc(size * sizeof(char), GFP_KERNEL); 
     if (!buf) 
      return -ENOMEM; 

     res = single_open(file, proc_accelerator_show, NULL); 

     if (!res) { 
      m = file->private_data; 
      m->buf = buf; 
      m->size = size; 
     } else { 
      kfree(buf); 
     } 

     return res; 
    } 

    /* File Operations for /proc/accelerator */ 
    static const struct file_operations proc_accelerator_operations = { 
     .open = proc_accelerator_open, 
    // .read = seq_read, 
     .read = proc_accelerator_read, 
     .write = proc_accelerator_write, 
     .llseek = seq_lseek, 
     .release = single_release 
    }; 
    /* 
int (*open) (struct inode *, struct file *); 
Though this is always the first operation performed on the device file, the driver 
is not required to declare a corresponding method. If this entry is NULL, opening 
the device always succeeds, but your driver isn’t notified. 

ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); 
Used to retrieve data from the device. A null pointer in this position causes the 
readsystem call to fail with-EINVAL(“Invalid argument”). A nonnegative return 
value represents the number of bytes successfully read (the return value is a 
“signed size” type, usually the native integer type for the target platform) 

ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); 
Sends data to the device. IfNULL, -EINVALis returned to the program calling the 
writesystem call. The return value, if nonnegative, represents the number of 
bytes successfully written. 

loff_t (*llseek) (struct file *, loff_t, int); 
Thellseek method is used to change the current read/write position in a file, and 
the new position is returned as a (positive) return value. Theloff_tparameter is 
a “long offset” and is at least 64 bits wide even on 32-bit platforms. Errors are 
signaled by a negative return value. If this function pointer isNULL, seek calls will 
modify the position counter in thefilestructure (described in the section “The 
file Structure”) in potentially unpredictable ways. 

int (*release) (struct inode *, struct file *); 
This operation is invoked when thefilestructure is being released. Likeopen, 
releasecan beNULL. 
* 
    */ 


    /* Shutdown function for accelerator 
    * ----------------------------------- 
    * Before accelerator shutdown, turn-off all the leds 
    */ 
static void accelerator_shutdown(struct platform_device *pdev) 
{ 
    iowrite32(0, base_addr); 
} 

/* Remove function for accelerator 
    * ---------------------------------- 
    * When accelerator module is removed, turn off all the leds first, 
    * release virtual address and the memory region requested. 
    */ 
static int accelerator_remove(struct platform_device *pdev) 
{ 
    accelerator_shutdown(pdev); 

    /* Remove /proc/accelerator entry */ 
    remove_proc_entry(DRIVER_NAME, NULL); 

    /* Release mapped virtual address */ 
    iounmap(base_addr); 

    /* Release the region */ 
    release_mem_region(res->start, remap_size); 

    return 0; 
} 

/* Device Probe function for accelerator 
    * ------------------------------------ 
    * Get the resource structure from the information in device tree. 
    * request the memory region needed for the controller, and map it into 
    * kernel virtual memory space. Create an entry under /proc file system 
    * and register file operations for that entry. 
    */ 
static int accelerator_probe(struct platform_device *pdev) 
{ 

    struct proc_dir_entry *accelerator_proc_entry; 
    int ret = 0; 
    printk(KERN_ALERT "Probing\n"); 
    res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 
    if (!res) { 
     dev_err(&pdev->dev, "No memory resource\n"); 
     return -ENODEV; 
    } 

    remap_size = res->end - res->start + 1; 
    if (!request_mem_region(res->start, remap_size, pdev->name)) { 
     dev_err(&pdev->dev, "Cannot request IO\n"); 
     return -ENXIO; 
    } 

    base_addr = ioremap(res->start, remap_size); 
    if (base_addr == NULL) { 
     dev_err(&pdev->dev, "Couldn't ioremap memory at 0x%08lx\n", 
      (unsigned long)res->start); 
     ret = -ENOMEM; 
     goto err_release_region; 
    } 

    accelerator_proc_entry = proc_create(DRIVER_NAME, 0, NULL, 
         &proc_accelerator_operations); 
    if (accelerator_proc_entry == NULL) { 
     dev_err(&pdev->dev, "Couldn't create proc entry\n"); 
     ret = -ENOMEM; 
     goto err_create_proc_entry; 
    } 

    printk(KERN_INFO DRIVER_NAME " probed at VA 0x%08lx\n", 
      (unsigned long) base_addr); 
    printk(KERN_ALERT "Goodbye, probe\n"); 

    return 0; 

    err_create_proc_entry: 
    iounmap(base_addr); 
    err_release_region: 
    release_mem_region(res->start, remap_size); 

    return ret; 
} 

/* device match table to match with device node in device tree */ 
/* 
https://lwn.net/Articles/448502/ 
*/ 
static const struct of_device_id accelerator_of_match[] = { 
    {.compatible = "PCA,bitSplitter"}, 
    {}, 
}; 

MODULE_DEVICE_TABLE(of, accelerator_of_match); 

/* platform driver structure for accelerator driver */ 
/* 
Platform devices are represented by the struct, and is found in <linux/platform_device.h> 
at minimum probe() and remove() must be supplied, the others have to do with power management 
https://lwn.net/Articles/448499/ 
*/ 
static struct platform_driver accelerator_driver = { 
    .driver = { 
      .name = DRIVER_NAME, 
      .owner = THIS_MODULE, 
      .of_match_table = accelerator_of_match}, 
    .probe = accelerator_probe, 
    .remove = accelerator_remove, 
    .shutdown = accelerator_shutdown 
}; 

/* Register accelerator platform driver */ 
/* 
    Helper macro for drivers that don't do 
* anything special in module init/exit. This eliminates a lot of 
* boilerplate. Each module may only use this macro once, and 
* calling it replaces module_init() and module_exit() 
* 
* Platform drivers are for HW that will not dynamically come and go into a Linux system, 
* such as the video and audio controllers in a tablet. In makes sense to statically pull 
* in those code necessary through the __initcall magic discussed above. 
* 
* http://henryomd.blogspot.com/2014/11/linux-kernel-startup.html 
*/ 
module_platform_driver(accelerator_driver); 

/* Module Informations */ 
/* 
Discussed in 2.6 Preliminaries 
*/ 
MODULE_AUTHOR("Digilent, Inc."); 
MODULE_LICENSE("GPL"); 
MODULE_DESCRIPTION(DRIVER_NAME ": accelerator driver (Simple Version)"); 
MODULE_ALIAS(DRIVER_NAME); 

OUTPUT from userland and kern.log

答えて

1

は、あなたがバッファに10個の文字を読んでいるが、緩衝液は以下のように定義されますcharの配列ではなく、charへのポインタの配列。

カーネルコードでの

問題:

// char *output; 
// you are writing to output without initialize it, this produce UB, which may be a crash, try this: 
char output[1024]; 
sprintf(output, "0x%02x, 0x%02x", out_lo, out_hi); // length = 10 
printk("OUTPUT = %s\n",output); 


// if(copy_to_user(buf, &output, len)) 
// here you are copying from the address of output, not output the buffer, try 
if(copy_to_user(buf, output, len)) ... 
+0

出力はもはやランダムな文字が、文字バッファーを示している[10]今、ちょうど空のセットを印刷します。 – gutelfuldead

+0

@minersrevoltカーネルコードを修正してもう一度テストしてみてください。 – fluter

+0

ありがとう - 同じ問題がまだありますが、printf( ".."、buffer)の空の出力です。 – gutelfuldead

1

だから、今取り組んでいます。

output [11] = {0}を割り当てるには@フルーターが必要でした。ここには最終的な機能と参照が必要です。読み取りのための

ドライバの機能:通話のための

static ssize_t proc_accelerator_read(struct file *file, const char __user * buf, 
        size_t count, loff_t * ppos) 
    { 
    printk("READ: "); 
    u32 out_lo; 
    char output[11] = {0}; 
    u32 out_hi; 
    int OUTLO_ADDR = 4; 
    int OUTHI_ADDR = 5; 
    u32 len = 11; 

    out_lo = ioread32(base_addr+OUTLO_ADDR); 
    out_hi = ioread32(base_addr+OUTHI_ADDR); 
    sprintf(output, "0x%02x, 0x%02x", out_lo, out_hi); // length = 10 
    printk("OUTPUT = %s\n",output); 
    if(copy_to_user(buf, output, len)) 
     return -EFAULT; 
    // returning total length of 11!!! 
    printk("exiting read...\n"); 
    return count; 
} 

ユーザランド機能:

void readAccelerator(unsigned int * outlo, unsigned int * outhi) 
{ 
    char buffer[11]; 
    size_t size = 1; 
    size_t nitems = 11; 
    FILE* fp; 

    fp = fopen("/proc/accelerator","r"); 
    if (fp == NULL) 
    { 
     printf("Cannot open for read\n"); 
     return -1; 
    } 
    /* 
    Expect return format: 
    0x00, 0x00 
    */ 
    fread(buffer, size, nitems, fp); 
// read(fp, buffer, nitems); 
    fclose(fp); 
    printf("%s\n",buffer); 
    return; 
}