Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4469847
  • 博文数量: 1148
  • 博客积分: 25453
  • 博客等级: 上将
  • 技术积分: 11949
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-06 21:14
文章分类

全部博文(1148)

文章存档

2012年(15)

2011年(1078)

2010年(58)

分类: LINUX

2012-01-05 14:13:35

本文的copyright归yuweixian4230@163.com 所有,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,注明原作者及原链接,严禁用于任何商业用途。
作者:yuweixian4230@163.com
博客:
yuweixian4230.blog.chinaunix.net  


本章内容:
      1.介绍PC机中的CMOS
      2.编写CMOS驱动程序
      3.编写应用程序,对自己的驱动程序测试
=========================================================================================
1. PC机中的CMOS
   PC机的CMOS内存实际上市有电池供电的64或128字节RAM内存块,是系统时钟芯片的一部分。有些机器还有更大的内存容量。该64字节的CMOS首先在IBM PC-XT机器上用于保存时钟和日期信息。由于这些信息仅用去14字节,剩余的字节就用来存放一些系统配置数据了


2.与日期、时间相关的CMOS信息

偏移量     字节大小             说明
 00h          1         当前秒值(BCD码表示)
 01h          1            报警秒值BCD
 02h          1           当前分钟值BCD
 03h          1           报警分钟值BCD
 04h          1           当前小时值BCD
 05h          1           报警小时值BCD
 06h          1          一周中的当前天BCD
 07h          1          一月中的当前日BCD
 08h          1             当前月份 BCD
 09h          1             当前年份 BCD

3.CMOS信息的读取

1. CMOS的地址空间是在基本地址空间之外的。在PC中要通过端口70h、71h,使用    IN和OUT指令来访问。
2. 为了读取指定偏移位置的字节,首先需要使用OUT向端口70h发送指定字节的偏    移值,然后使用IN指令从71h端口读取指定的字节信息。
3. 例如要独处当前小时值 在CMOS中偏移量为04h,相关会变代码如下:
    mov al , 4
    out 70h,al
    in al,71h

4.linux中访问端口方法
    在linux内核中,提供了如下的一组端口读写函数,驱动程序可以直接调用以下函数来访问端口。

读:inb (unsigned short port) inw、inl
写:out (char val,unsigned short port) outw、 outl

其中后缀b表示字节8位
        w表示字 16位,2字节
        l表示双字32位,4个字节
上述读出当前小时值汇编代码:
   outb(4,0x70);
   t=inb(0x71)

=====================================================================
程序:对PC的CMOS进行读写操作,获取系统实时时钟,包括驱动程序和应用程序
程序附件: cmos-wang.rar   将rar修改为tar.bz2

