知識社群登入
位置: 艾鍗學院 Blog > 專業論壇 > 討論
[嵌入式Linux實作問題] 關於一個linux driver 的問題
1樓
 
老師, 請教一個driver 的問題, Linux 2.63以上mergekernel driver uio .

 

我參考下面的三篇文章, 實做一個最基本功能的uio driver, 就為read interrupt ,  mmap access kernel 映射到user space address , 後來發現聽interrupt 是可以, 但是 mmap 上來的位址,做讀取或寫入值的動作結果不如預期。我設定位置為chip select , 1mb (0x1A100000~0x1A1fffff), 讀取時會有一個固定的值, 但是怎麼read 都是錯的值,  char device ioremap(0x1A100000,0xf)作的話可以read正確的值,以下為程式碼, 最下面有三篇寫時所參考的文章:

 

kernel_part

#include <linux/module.h> 

#include <linux/platform_device.h> 

#include <linux/uio_driver.h>   

#include <linux/device.h> /* class_create */ 

#include <linux/kobject.h> /* kobject_uevent */ 

#include <linux/slab.h> /* kmalloc, kfree */ 

#define IRQ_INT 20

static struct resource abc[] = {

        [0] = {

                .start = 0x1A100000,

                .end =   0x1A100000+0xf,

                .flags = IORESOURCE_MEM,

        },

 

};

struct uio_info test_info = { 

        .name = "uio", 

        .version = "0.1", 

        .irq = IRQ_INT, 

}; 

 

static int drv_test_probe(struct device *dev); 

static int drv_test_remove(struct device *dev); 

 

static struct device_driver uio_test_driver = { 

        .name = "test", 

        .bus = &platform_bus_type, 

        .probe = drv_test_probe, 

        .remove = drv_test_remove, 

}; 

 

static irqreturn_t test_handler(int irq, struct uio_info *dev_info){

        printk("interrupt occur\n");

        return IRQ_HANDLED;

       

}

 

static int drv_test_probe(struct device *dev){ 

        test_info.mem[0].addr = abc[0].start;

        test_info.mem[0].size = abc[0].end - abc[0].start+1;

        test_info.mem[0].memtype = UIO_MEM_PHYS;

        test_info.mem[0].internal_addr= ioremap_nocache(test_info.mem[0].addr, test_info.mem[0].size+1);

       

    if(test_info.mem[0].addr == 0) 

            return -ENOMEM;

                               

        test_info.irq = IRQ_INT;

    test_info.irq_flags = IRQF_SHARED;  

        test_info.handler=test_handler;

 

         if( uio_register_device(dev, &test_info)){ 

            kfree((void *)test_info.mem[0].addr); 

            return -ENODEV; 

    } 

       

    return 0; 

} 

 

static int drv_test_remove(struct device *dev) 

{ 

    uio_unregister_device(&test_info); 

     

    return 0; 

}

 

static struct platform_device * uio_test_device; 

 

static int __init uio_test_init(void){     

        uio_test_device = platform_device_register_simple("test", -1, NULL, 0); 

        return driver_register(&uio_test_driver); 

} 

static void __exit uio_test_exit(void){

        platform_device_unregister(uio_test_device); 

        driver_unregister(&uio_test_driver); 

} 

module_init(uio_test_init); 

module_exit(uio_test_exit); 

 

MODULE_LICENSE("Dual BSD/GPL");

MODULE_DESCRIPTION("UIO test driver");

 

User_space part

#include <errno.h>

#include <fcntl.h>

#include <stdio.h>

#include <sys/mman.h>

 

int main() {

 

        int uio_fd;

    void *access_address;

    int  interrupt=0;

        int i=0;

       

    uio_fd = open("/dev/uio0", O_RDWR | O_SYNC);

    if(uio_fd  < 0) {

        perror("uio open");

        return errno;

    }

    access_address = mmap(NULL, 0x10, PROT_READ | PROT_WRITE, MAP_SHARED, uio_fd, 0);

       

    if(access_address == MAP_FAILED) {

        perror("uio mmap");

        return errno;

    }

       

        printf("*access_address = %x\n", *((short *) access_address));

       

        unsigned int * addr = (unsigned int*) access_address;

         

        printf("*access_address = %x\n", *addr);

 

        read(uio_fd,&interrupt,sizeof(interrupt));

       

    return errno;

}

 

 

Reference:

        http://www.kernel.org/doc/htmldocs/uio-howto.html

http://blog.csdn.net/ganggexiongqi/article/details/6794215

http://daydreamer.idv.tw/rewrite.php/read-41.html

2樓
看程式碼是没有什麼問題,所以建議trace一下drivers/uio/uio.c其中mmap的動作
3樓
 
多謝老師指導
 
那再問老師比較detail的問題, 因為我比較少這方面的經驗, 我可以用什麼方法或方式去 trace uio.c 這部分的code ,
 
那要注意一些什麼, http://blog.csdn.net/ganggexiongqi/article/details/6737647 這篇有提到uio.c 但是有點看不
 
太懂.  因為這禮拜天才上課, 還有一段時間 , 所以看能不能早點解決.
4樓
就在程碼裹面加printk()去印訊息,即可知道程式如何跑了,另外我看了一下你的程式碼,其中並未對mmap位址的內容做寫入的動作,裹面的資料應該是不定資料,另外在最後的read動作,應是從頭開始讀,而且它是int所以一次讀取4個bytes,而前面則是讀2個bytes,後面讀4個bytes