OpenRisc 驱动之helloworld

引言

我觉得ORPSoC的关键在于‘P’,即programmable。SoC的有优势就在于只要是满足总线interface的ip,可以实现plug & work。

所以一旦完成前面的工作之后,添加属于自己的ip core到ORPSoC的wishbone总线上,并编写它对应的驱动就成为非常关键的一步。

本小节就做一个简单的例子,来说明需要完成的工作步骤及其中遇到的问题和对应的解决方法。

 

11.1 编写wishbone为interface的ip core(ip_mkg)

1》这一步请参考:

http://blog.csdn.net/rill_zhen/article/details/8659788

2》将其中的my_slave_module链接到ORPSoC的wishbone上。

 

11.2 编写linux下的driver module

代码及makefile如下:

1》ip_mkg.c

 

[html]  view plain copy print ?
  1. /*  
  2. *  
  3. * rill mkg driver  
  4. *  
  5. */  
  6. #include <linux/vmalloc.h>  
  7. #include <linux/slab.h>  
  8.   
  9. #include <linux/kernel.h>  
  10. #include <linux/module.h>  
  11. #include <linux/fs.h>  
  12. #include <asm/uaccess.h> /* get_user and put_user */  
  13. //#include <linux/clk.h>  
  14. //#include <linux/ioport.h>  
  15. #include <asm/io.h> /*ioremap*/  
  16. #include <linux/platform_device.h> /*cleanup_module*/  
  17.   
  18. #include "ip_mkg.h"  
  19.   
  20.   
  21. void    __iomem     *g_mkg_mem_base = NULL;  
  22.   
  23. static int device_open(struct inode *inode, struct file *file)  
  24. {  
  25.     g_mkg_mem_base = ioremap(MKG_MEM_BASE,MKG_MEM_LEN);  
  26.     if(NULL == g_mkg_mem_base)  
  27.     {  
  28.         printk(KERN_ERR "mkg open ioremap error!\n");  
  29.         return -1;  
  30.     }  
  31.     else  
  32.     {  
  33.         printk("mkg ioremap addr:%d!\n",(int)g_mkg_mem_base);  
  34.     }  
  35.   
  36.     return 0;  
  37. }  
  38.   
  39. static int device_release(struct inode *inode, struct file *file)  
  40. {  
  41.     return 0;  
  42. }  
  43.   
  44.   
  45. static ssize_t device_read(struct file *filp, char *buffer, size_t length, loff_t *offset)  
  46. {  
  47.     return 0;  
  48. }  
  49.   
  50. static ssize_t device_write(struct file *filp, const char *buffer, size_t count, loff_t *offset)  
  51. {  
  52.    return 0;  
  53. }  
  54.   
  55. long device_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param)  
  56. {  
  57.    int ret_val = 0;  
  58.    unsigned int ret = 0;  
  59.    struct reg_data *new_regs;  
  60.   
  61.    switch(ioctl_num)  
  62.    {  
  63.       case IOCTL_REG_SET:  
  64.       {  
  65.          new_regs = (struct reg_data*)kmalloc(sizeof(struct reg_data), GFP_KERNEL);  
  66.          if((ret_val = copy_from_user(new_regs, (struct reg_data*)ioctl_param, sizeof(struct reg_data))) != 0)   
  67.             {  
  68.                 kfree(new_regs);  
  69.                 printk(KERN_ERR " error copy line_datafrom user.\n");  
  70.                 return -1;  
  71.             }  
  72.   
  73.             iowrite16(new_regs->value,g_mkg_mem_base+new_regs->addr);  
  74.          kfree(new_regs);  
  75.      }  
  76.      break;  
  77.   
  78.     case IOCTL_REG_GET:  
  79.     {  
  80.      new_regs = (struct reg_data*)kmalloc(sizeof(struct reg_data), GFP_KERNEL);  
  81.      if((ret_val = copy_from_user(new_regs, (struct reg_data*)ioctl_param, sizeof(struct reg_data))) != 0)   
  82.         {  
  83.             kfree(new_regs);  
  84.             printk(KERN_ERR " error copy line_datafrom user.\n");  
  85.             return -1;  
  86.         }  
  87.   
  88.         ret = ioread16(g_mkg_mem_base+new_regs->addr);  
  89.         kfree(new_regs);  
  90.         return ret;  
  91.     }  
  92.     break;  
  93.         
  94.    }  
  95.   
  96.   
  97.   return -1;  
  98. }  
  99.   
  100. struct file_operations our_file_ops = {  
  101.   .unlocked_ioctl = device_ioctl,  
  102.   .read = device_read,  
  103.   .write = device_write,  
  104.   .open = device_open,  
  105.   .release = device_release,  
  106.   .owner = THIS_MODULE,  
  107. };  
  108.   
  109. int init_module()  
  110. {  
  111.     int ret_val;  
  112.     int ret;  
  113.     void __iomem *ret_from_request;  
  114.       
  115.   
  116.     //=== Allocate character device   
  117.     ret_val = register_chrdev(MAJOR_NUM, DEVICE_NAME, &our_file_ops);  
  118.     if (ret_val < 0)  
  119.     {  
  120.         printk(KERN_ALERT " device %s failed(%d)\n", DEVICE_NAME, ret_val);  
  121.         return ret_val;  
  122.     }  
  123.   
  124.     ret = check_mem_region(MKG_MEM_BASE, MKG_MEM_LEN);  
  125.     if (ret < 0)   
  126.     {  
  127.         printk(KERN_ERR "mkg check_mem_region bussy error!\n");  
  128.         return -1;  
  129.     }  
  130.   
  131.     ret_from_request = request_mem_region(MKG_MEM_BASE, MKG_MEM_LEN, "ip_mkg");  
  132.   
  133.     //===ioremap mkg registers  
  134.   
  135.     g_mkg_mem_base = ioremap(MKG_MEM_BASE,MKG_MEM_LEN);  
  136.     if(NULL == g_mkg_mem_base)  
  137.     {  
  138.         printk(KERN_ERR "mkg ioremap error!\n");  
  139.         return -1;  
  140.     }  
  141.     else  
  142.     {  
  143.         ;//printk("mkg ioremap addr:%d!\n",g_mkg_mem_base);  
  144.     }  
  145.   
  146.     printk("mkg module init done!\n");  
  147.   
  148.     return 0;  
  149. }  
  150.   
  151. void cleanup_module()  
  152. {  
  153.     release_mem_region(MKG_MEM_BASE, MKG_MEM_LEN);  
  154.   
  155.     unregister_chrdev(MAJOR_NUM, DEVICE_NAME);  
  156. }  
  157.   
  158. MODULE_LICENSE("GPL");  
  159. MODULE_AUTHOR("Rill zhen:rillzhen@gmail.com");  


 

 

