应用层
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <strings.h>
#include <sys/mman.h>
int main(int argc, char **argv)
{
if(2 != argc)
{
printf("Usage: %s <file>\n", argv[0]);
return 0;
}
int fd = open(argv[1], O_RDWR);
if(-1 == fd)
{
perror("open");
return -1;
}
// 将fd代表的设备文件映射到用户虚拟地址空间
char *q = mmap(NULL, 10240, PROT_WRITE|PROT_READ , MAP_SHARED, fd, 0);
if( MAP_FAILED == q)
{
perror("mmap");
return -1;
}
int *p = (int*)(q+0x0c44);
while(1)
{
*p = 1<<7;
sleep(1);
sync();
*p &= ~(1<<7);
sleep(1);
sync();
}
close(fd);
}
驱动层
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <asm/io.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <linux/highmem.h>
#include <asm/kmap_types.h>
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("a simple driver example!");
typedef struct leddat{
int *baseaddr;
int pin;
}LEDDAT;
struct led{
dev_t num;
struct cdev *mycdev;
LEDDAT leds[4];
}MYLED;
static int myled_open(struct inode *inodep, struct file *filep)
{
int i = 4;
printk("led open called\n");
MYLED.leds[0].baseaddr = ioremap(0x11000c40, 8);
MYLED.leds[0].pin = 7;
MYLED.leds[1].baseaddr = ioremap(0x11000c20, 8);
MYLED.leds[1].pin = 0;
MYLED.leds[2].baseaddr = ioremap(0x114001E0, 8);
MYLED.leds[2].pin = 4;
MYLED.leds[3].baseaddr = ioremap(0x114001E0, 8);
MYLED.leds[3].pin = 5;
// *MYLED.gpx2con = *MYLED.gpx2con &~(0xf<<28) | 1<<28;
while(i--)
iowrite32((ioread32(MYLED.leds[i].baseaddr)&~(0xf<<(MYLED.leds[i].pin*4))) | 1<<(MYLED.leds[i].pin*4) ,MYLED.leds[i].baseaddr);
return 0;
}
char buf[100] = {"hello"};
static ssize_t myled_read (struct file *f, char __user *p, size_t n, loff_t *off)
{
if(copy_to_user(p, buf, 5))
{
return -EFAULT;
}
return 5;
}
static ssize_t myled_write (struct file *f, const char __user *p, size_t n, loff_t *off)
{
if(copy_from_user(buf, p, n))
{
return -EFAULT;
}
return n;
}
#define ON _IOW('L', 0, int)
#define OFF _IOW('L', 1, int)
#define XXX _IOW('L', 2, int)
static long myled_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
{
int *dataaddr = MYLED.leds[arg].baseaddr+1;
int pin = MYLED.leds[arg].pin;
switch(cmd)
{
case ON:
iowrite32((ioread32(dataaddr) | 1<<pin ), dataaddr);
break;
case OFF:
iowrite32((ioread32(dataaddr) & ~(1<<pin)) ,dataaddr);
break;
case XXX:
printk("unknow cmd\n");
break;
}
return 0;
}
static int myled_release(struct inode *inodep, struct file *filep)
{
int i = 4;
printk("led closed\n");
while(i--)
iounmap(MYLED.leds[i].baseaddr);
return 0;
}
int myled_mmap(struct file *f, struct vm_area_struct *vma)
{// 以页对其映射
return remap_pfn_range(vma, vma->vm_start, 0x11000000>>PAGE_SHIFT,
vma->vm_end-vma->vm_start,
vma->vm_page_prot);
}
struct file_operations myops = {
.owner = THIS_MODULE,
.open = myled_open,
.unlocked_ioctl = myled_ioctl,
.read = myled_read,
.write = myled_write,
.mmap = myled_mmap,
.release = myled_release
};
static int __init mymodule_init(void)
{
int ret = 0;
printk("led module in\n");
//request dev num
ret = alloc_chrdev_region(&MYLED.num, 0, 1, "leddddddddddd");
if(ret)
{
printk("devnum alloc fail!\n");
return ret;
}
printk("num: %d\n", MAJOR(MYLED.num) );
//create cdev object
MYLED.mycdev = cdev_alloc();
if(NULL==MYLED.mycdev)
{
printk("alloc cdev fail!\n");
goto cdev_alloc_out;
}
//init cdev ops
cdev_init(MYLED.mycdev, &myops);
MYLED.mycdev->owner = THIS_MODULE;
//register cdev into kernel
ret = cdev_add(MYLED.mycdev, MYLED.num, 1);
if(ret)
{
printk("add cdev fail!\n");
goto cdev_add_out;
}
return 0;
cdev_add_out:
kfree(MYLED.mycdev);
cdev_alloc_out:
unregister_chrdev_region(MYLED.num, 1);
return ret;
}
static void __exit mymodule_exit(void)
{
//unregister cdev from kernel
cdev_del(MYLED.mycdev);
//release cdev object
kfree(MYLED.mycdev);
//release dev num
unregister_chrdev_region(MYLED.num, 4);
printk("led module release\n");
}
module_init(mymodule_init);
module_exit(mymodule_exit);