Chinaunix首页 | 论坛 | 博客
  • 博客访问: 151799
  • 博文数量: 40
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 908
  • 用 户 组: 普通用户
  • 注册时间: 2013-09-03 11:03
个人简介

学习linux

文章分类
文章存档

2014年(7)

2013年(33)

我的朋友

分类: 嵌入式

2013-09-04 13:34:10

CPU通过总线和各种设备相连,每种外设都是通过寄存器进行控制。外设可以将寄存器映射到I/O端口或者I/O内存,例如ISA大多映射到端口,而PCI大多映射到内存。这都和RAM内存不同,因为I/O操作都会有边际效应,不能使用高速缓存,也不能发生访问指令重新排序的优化。这不是问题,因为启动内核时告诉了RAM地址和大小,内核不会对其它地址使用高速缓存。

在使用I/O端口前,必须先声明(虽然这不是必须的),确保端口此时别的驱动程序没有使用。不过ARM中都是映射到I/O内存。所以下面只说I/O内存。

对于ram内存,linux都是经过MMU用页表映射的方式访问物理地址的。对于I/O内存基本也是这样的。(不过有的机器,I/O内存访问时没有经过mmu页表,所以也就不需要内核建立页表,arm是不可以这样的,一定要先映射到内核虚拟地址)
还有一种情况:静态映射,即在map_desc结构数组中定义映射关系后,驱动就可以直接用那个虚拟地址的偏移来访问寄存器了。

访问I/O内存:先request_mem_region声明一下(虽然这不是必须的),确保没有其它的驱动程序在使用;再由内核建立页表映射ioremap。
解除映射用iounmap,不再使用I/O内存时用release_mem_region声明。
访问函数:ioread8,ioread16,ioread32;iowrite8,iowrite16,iowrite32;
不应该使用老的接口:readb,readw,readl;writeb,writew,writel;

例子:用上面的知识编写LED驱动程序
头文件:mach/regs-gpio.h定义了大多基地址,可以自定义头文件mach/archer-gpio.h定义详细的寄存器。
源文件:我用misc设备来实现led驱动,在misc/archer-led.c。




