mini2440 rtc时钟设备驱动开发源代码(宋宝华框架)

来源:互联网 发布:ubuntu 压缩软件 编辑:程序博客网 时间:2024/04/28 17:58

/*********************************************************************************

mini2440 rtc时钟设备驱动开发源代码(宋宝华框架)

********************************************************************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>


//使用宋宝华推荐的普通字符设备框架
#include <linux/fcntl.h>
#include <linux/cdev.h>
#include <linux/version.h>
#include <linux/vmalloc.h>
#include <linux/ctype.h>
#include <linux/pagemap.h>

#include <linux/device.h>


#include <asm/io.h> 
//#include <asm/arch/regs-gpio.h>  //2.6.12
#include <mach/regs-gpio.h>    // 2.6.32


static void __iomem *rtc_base;
static void __iomem *alm_base;
static void __iomem *bcd_base;

#define rRTCCON (*(volatile unsigned long *)(rtc_base + 0x00))
#define rTICNT (*(volatile unsigned long *)(rtc_base + 0x04))
#define rRTCALM (*(volatile unsigned long *)(rtc_base + 0x0a))

#define rALMSEC (*(volatile unsigned long *)(alm_base + 0x00))
#define rALMMIN (*(volatile unsigned long *)(alm_base + 0x04))
#define rALMHOUR (*(volatile unsigned long *)(alm_base + 0x08))
#define rALMDATE (*(volatile unsigned long *)(alm_base + 0x0c))
#define rALMMON  (*(volatile unsigned long *)(alm_base + 0x10))
#define rALMYEAR  (*(volatile unsigned long *)(alm_base + 0x14))

#define rBCDSEC (*(volatile unsigned long *)(bcd_base + 0x00))
#define rBCDMIN (*(volatile unsigned long *)(bcd_base + 0x04))
#define rBCDHOUR (*(volatile unsigned long *)(bcd_base + 0x08))
#define rBCDDATE (*(volatile unsigned long *)(bcd_base + 0xc))
#define rBCDDAY (*(volatile unsigned long *)(bcd_base + 0x10))
#define rBCDMON  (*(volatile unsigned long *)(bcd_base + 0x14))
#define rBCDYEAR  (*(volatile unsigned long *)(bcd_base + 0x18))

 


#define  LEDOFF 0
#define  LEDON 1
//#define rtc_MAJOR 235  //静态分配
#define rtc_MAJOR 0 //动态分配
#define rtc_MINOR 0

int devmajor =   rtc_MAJOR;
int devminor =   rtc_MINOR;
dev_t dev = 0;
//设备结构
//设备结构
struct rtc_dev
{
 struct cdev cdev;   /* Char device structure*/
 
};
struct TIME_RTC
{
 int year;
 int mon;
 int day;  //周
 int date;
 int hour;
 int min;
 int sec;
 
};

struct rtc_dev *rtc_devices;
struct class *my_class; //my_class

int rtc_open(struct inode *inode, struct file *filp)
{ /*
 rRTCCON = (1<<0);
 rTICNT = (1<<7)|(12<<0);
 rRTCALM = 0X3F;
 return 0;*/
 rRTCCON = (0x0<<3)|(0x0<<2)|(0x0<<1)|(0x1<<0);
 //rTICNT = (0x1<<7)|(12<<0);  //闹钟
 //rRTCALM = (0x1<<6)|(0x1<<5)|(0x1<<4)|(0x1<<3)|(0x1<<2)|(0x1<<1)|(0x1<<0);
 
 return 0;
 
}
int rtc_release(struct inode *inode, struct file *filp)
{
 
 return 0;
}
int rtc_ioctl(struct inode *inode, struct file *filp,unsigned int cmd, unsigned long arg)
{
 
 return 0;
}