2》ip_mkg.h,需要注意的是ip core的基地址是在写verilog HDL时指定的。

 

[html]  view plain copy print ?
  1. #ifndef __IP_MKG_H__  
  2. #define __IP_MKG_H__  
  3.   
  4. #define MAJOR_NUM   102  
  5. #define DEVICE_NAME "ip_mkg"  
  6. #define MKG_MEM_BASE 0x10000001  
  7. #define MKG_MEM_LEN 32  
  8.   
  9. #define IOCTL_REG_SET 0  
  10. #define IOCTL_REG_GET 1  
  11.   
  12.   
  13.   
  14. struct reg_data   
  15. {  
  16.     unsigned short addr;  
  17.     int value;  
  18. };  
  19.   
  20. #endif  


 

 

3》Makefile

 

[html]  view plain copy print ?
  1. # To build modules outside of the kernel tree, we run "make"  
  2. # in the kernel source tree; the Makefile these then includes this  
  3. # Makefile once again.  
  4. # This conditional selects whether we are being included from the  
  5. # kernel Makefile or not.  
  6. ifeq ($(KERNELRELEASE),)  
  7.   
  8.     # Assume the source tree is where the running kernel was built  
  9.     # You should set KERNELDIR in the environment if it's elsewhere  
  10.     KERNELDIR ?= /home/openrisc/soc-design/linux  
  11.     # The current directory is passed to sub-makes as argument  
  12.     PWD := $(shell pwd)  
  13.   
  14. modules:  
  15.     make -C $(KERNELDIR) M=$(PWD) modules ARCH=openrisc CROSS_COMPILE=or32-linux-  
  16.   
  17. modules_install:  
  18.     make -C $(KERNELDIR) M=$(PWD) modules_install ARCH=openrisc CROSS_COMPILE=or32-linux-  
  19.   
  20. clean:  
  21.     rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers  
  22.   
  23. .PHONY: modules modules_install clean  
  24.   
  25. else  
  26.     # called from kernel build system: just declare what our modules are  
  27.     obj-m :ip_mkg.o  
  28. endif  


 

 