点击(此处)折叠或打开

  1. #include <linux/module.h>
  2. #include <linux/types.h>
  3. #include <linux/fs.h>
  4. #include <linux/errno.h>
  5. #include <linux/mm.h>
  6. #include <linux/sched.h>
  7. #include <linux/init.h>
  8. #include <linux/cdev.h>//cdev
  9. #include <asm/io.h>
  10. #include <asm/system.h>
  11. #include <asm/uaccess.h>
  12. #include <linux/slab.h>//kmalloc
  13. //
  14. #include <linux/ioctl.h>
  15. #include <linux/timer.h>
  16. #include <asm/atomic.h>
  17. #include <linux/spinlock.h>
  18. #include <linux/poll.h>
  19. #include <linux/miscdevice.h>
  20. //
  21. #include <mach/map.h>
  22. #include <mach/regs-gpio.h>
  23. #include <mach/archer-gpio.h>


  24. #define DEVICE_NAME "OK6410_LED"
  25. #define DEVICE_MINOR    0
  26. #define LED_ON 0x1
  27. #define LED_OFF 0x2

  28. struct ok6410_led_dev
  29. {
  30.     struct miscdevice misc;
  31.     int open_counter;
  32.     spinlock_t lock;
  33.     struct semaphore sem;
  34. };

  35. struct ok6410_led_dev *ok6410_led_devp;
  36. int device_minor=DEVICE_MINOR;

  37. int ok6410_led_open(struct inode *inode,struct file *filp)
  38. {
  39.     unsigned int reg;
  40.     filp->private_data=ok6410_led_devp;

  41.     spin_lock(&ok6410_led_devp->lock);
  42.     if(ok6410_led_devp->open_counter>0)
  43.     {
  44.         ok6410_led_devp->open_counter++;
  45.         spin_unlock(&ok6410_led_devp->lock);
  46.         printk(KERN_ERR "second open\n");
  47.         return 0;
  48.     }
  49.     ok6410_led_devp->open_counter++;
  50.     spin_unlock(&ok6410_led_devp->lock);
  51.     printk(KERN_ERR "first open\n");
  52.     //
  53.     
  54.     reg=readl(S3C64XX_GPMCON);
  55.     reg&=(~0xffff);
  56.     reg|=0x1111;
  57.     writel(reg,S3C64XX_GPMCON);
  58.     //four bits
  59.     reg=readl(S3C64XX_GPMDAT);
  60.     //all light
  61.     reg&=(~0xf);
  62.     writel(reg,S3C64XX_GPMDAT);

  63.     return 0;
  64. }

  65. int ok6410_led_release(struct inode *inode,struct file *filp)
  66. {
  67.     unsigned int reg;
  68.     spin_lock(&ok6410_led_devp->lock);
  69.     ok6410_led_devp->open_counter--;
  70.     if(ok6410_led_devp->open_counter>0)
  71.     {    
  72.         spin_unlock(&ok6410_led_devp->lock);
  73.         printk(KERN_ERR "second release\n");
  74.         return 0;
  75.     }
  76.     spin_unlock(&ok6410_led_devp->lock);
  77.     printk(KERN_ERR "first release\n");

  78.     reg=readl(S3C64XX_GPMDAT);
  79.     reg|=0xf;
  80.     writel(reg,S3C64XX_GPMDAT);
  81.     reg=readl(S3C64XX_GPMCON);
  82.     reg&=(~0xffff);
  83.     writel(reg,S3C64XX_GPMCON);

  84.     return 0;
  85. }

  86. ssize_t ok6410_led_read(struct file *filp,char __user *buf,
  87.     size_t size,loff_t *ppos)
  88. {
  89.     unsigned char reg;
  90.     struct ok6410_led_dev *dev=filp->private_data;
  91. //    if(down_interrupt(&dev->sem))
  92. //        return -ERESTARTSYS;
  93.     down(&dev->sem);
  94.     reg=readb(S3C64XX_GPMDAT);

  95. /*    if(put_user(reg,(unsigned int *)buf))
  96.         return -EFAULT;
  97.     else
  98.     */
  99.     buf[0]=reg;
  100.     up(&dev->sem);
  101.     return sizeof(unsigned char);    
  102. }

  103. ssize_t ok6410_led_write(struct file *filp,const char __user *buf,
  104.     size_t size,loff_t *ppos)
  105. {
  106.     unsigned char reg;
  107.     struct ok6410_led_dev *dev=filp->private_data;
  108. /*    if(get_user(reg,(unsigned int *)buf))
  109.         return -EFAULT;
  110. */
  111. //    if(down_interrupt(&dev->sem))
  112. //        return -ERESTARTSYS;
  113.     down(&dev->sem);
  114.     reg=readb(S3C64XX_GPMDAT);
  115.     reg&=0xf0;//高位不变
  116.     reg|=buf[0]&0x0f;
  117.     writeb(reg,S3C64XX_GPMDAT);
  118.     up(&dev->sem);
  119.     return sizeof(unsigned char);
  120. }

  121. long ok6410_led_ioctl(struct file *filp,
  122.     unsigned int cmd,unsigned long arg)
  123. {
  124.     unsigned char reg;
  125.     struct ok6410_led_dev *dev=filp->private_data;
  126.     switch(cmd)
  127.     {
  128.         case LED_ON:
  129.             reg=0x00;//0x00 ???
  130. //            if(down_interrupt(&dev->sem))
  131. //                return -ERESTARTSYS;
  132.             down(&dev->sem);
  133.             writeb(reg,S3C64XX_GPMDAT);
  134.             up(&dev->sem);
  135.             break;
  136.         case LED_OFF:
  137.             reg=0x0f;
  138. //            if(down_interrupt(&dev->sem))
  139. //                return -ERESTARTSYS;
  140.             down(&dev->sem);
  141.             writeb(reg,S3C64XX_GPMDAT);
  142.             up(&dev->sem);
  143.             break;
  144.         default:
  145.             return -EINVAL;
  146.     }
  147.     return 0;
  148. }

  149. struct file_operations ok6410_led_fops=
  150. {
  151.     .owner=    THIS_MODULE,
  152.     .open=    ok6410_led_open,
  153.     .release=ok6410_led_release,
  154.     .read=    ok6410_led_read,
  155.     .write=    ok6410_led_write,
  156. //    .ioctl=    ok6410_led_ioctl,
  157.     .unlocked_ioctl = ok6410_led_ioctl,
  158. };
  159. /*
  160. struct miscdevice misc=
  161. {
  162.     .minor= MISC_DYNAMIC_MINOR,
  163.     .name=    DEVICE_NAME,
  164.     .fops=    &ok6410_led_fops,
  165. };
  166. */
  167. int __init ok6410_led_init(void)
  168. {
  169.     int ret;
  170.     //malloc
  171.     ok6410_led_devp=kmalloc(sizeof(struct miscdevice),GFP_KERNEL);
  172.     if(!ok6410_led_devp)
  173.     {
  174.         printk(KERN_ERR "malloc fail\n");
  175.         return -ENOMEM;
  176.     }
  177.     memset(ok6410_led_devp,0,sizeof(struct ok6410_led_dev));

  178.     //set misc
  179.     if(device_minor==0)
  180.         ok6410_led_devp->misc.minor=MISC_DYNAMIC_MINOR;
  181.     else
  182.         ok6410_led_devp->misc.minor=device_minor;
  183.     ok6410_led_devp->misc.name=DEVICE_NAME;
  184.     ok6410_led_devp->misc.fops=&ok6410_led_fops;

  185.     //register cdev
  186.     ret=misc_register(&ok6410_led_devp->misc);
  187.     if(ret<0)
  188.     {
  189.         printk(KERN_ERR "register fail\n");
  190.         kfree(ok6410_led_devp);
  191.         return ret;
  192.     }

  193.     ok6410_led_devp->open_counter=0;
  194.     spin_lock_init(&ok6410_led_devp->lock);
  195.     sema_init(&ok6410_led_devp->sem,1);

  196.     printk(KERN_ERR "register success\n");
  197.     return 0;
  198. }

  199. void __exit ok6410_led_exit(void)
  200. {
  201.     misc_deregister(&ok6410_led_devp->misc);
  202.     kfree(ok6410_led_devp);
  203. }

  204. MODULE_AUTHOR("Archer");
  205. MODULE_LICENSE("Dual BSD/GPL");

  206. module_param(device_minor,int,S_IRUGO);

  207. module_init(ok6410_led_init);
  208. module_exit(ok6410_led_exit);




阅读(1152) | 评论(0) | 转发(0) |
0

上一篇:linux驱动的加载过程

下一篇:从win32到MFC

给主人留下些什么吧!~~