//也可以使用rtc_write来替代rtc_ioctl
ssize_t rtc_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
 struct TIME_RTC set_time;
 int len = sizeof(struct TIME_RTC);
 
 /*用户空间->内核空间*/  /*失败返回没有被拷贝的字节数,成功0*/
 if (copy_from_user(&set_time, buf, len))
 {
  printk(" copy_to_user error\n");
  return -EFAULT;
 }
 
 rBCDHOUR = ((set_time.hour/10)<<4)|(set_time.hour%10);
 rBCDMIN = ((set_time.min/10)<<4)|(set_time.min%10);
 rBCDSEC= (set_time.sec/10)<<4|(set_time.sec%10);
 rBCDYEAR = (set_time.year/10)<<4|(set_time.year%10);
 rBCDMON = (set_time.mon/10)<<4|(set_time.mon%10);
 rBCDDATE = (set_time.date/10)<<4|(set_time.date%10);
 rBCDDAY = set_time.day;
 
 /*

 if(set_time.day>7) //设置闹钟
 {
  rALMHOUR = ((set_time.hour/10)<<4)|(set_time.hour%10);
  rALMMIN = ((set_time.min/10)<<4)|(set_time.min%10);
  rALMSEC= (set_time.sec/10)<<4|(set_time.sec%10);
  rALMYEAR = (set_time.year/10)<<4|(set_time.year%10);
  rALMMON = (set_time.mon/10)<<4|(set_time.mon%10);
  rALMDATE = (set_time.date/10)<<4|(set_time.date%10);
  
 }
 else
 { //设定时间
  rBCDHOUR = ((set_time.hour/10)<<4)|(set_time.hour%10);
  rBCDMIN = ((set_time.min/10)<<4)|(set_time.min%10);
  rBCDSEC= (set_time.sec/10)<<4|(set_time.sec%10);
  rBCDYEAR = (set_time.year/10)<<4|(set_time.year%10);
  rBCDMON = (set_time.mon/10)<<4|(set_time.mon%10);
  rBCDDATE = (set_time.date/10)<<4|(set_time.date%10);
  rBCDDAY = set_time.day;

 }

*/
 
 return 0;
}

ssize_t rtc_read(struct file *filp,char __user *buf,size_t size,loff_t *offp)
{
 struct TIME_RTC rtc_time;
 int len=sizeof(struct TIME_RTC);
 rtc_time.year = rBCDYEAR;
 rtc_time.year = (rtc_time.year>>4)*10+(rtc_time.year & 0xf);
 rtc_time.mon = rBCDMON;
 rtc_time.mon = (rtc_time.mon>>4)*10+(rtc_time.mon & 0xf);
 rtc_time.date = rBCDDATE;
 rtc_time.date = (rtc_time.date>>4)*10 + (rtc_time.date & 0xf);
 rtc_time.day = rBCDDAY;
 rtc_time.hour = rBCDHOUR;
 rtc_time.hour = (rtc_time.hour>>4)*10+(rtc_time.hour & 0xf);
 rtc_time.min = rBCDMIN;
 rtc_time.min = (rtc_time.min>>4)*10 + (rtc_time.min & 0xf);
 rtc_time.sec = rBCDSEC;
 rtc_time.sec =(rtc_time.sec>>4)*10 + (rtc_time.sec & 0xf);
 

 /*内核空间->用户空间*/
 if (copy_to_user(buf, &rtc_time, len))  //从指针当前位置开始读故+p
 {
  printk("copy_to_user error\n");
  return  - EFAULT; /* Bad address 错误的地址*/
 }
 
 return 0;
}

struct file_operations rtc_fops = {
 .owner = THIS_MODULE,
 .ioctl = rtc_ioctl,
 .open = rtc_open,
 .write = rtc_write,
 .read =  rtc_read,
 .release=rtc_release,
};

/*******************************************************
                MODULE ROUTINE
*******************************************************/

