c - read error device driver -


not able receive buffer using fread() userland function. driver using copy_to_user() pass info. there blatant errors in way implementing this?

the error can seen in printf("%s\n",buffer); statement userland code.

userland code:

#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 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 write\n");         return -1;     }      fputs(str, fp);     fclose(fp); } 

device driver code:

#include <linux/kernel.h> #include <linux/module.h> #include <asm/uaccess.h>    /* needed copy_from_user */ #include <asm/io.h>         /* needed io read/write functions */ #include <linux/proc_fs.h>  /* needed proc file system functions */ #include <linux/seq_file.h> /* needed sequence file operations */ #include <linux/platform_device.h>  /* needed platform driver functions */ #include <linux/slab.h> /*for kmalloc , 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 /proc/accelerator  * -----------------------------------  *  when user cat string /proc/accelerator file, string stored in  *  const char __user *buf. function copy string user  *  space kernel space, , change unsigned long value.  *  write value register of accelerator controller,  *  , turn on 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 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 register value of accelerator controller, print value   *  sequence file struct seq_file *p. in file open operation /proc/accelerator   *  callback function called first fill seq_file,   *  , seq_read function print whatever in seq_file 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 /proc/accelerator    * ------------------------------------    *  when user want read /proc/accelerator (i.e. cat /proc/accelerator), open function     *  called first. in open function, seq_file prepared ,     *  status of accelerator filled seq_file proc_accelerator_show function.    *    *p 69     int (*open) (struct inode *, struct file *);     though first operation performed on device file, driver     not required declare corresponding method. if entry null, opening     device succeeds, 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 /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 first operation performed on device file, driver not required declare corresponding method. if entry null, opening device succeeds, driver isn’t notified.  ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); used retrieve data device. null pointer in position causes readsystem call fail with-einval(“invalid argument”). nonnegative return value represents number of bytes read (the return value “signed size” type, native integer type target platform)  ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); sends data device. ifnull, -einvalis returned program calling writesystem call. return value, if nonnegative, represents number of bytes written.  loff_t (*llseek) (struct file *, loff_t, int); thellseek method used change current read/write position in file, , new position returned (positive) return value. theloff_tparameter “long offset” , @ least 64 bits wide on 32-bit platforms. errors signaled negative return value. if function pointer isnull, seek calls modify position counter in thefilestructure (described in section “the file structure”) in potentially unpredictable ways.  int (*release) (struct inode *, struct file *); operation invoked when thefilestructure being released. likeopen, releasecan benull. *   */     /* shutdown function accelerator    * -----------------------------------    *  before accelerator shutdown, turn-off leds   */  static void accelerator_shutdown(struct platform_device *pdev)  {     iowrite32(0, base_addr);  }   /* remove function accelerator   * ----------------------------------   *  when accelerator module removed, turn off leds first,   *  release virtual address , 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 region */      release_mem_region(res->start, remap_size);       return 0;  }   /* device probe function accelerator   * ------------------------------------   *  resource structure information in device tree.   *  request memory region needed controller, , map   *  kernel virtual memory space. create entry under /proc file system   *  , register file operations 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 @ 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 @ 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 match 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 accelerator driver */  /*  platform devices represented struct, , found in <linux/platform_device.h>  @ minimum probe() , remove() must supplied, others have 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 drivers don't  * special in module init/exit.  eliminates lot of  * boilerplate.  each module may use macro once, ,  * calling replaces module_init() , module_exit()  *  * platform drivers hw not dynamically come , go linux system,   * such video , audio controllers in tablet.  in makes sense statically pull   * in code necessary through __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 userland , kern.log

in readaccelerator function, reading 10 chars buffer, buffer defined array of pointer char, not array of char, try this:

// char * buffer[10]; <-- problem here char buffer[10]; 

problems in kernel code:

// char *output; // writing output without initialize it, produce ub, may 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 copying address of output, not output buffer, try if(copy_to_user(buf, output, len)) ... 

Comments

Popular posts from this blog

Django REST Framework perform_create: You cannot call `.save()` after accessing `serializer.data` -

Why does Go error when trying to marshal this JSON? -