我參考下面的三篇文章, 實做一個最基本功能的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);
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");
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));
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
我參考下面的三篇文章, 實做一個最基本功能的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