本章内容:
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进行读写操作,获取系统实时时钟,包括驱动程序和应用程序
======================================================================
驱动程序代码:
-
-
#define CMOS_READ(addr) ({outb(0x80|addr,0x70);inb(0x71);})
-
#define BCD_TO_BIN(val) ((val)=((val)&15)+((val)>>4)*10) 将BDC码转换为BIN二进制码
-
-
struct cmos_dev{
-
struct cdev cdev; /* The cdev structure */
-
char name[10]; /* Name of I/O region */
-
};
-
struct cmos_dev *cmos_devp;
-
-
static struct file_operations cmos_fops = {
-
.owner = THIS_MODULE, /* Owner *///<linux/fs.h>
-
.open = cmos_open, /* Open method */
-
.release = cmos_release, /* Release method */
-
.read = cmos_read,
-
};
-
-
static dev_t cmos_dev_number; /* Allotted device number */
-
struct class *cmos_class; /* Tie with the device model */
-
-
#define DEVICE_NAME "ywxcmos" //
-
#define CMOS_BANK0_INDEX_PORT 0x70 //命令输入端口
-
#define CMOS_BANK0_DATA_PORT 0x71 //数据输出端口
-
unsigned char addrport = CMOS_BANK0_INDEX_PORT;
-
unsigned char dataport = CMOS_BANK0_DATA_PORT;
-
-
static int __init cmos_init(void)
-
{
-
int ret;
-
//动态注册一个设备号
-
if(alloc_chrdev_region(&cmos_dev_number, 0,1, DEVICE_NAME) < 0) // register 1 dev
-
{
-
printk(KERN_DEBUG "Can't register device\n");
-
return -1;
-
}
-
//在/sys/class新建逻辑设备类 ywxcmos_class 挂载将要建立的设备
-
cmos_class = class_create(THIS_MODULE, "ywxcmos_class");
-
-
//动态申请内存空间
-
cmos_devp = kmalloc(sizeof(struct cmos_dev), GFP_KERNEL);
-
if (!cmos_devp)
-
{
-
printk("Bad Kmalloc\n");
-
return -ENOMEM;
-
}
-
-
//申请io端口,设备名
-
sprintf(cmos_devp->name, "ywxcmos%d", 0);
-
//在PC机上,已经占有了70 71端口号,需要释放
-
release_region(addrport,2);//70h 71h
-
if(!(request_region(addrport, 2, cmos_devp->name)))
-
{
-
printk("ywxcmos: I/O port 0x%x is not free.\n", addrport);
-
return -EIO;
-
}
-
-
//注册字符设备
-
cdev_init(&cmos_devp->cdev, &cmos_fops);
-
cmos_devp->cdev.owner = THIS_MODULE;
-
ret = cdev_add(&cmos_devp->cdev, cmos_dev_number, 1);
-
if(ret)
-
{
-
printk("Bad cdev\n");
-
return ret;
-
}
-
-
//动态在/dev/下新建设备节点==mknod手动建立 /dev/ywxcmos0
-
device_create(cmos_class, NULL, MKDEV(MAJOR(cmos_dev_number), 0),NULL,"ywxcmos0");
-
-
//初始化结束
-
printk("ywxCMOS Driver Initialized.\n");
-
return 0;
-
}
-
-
static void __exit cmos_cleanup(void)
-
{
-
printk("exit starting...\n");
-
//注销 设备号 250
-
unregister_chrdev_region((cmos_dev_number), 1);
-
//注销 逻辑设备 /dev/ywxcmos c 250 0
-
device_destroy(cmos_class, MKDEV(MAJOR(cmos_dev_number), 0));
-
//释放 io端口 70h 71h
-
release_region(addrport, 2);
-
//注销字符设备
-
cdev_del(&cmos_devp->cdev);
-
//释放内存
-
kfree(cmos_devp);
-
//注销 逻辑设备类/sys/class/ywxcmos_class
-
class_destroy(cmos_class);
-
-
printk("exit finished..\n");
-
}
-
-
int cmos_open(struct inode *inode, struct file *file)
-
{
-
struct cmos_dev *cmos_devp;
-
-
/* Get the per-device structure that contains this cdev */
-
cmos_devp = container_of(inode->i_cdev, struct cmos_dev, cdev);
-
-
/* Easy access to cmos_devp from rest of the entry points */
-
file->private_data = cmos_devp;
-
-
/* Initialize some fields */
-
// cmos_devp->size = CMOS_BANK_SIZE;
-
// cmos_devp->current_pointer = 0;
-
-
return 0;
-
}
-
-
-
int cmos_release(struct inode *inode, struct file *file)
-
{
-
return 0;
-
}
-
-
ssize_t cmos_read(struct file *file, char *buf,size_t count, loff_t *ppos)
-
{
-
char d[6];
-
int i;
-
//struct cmos_dev *dev = file->private_data;
-
printk("cmos driver:read\n");
-
//yy/mm/dd/hh/min/sec
-
d[0] = CMOS_READ(9);
-
d[1] = CMOS_READ(8);
-
d[2] = CMOS_READ(7);
-
d[3] = CMOS_READ(4);
-
d[4] = CMOS_READ(2);
-
d[5] = CMOS_READ(0);
-
for(i=0;i<6;i++)
-
BCD_TO_BIN(d[i]);
-
if(count > 6)
-
count = 6;
-
copy_to_user(buf,d,count);
-
return count;
-
}
-
-
MODULE_LICENSE("GPL");
-
-
module_init(cmos_init);
-
module_exit(cmos_cleanup);
应用程序:
-
char buf[6];
-
-
int main(int argc,char **argv)
-
{
-
int fd;
-
int ret;
-
if((fd=open("/dev/ywxcmos0",O_RDWR))<0)
-
{
-
printf("cmos driver open fail\n");
-
return -1;
-
}
-
ret=read(fd,buf,6);
-
if(ret == -1)
-
{
-
printf("read fail\n");
-
return -1;
-
}
-
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]);
-
close(fd);
-
return 0;
-
}
=======================================================================
具体操作过程:
-
ywx@ywx:~/desktop/module/jingtong/cmos-wang$ sudo insmod ./cmos.ko
-
[sudo] password for ywx:
-
ywx@ywx:~/desktop/module/jingtong/cmos-wang$ ls /sys/class/ywxcmos_class/
-
ywxcmos0
-
ywx@ywx:~/desktop/module/jingtong/cmos-wang$ ls -la /dev/ywxcmos0
-
crw------- 1 root root 250, 0 2012-01-08 11:55 /dev/ywxcmos0
-
root@ywx:/home/ywx/desktop/module/jingtong/cmos-wang/app# ./app
-
CMOS tell me time is:2012/01/08 03:56:22 通过app应用程序读取 系统时间
-
root@ywx:/home/ywx/desktop/module/jingtong/cmos-wang/app# hwclock -r
-
Sun 08 Jan 2012 03:56:24 AM CST -0.794303 seconds 通过hwclock硬件时钟 读取时间,说明是正确的
阅读(6123) | 评论(0) | 转发(0) |