11.3 遇到的问题

1》当在执行make时会遇到如下警告:__ioremap undefined。

2》在板子上insmod时会遇到如下error:unknown symbol __ioremap。

 

11.4 解决方法

在arch/openrisc/mm/ioremap.c中添加如下代码:并重新编译kernel。

 

[html]  view plain copy print ?
  1. #include <linux/module.h>  
  2.   
  3. EXPORT_SYMBOL(__ioremap);  


 

 

 

 

 

11.5 小结

实验步骤

 

0》virtualbox虚拟机unbuntu上安装nfs服务

0.0>确保virtualbox能上网

0.1> apt-get install nfs-kernel-server

0.2>创建nfs共享目录:mkdir /home/openrisc/nfs

0.3>vim /etc/exports,添加如下内容

/home/openrisc/nfs  *(rw,sync)

0.4>重启nfs服务

sudo /etc/init.d/nfs-kernel-server restart

 

1》修改arch/openrisc/mm/ioremap.c

2》cd /home/openrisc/soc-design/linux

3》make ARCH=openrisc defconfig;make生成vmlinux

4》cd 到ip_mkg下,make生成ip_mkg.ko模块文件

5》参考如下链接,在FPGA板子上运行linux(刚刚生成的vmlinux文件)

http://blog.csdn.net/rill_zhen/article/details/8535317

6》配置virtualbox的ip

sudo ifconfig eth8 192.168.1.101 broadcast 192.168.1.255

7》配置PC机的ip为192.168.1.102

8》板子起来后默认的ip为192.168.1.100,如果不是,则需要配置为同一网段。确保板子能ping通virtualbox。别忘了将板子和PC用网线连起来。

9》板子上执行mkdir nfs,创建本地nfs共享目录

10》挂载NFS:mount -t nfs -o nolock 192.168.1.101:/home/openrisc/nfs /nfs

11》在virtualbox里将ip_mkg.ko copy到nfs共享目录

12》板子上cd nfs

13》执行insmod ip_mkg.ko加载模块,可以通过lsmod检查一下

14》创建设备节点:mknod /dev/ip_mkg c 102 0

15》测试:cat /dev/ip_mkg,看到如下结果:

16》上面的命令确实有些多,如果不想在每次板子起来后手动敲键盘,可以修改一下rootfs的启动脚本文件,这样就不用每次手动输入了,文件路径如下

soc-design/linux/arch/openrisc/support/initramfs/etc/init.d/rcS

\soc-design\linux\arch\openrisc\support\initramfs\这个目录就是用busybox制作的rootfs的源。 

 

 

16》运行helloworld

16.1>编写hello.c

[html]  view plain copy print ?
  1. #include <stdio.h>  
  2.   
  3. void main()  
  4. {  
  5. printf("rill helloworld!\n");  
  6. }  


16.2>编译: or2-linux-gcc hello.c -o hello

16.3>copy到板子上:cp hello /home/openrisc/nfs

16.4>在板子上cd到/nfs,然后ls可以看到刚copy来的hello文件,最后运行:./hello,可以看到输出:

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值