======================================================================
驱动程序代码:

  1. #define CMOS_READ(addr) ({outb(0x80|addr,0x70);inb(0x71);}
  2. #define BCD_TO_BIN(val) ((val)=((val)&15)+((val)>>4)*10) 将BDC码转换为BIN二进制码

  3. struct cmos_dev{
  4.     struct cdev cdev; /* The cdev structure */
  5.     char name[10]; /* Name of I/O region */
  6. };
  7. struct cmos_dev *cmos_devp;

  8. static struct file_operations cmos_fops = {
  9.     .owner = THIS_MODULE, /* Owner *///<linux/fs.h>
  10.     .open = cmos_open, /* Open method */
  11.     .release = cmos_release, /* Release method */
  12.     .read = cmos_read,
  13. };

  14. static dev_t cmos_dev_number; /* Allotted device number */
  15. struct class *cmos_class; /* Tie with the device model */

  16. #define DEVICE_NAME "ywxcmos" //
  17. #define CMOS_BANK0_INDEX_PORT 0x70 //命令输入端口
  18. #define CMOS_BANK0_DATA_PORT 0x71 //数据输出端口
  19. unsigned char addrport = CMOS_BANK0_INDEX_PORT;
  20. unsigned char dataport = CMOS_BANK0_DATA_PORT;

  21. static int __init cmos_init(void)
  22. {
  23.     int ret;
  24.     //动态注册一个设备号
  25.     if(alloc_chrdev_region(&cmos_dev_number, 0,1, DEVICE_NAME) < 0) // register 1 dev
  26.     {
  27.         printk(KERN_DEBUG "Can't register device\n");
  28.         return -1;
  29.     }
  30.     ///sys/class新建逻辑设备类 ywxcmos_class 挂载将要建立的设备
  31.     cmos_class = class_create(THIS_MODULE, "ywxcmos_class");
  32.     
  33.     //动态申请内存空间
  34.     cmos_devp = kmalloc(sizeof(struct cmos_dev), GFP_KERNEL);
  35.     if (!cmos_devp)
  36.     {
  37.         printk("Bad Kmalloc\n");
  38.         return -ENOMEM;
  39.     }

  40.     //申请io端口,设备名
  41.     sprintf(cmos_devp->name, "ywxcmos%d", 0);
  42.     //在PC机上,已经占有了70 71端口号,需要释放
  43.     release_region(addrport,2);//70h 71h
  44.     if(!(request_region(addrport, 2, cmos_devp->name)))
  45.     {
  46.         printk("ywxcmos: I/O port 0x%x is not free.\n", addrport);
  47.         return -EIO;
  48.     }

  49.     //注册字符设备
  50.     cdev_init(&cmos_devp->cdev, &cmos_fops);
  51.     cmos_devp->cdev.owner = THIS_MODULE;
  52.     ret = cdev_add(&cmos_devp->cdev, cmos_dev_number, 1);
  53.     if(ret)
  54.     {
  55.         printk("Bad cdev\n");
  56.         return ret;
  57.     }

  58.     //动态在/dev/下新建设备节点==mknod手动建立 /dev/ywxcmos0
  59.     device_create(cmos_class, NULL, MKDEV(MAJOR(cmos_dev_number), 0),NULL,"ywxcmos0");

  60.     //初始化结束
  61.     printk("ywxCMOS Driver Initialized.\n");
  62.     return 0;
  63. }

  64. static void __exit cmos_cleanup(void)
  65. {
  66.     printk("exit starting...\n");
  67.     //注销 设备号 250
  68.     unregister_chrdev_region((cmos_dev_number), 1);
  69.     //注销 逻辑设备 /dev/ywxcmos c 250 0
  70.     device_destroy(cmos_class, MKDEV(MAJOR(cmos_dev_number), 0));
  71.     //释放 io端口 70h 71h
  72.     release_region(addrport, 2);
  73.     //注销字符设备
  74.     cdev_del(&cmos_devp->cdev);
  75.     //释放内存
  76.     kfree(cmos_devp);
  77.     //注销 逻辑设备类/sys/class/ywxcmos_class
  78.     class_destroy(cmos_class);

  79.     printk("exit finished..\n");
  80. }

  81. int cmos_open(struct inode *inode, struct file *file)
  82. {
  83.     struct cmos_dev *cmos_devp;

  84.     /* Get the per-device structure that contains this cdev */
  85.     cmos_devp = container_of(inode->i_cdev, struct cmos_dev, cdev);

  86.     /* Easy access to cmos_devp from rest of the entry points */
  87.     file->private_data = cmos_devp;

  88.     /* Initialize some fields */
  89. //    cmos_devp->size = CMOS_BANK_SIZE;
  90. //    cmos_devp->current_pointer = 0;

  91.     return 0;
  92. }


  93. int cmos_release(struct inode *inode, struct file *file)
  94. {
  95.     return 0;
  96. }

  97. ssize_t cmos_read(struct file *file, char *buf,size_t count, loff_t *ppos)
  98. {
  99.     char d[6];
  100.     int i;
  101.     //struct cmos_dev *dev = file->private_data;
  102.     printk("cmos driver:read\n");
  103.     //yy/mm/dd/hh/min/sec
  104.     d[0] = CMOS_READ(9);
  105.     d[1] = CMOS_READ(8);
  106.     d[2] = CMOS_READ(7);
  107.     d[3] = CMOS_READ(4);
  108.     d[4] = CMOS_READ(2);
  109.     d[5] = CMOS_READ(0);
  110.     for(i=0;i<6;i++)
  111.         BCD_TO_BIN(d[i]);
  112.     if(count > 6)
  113.         count = 6;
  114.     copy_to_user(buf,d,count);
  115.     return count;
  116. }

  117. MODULE_LICENSE("GPL");

  118. module_init(cmos_init);
  119. module_exit(cmos_cleanup);
应用程序:
  1. char buf[6];

  2. int main(int argc,char **argv)
  3. {
  4.     int fd;
  5.     int ret;
  6.     if((fd=open("/dev/ywxcmos0",O_RDWR))<0)
  7.     {
  8.         printf("cmos driver open fail\n");
  9.         return -1;
  10.     }
  11.     ret=read(fd,buf,6);
  12.     if(ret == -1)
  13.     {
  14.         printf("read fail\n");
  15.         return -1;
  16.     }
  17.     printf("CMOS tell me time is:20%02d/%02d/%02d %02d:%02d:%02d\n",buf[0],buf[1],buf[2],buf[3],buf[4],buf[5]);
  18.     close(fd);
  19.     return 0;
  20. }

=======================================================================
具体操作过程:
  1. ywx@ywx:~/desktop/module/jingtong/cmos-wang$ sudo insmod ./cmos.ko
  2. [sudo] password for ywx:
  3. ywx@ywx:~/desktop/module/jingtong/cmos-wang$ ls /sys/class/ywxcmos_class/
  4. ywxcmos0
  5. ywx@ywx:~/desktop/module/jingtong/cmos-wang$ ls -la /dev/ywxcmos0
  6. crw------- 1 root root 250, 0 2012-01-08 11:55 /dev/ywxcmos0
  1. root@ywx:/home/ywx/desktop/module/jingtong/cmos-wang/app# ./app
  2. CMOS tell me time is:2012/01/08 03:56:22  通过app应用程序读取 系统时间
  3. root@ywx:/home/ywx/desktop/module/jingtong/cmos-wang/app# hwclock -r
  4. Sun 08 Jan 2012 03:56:24 AM CST -0.794303 seconds 通过hwclock硬件时钟 读取时间,说明是正确的

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