//卸载
void rtc_cleanup_module(void)
{
 //dev_t devno = MKDEV(rtc_MAJOR, rtc_MINOR);
 
 iounmap(rtc_base);
 iounmap(alm_base);
 iounmap(bcd_base);
 
 if (rtc_devices)
 {
  cdev_del(&rtc_devices->cdev);//5 从系统中移除一个字符设备
  kfree(rtc_devices);
 }
 device_destroy(my_class, MKDEV(devmajor, 0));         //delete device node under /dev
 class_destroy(my_class);                               //delete class created by us
 unregister_chrdev_region(dev,1);// 6 释放设备编号
}
//挂载
int rtc_init_module(void)
{
 int result;

 if(devmajor)
 {
  dev = MKDEV(devmajor, devminor); // 1 获得设备号
  result = register_chrdev_region(dev, 1, "rtc_driver"); // 2 分配设备编号
 }
 else
 {
  result = alloc_chrdev_region(&dev, devminor, 1, "rtc_driver");
 // //2  动态分配设备编号
  devmajor = MAJOR(dev);
 }
 if (result < 0)
 {
  printk(KERN_WARNING "scull: can't get major %d\n", devmajor);
  return result;
 }
 
 printk(KERN_WARNING "led get major: %d\n", devmajor);
 rtc_devices = kmalloc(sizeof(struct rtc_dev), GFP_KERNEL);//分配内存给本设备结构体

 if (!rtc_devices)
 {
  result = -ENOMEM;
  goto fail;
 }
 
 memset(rtc_devices, 0, sizeof(struct rtc_dev));

 cdev_init(&rtc_devices->cdev, &rtc_fops);//(1)  // 字符设备的注册,即将结构嵌入到自己的设备中
 rtc_devices->cdev.owner = THIS_MODULE;
 rtc_devices->cdev.ops = &rtc_fops; //(2)
 result = cdev_add (&rtc_devices->cdev, dev, 1);// 4 把本设备放内核中
 if(result)
 {
  printk(KERN_NOTICE "Error %d adding rtc\n", result);
  goto fail;
 }
  //创建节点方法2  使用函数自动创建  方法1是手动创建#mknod /dev/test c 235 0
// 下面方法2.6.32支持。2.6.18 2.6.12不支持

    /* create your own class under /sysfs   2.6.32*/
   my_class = class_create(THIS_MODULE, "my_class");
   if(IS_ERR(my_class))
   {
     printk("Err: failed in creating class.\n");
     return -1;
    }
 
   /* register your own device in sysfs, and this will cause udev to create corresponding device node */
    device_create( my_class, NULL, MKDEV(devmajor, 0),  NULL, "rtc_driver");

 rtc_base = (volatile unsigned *)ioremap((volatile unsigned *)0x57000040,12);
 alm_base = (volatile unsigned *)ioremap((volatile unsigned *)0x57000054,24);
 bcd_base = (volatile unsigned *)ioremap((volatile unsigned *)0x57000070,28);
 return 0;

fail:
 rtc_cleanup_module(); //注销
 return result;
}

module_init(rtc_init_module); //注册
module_exit(rtc_cleanup_module); //注销
MODULE_AUTHOR("hui");
MODULE_LICENSE("GPL");

/*********************************************************************************

/*********************************************************************************

应用程序测试代码

********************************************************************************/


#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MYRTC "/dev/rtc_driver"

void Delay_MS( unsigned int time)  //50 ns
{
 unsigned int i,j;
 
 for ( i=0; i<time; i++)
 {
    for(j=0;j<30000;j++)
    {
   
    } 
   } 
}
struct TIME_RTC
{
 unsigned int year;
 unsigned int mon;
 unsigned int day;  //周
 unsigned int date;
 unsigned int hour;
 unsigned int min;
 unsigned int sec;
 
}TIME_RTC;
int main(void)
{
 int fd,i=0;
 int cmd;
 int status;
 struct TIME_RTC rtc_time;
 printf("the struct TIME_RTC len is: %d\n",sizeof(struct TIME_RTC));
 
       fd = open(MYRTC,O_RDWR,0666);
 if (fd < 0)
 {
  perror("open device rtc_driver error\n");
  exit(1);
 }
 printf("open /dev/rtc_driver success!\n");

 int year,mon,date,day,hour,min,sec;
 
 

 read(fd,&rtc_time,sizeof(struct TIME_RTC));

 printf("************000000***************\n");
 printf("**date:%d - %d -%d\n",rtc_time.year,rtc_time.mon,rtc_time.date);
 printf("**workday:%d\n",rtc_time.day);
 printf("**time:%d : %d : %d\n",rtc_time.hour,rtc_time.min,rtc_time.sec);
 printf("***************************\n");

 printf("please input the date and time that you will set!!\n");
 
 printf("please input year: ");
 scanf("%d",&rtc_time.year);

 printf("please input mon: ");
 scanf("%d",&rtc_time.mon);

 printf("please input date: ");
 scanf("%d",&rtc_time.date);

 printf("please input day: ");
 scanf("%d",&rtc_time.day);

 printf("please input hour: ");
 scanf("%d",&rtc_time.hour); 
 
 printf("please input min: ");
 scanf("%d",&rtc_time.min);
 
 printf("please input sec: ");
 scanf("%d",&rtc_time.sec); 
 write(fd,&rtc_time,sizeof(struct TIME_RTC));
 sleep(5);
 read(fd,&rtc_time,sizeof(struct TIME_RTC));
 printf("the time is :\n");
 printf("***************************\n");
 printf("**date:%d - %d -%d\n",rtc_time.year,rtc_time.mon,rtc_time.date);
 printf("**workday:%d\n",rtc_time.day);
 printf("**time:%d : %d : %d\n",rtc_time.hour,rtc_time.min,rtc_time.sec);
 printf("***************************\n");
 close(fd);
 return 0;
}

原创粉丝点击