Chinaunix首页 | 论坛 | 博客
  • 博客访问: 276658
  • 博文数量: 74
  • 博客积分: 1336
  • 博客等级: 中尉
  • 技术积分: 1057
  • 用 户 组: 普通用户
  • 注册时间: 2009-07-02 09:33
文章分类

全部博文(74)

文章存档

2016年(6)

2015年(4)

2014年(20)

2013年(8)

2012年(16)

2010年(9)

2009年(11)

我的朋友

分类: LINUX

2012-08-03 17:47:37

1、以IO内存方式控制LED

    可以将IO端口映射到IO内存空间来访问,在设备驱动模块的加载函数或者open()函数中可以调用request_mem_region()函数来申请资源,使用ioremap()函数将IO端口所在的物理地址映射到虚拟地址上,之后,就可以调用readb(),readw(),readl()等函数读写寄存器中的内容了,不在使用IO内存时,可以使用iounmap()函数释放物理地址到虚拟地址的映射。最后使用release_mem_region()函数释放申请的资源。

I/O内存的操作需按如下步骤完成:

1)    申请

n   struct resource *request_mem_region(unsigned long start, unsigned long len, char *name)这个函数申请一个从start 开始,长度为len 字节的内存区。如果成功,返回非NULL;否则返回NULL,所有已经在使用的I/O内存在/proc/iomem 中列出。

2)    访问

在访问I/O内存之前, 必须进行物理地址到虚拟地址的映射,ioremap 函数具有此功能:

n   void *ioremap(unsigned long phys_addr, unsigned long size)

ioremap接收一个物理地址和一个整个IO端口的大小,返回一个虚拟地址,这个虚拟地址对应一个size大小的物理地址空间。

3)    访问 I/O 内存的正确方法是通过一系列内核提供的函数:

a)    I/O 内存读, 使用下列之一:

n   unsigned ioread8(void *addr)

n   unsigned ioread16(void *addr)

n   unsigned ioread32(void *addr)

b)    I/O 内存, 使用下列之一:

n   void iowrite8(u8 value, void *addr)

n   void iowrite16(u16 value, void *addr)

n   void iowrite32(u32 value, void *addr)

老版本的 I/O 内存访问函数:

c)    I/O 内存读, 使用下列之一:

n   unsigned readb(address)

n   unsigned readw(address)

n   unsigned readl(address)

d)    I/O 内存, 使用下列之一:

n   unsigned writeb(unsigned value, address)

n   unsigned writew(unsigned value, address)

n   unsigned writel(unsigned value, address)

4)    释放内存

I/O内存不再需要使用时应当释放,步骤如下:

n   void iounmap(void * addr)

iounmap()函数接收ioremap函数申请的虚拟地址作为参数,并取消物理地址到虚拟地址的映射。

n   void release_mem_region(unsigned longstart, unsigned long len)

release_mem_region()函数释放申请的资源。

2IO内存方式控制LED实例

    本实例硬件原理见4.1.7节讲述,。

#include

#include

#include

#include

//#include

//#include

#include

#include

#include

#include

#include

#include //for  udev

#include

#include

#define VIRTUALMEM_MAJOR 0    /*预设的ioport的主设备号*/

static unsigned int gpfcon_old = 0;

static unsigned int gpfdat_old = 0;

static unsigned int gpfup_old  = 0;

static int Virtualmem_major = VIRTUALMEM_MAJOR;

struct resource *IO_mem_resource;

unsigned long io_addr;

/*Virtualmem设备结构体*/

struct Virtualmem_dev                                    

{

     struct cdev cdev; /*cdev结构体*/                            

};

struct Virtualmem_dev *Virtualmem_devp; /*设备结构体指针*/

/*文件打开函数*/

int Virtualmem_open(struct inode *inode, struct file *filp)

{

     /*将设备结构体指针赋值给文件私有数据指针*/

     filp->private_data = Virtualmem_devp;

     printk("In the open process! turn off the led!\n");

     iowrite32(0x5500 | ioread32 (io_addr),io_addr);//GPFCON

     iowrite32(0xF0 | ioread32 (io_addr+8),(io_addr+8));//GPFUP

     iowrite32(0xF0 | ioread32 (io_addr+4),(io_addr+4));//GPFDAT

     return 0;

}

/*文件释放函数*/

int Virtualmem_release(struct inode *inode, struct file *filp)

{

     iowrite32(gpfcon_old,io_addr);

     iowrite32(gpfup_old,(io_addr+8));

     iowrite32(gpfdat_old,(io_addr+4)); 

     return 0;

}

/*读函数*/

static ssize_t Virtualmem_read(struct file *filp, char __user *buf, size_t size,

                                   loff_t *ppos)

{

     int ret = 0;

     struct Virtualmem_dev *dev = filp->private_data;   /*获得设备结构体指针*/

     return ret;

}

/*写函数*/

static ssize_t Virtualmem_write(struct file *filp, const char __user *buf,

                                   size_t size, loff_t *ppos)

{

     unsigned int count = size;

     int ret = 0;

     struct Virtualmem_dev *dev = filp->private_data;   /*获得设备结构体指针*/

     unsigned char *userbuf;    

     /*用户空间->内核空间*/

     if (copy_from_user(userbuf, (unsigned char *)buf, count))

         ret =  - EFAULT;

     else

     {

         iowrite32((*userbuf),(io_addr+4));         

         printk("write data from user to iomem!\n");

     }

     return ret;

}

/*文件操作结构体*/

static const struct file_operations Virtualmem_fops =

{

     .owner = THIS_MODULE,

     .read = Virtualmem_read,

     .write = Virtualmem_write,

     .open = Virtualmem_open,

     .release = Virtualmem_release,

};

/*初始化并注册cdev*/

static void Virtualmem_setup_cdev(struct Virtualmem_dev *dev, int index)

{

     int err, devno = MKDEV(Virtualmem_major, index);

     cdev_init(&dev->cdev, &Virtualmem_fops);

     dev->cdev.owner = THIS_MODULE;

     dev->cdev.ops = &Virtualmem_fops;

     err = cdev_add(&dev->cdev, devno, 1);

     if (err)

         printk(KERN_ALERT "Error %d adding Virtualmem%d", err, index);  

}

/*设备驱动模块加载函数*/

int Virtualmem_init(void)

{

     int result;

     dev_t devno = MKDEV(Virtualmem_major, 0);

     /* 申请设备号*/

     if (Virtualmem_major)

         result = register_chrdev_region(devno, 1, "iomem");

     else  /* 动态申请设备号 */

     {

         result = alloc_chrdev_region(&devno, 0, 1, "iomem");

         Virtualmem_major = MAJOR(devno);

     } 

     if (result < 0)

         return result;

     /* 动态申请设备结构体的内存*/

     Virtualmem_devp = kmalloc(sizeof(struct Virtualmem_dev), GFP_KERNEL);

     if (!Virtualmem_devp)  /*申请失败*/

     {

         result =  - ENOMEM;

         goto fail;

     }

     memset(Virtualmem_devp, 0, sizeof(struct Virtualmem_dev));

     Virtualmem_setup_cdev(Virtualmem_devp, 0);

     if ((IO_mem_resource=request_mem_region(0x56000050, 0x0c,"iomem"))==NULL)

         goto fail;

     else

     {

         printk("In the init process! \n");

         io_addr =(unsigned long) ioremap(0x56000050 , 0x0c);       

         printk("io_addr : %lx \n", io_addr);

         gpfcon_old = ioread32 (io_addr);

         gpfdat_old = ioread32 (io_addr+4);

         gpfup_old = ioread32 (io_addr+8);      

         printk("S3C2410_GPFCON is %8X\n",gpfcon_old);

         printk("S3C2410_GPFUP  is %8X\n",gpfup_old);

         printk("S3C2410_GPFDAT is %8X\n",gpfdat_old); 

         return 0;

     }

     fail: unregister_chrdev_region(devno, 1);

     return result;

}

/*模块卸载函数*/

void Virtualmem_exit(void)

{

     if (IO_mem_resource!=NULL) release_mem_region(0x56000050, 0x0c);

     cdev_del(&Virtualmem_devp->cdev);   /*注销cdev*/

     kfree(Virtualmem_devp);    /*释放设备结构体内存*/

     unregister_chrdev_region(MKDEV(Virtualmem_major, 0), 1);     /*释放设备号*/

}

MODULE_AUTHOR("AK-47");

MODULE_LICENSE("Dual BSD/GPL");

module_param(Virtualmem_major, int, S_IRUGO);

module_init(Virtualmem_init);

module_exit(Virtualmem_exit);

3IO内存方式测试代码

#include

#include

#include

#include

#include

#include

#define DEVICE_FILENAME "/dev/iomem"

int main ( )

{

     int dev;

     int loop;

     char buf[128];

     dev = open(DEVICE_FILENAME,O_RDWR|O_NDELAY);

     if (dev >= 0)

     {

         printf("\nwait? input\n");

         printf("write the 0x5f to the Port F!\n");

         buf[0]=0x5f;

         write (dev, buf, 1);

         sleep (2);

         printf("write the 0xaf to the Port F!\n");

         buf[0]=0xaf;

         write (dev, buf, 1);

         sleep (1);

     }

     else

     {

         printf("open failure!\n");

     }

     close (dev);

     return 0;

}

4、驱动程序测试

加载驱动程序后,创建设备节点,然后运行测试程序,由于向LED所在端口先后写了0x5f0xaf,因此会观察到4个发光二极管交替闪亮一次。

阅读(1328) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~