linux驱动编程--RTC(part one)

来源:互联网 发布:网络机顶盒港澳台直播 编辑:程序博客网 时间:2024/05/19 19:13

一. 逻辑架构

                虽然感觉上面向过程的程序设计好像更加适合提高驱动的效率,但如果愿意牺牲一点效率采用一些面向对象的设计方法对于驱动新手是件比较舒服的事。

                在这次的RTC编程里,为了使结构更加清晰,将整个驱动结构分成了三层,Hardware, Software, rtc.

                Hardware层负责寄存器操作,屏蔽具体的寄存器地址信息。

/** hardware operation*/struct tagHardware;typedef bool (*REG_OPS_R)( struct tagHardware *hthis, uint8 *val);typedef bool (*REG_OPS_W)( struct tagHardware *hthis, uint8 val);struct tagHardware {/** resource*/struct resource*res;struct resource*res_mem;void __iomem*base;/** operation*///control registerREG_OPS_RfuncCon_r;REG_OPS_WfuncCon_w;REG_OPS_RfuncTicnt_r;REG_OPS_WfuncTicnt_w;REG_OPS_RfuncAlm_r;REG_OPS_WfuncAlm_w;//time registerREG_OPS_RfuncSec_r;REG_OPS_WfuncSec_w;REG_OPS_RfuncMin_r;REG_OPS_WfuncMin_w;REG_OPS_RfuncHour_r;REG_OPS_WfuncHour_w;REG_OPS_RfuncDay_r;REG_OPS_WfuncDay_w;REG_OPS_RfuncDate_r;REG_OPS_WfuncDate_w;REG_OPS_RfuncMon_r;REG_OPS_WfuncMon_w;REG_OPS_RfuncYear_r;REG_OPS_WfuncYear_w;//alarm registerREG_OPS_RfuncASec_r;REG_OPS_WfuncASec_w;REG_OPS_RfuncAMin_r;REG_OPS_WfuncAMin_w;REG_OPS_RfuncAHour_r;REG_OPS_WfuncAHour_w;REG_OPS_RfuncADate_r;REG_OPS_WfuncADate_w;REG_OPS_RfuncAMon_r;REG_OPS_WfuncAMon_w;REG_OPS_RfuncAYear_r;REG_OPS_WfuncAYear_w;};

 

                Software层负责将寄存器操作组合成有实际意义的操作,例如打开RTCEN使能,设置tick时钟频率。

struct tagSoftware;typedef bool (*BIT_OPS)( struct tagSoftware *sthis, bool isTure);typedef bool (*SETFREQ)( struct tagSoftware *sthis, int freq);typedef bool (*READTIM)( struct tagSoftware *sthis, struct rtc_time *buf);typedef bool (*SETTIM)( struct tagSoftware *sthis, const struct rtc_time *buf);typedef bool (*SETALMEN)( struct tagSoftware *sthis, uint8 *mask);/** basic operation*/struct tagSoftware {/** resource*/struct tagHardware*Hardware;struct resource*res_tickno;struct resource*res_alarmno;/** public function*/BIT_OPSfuncRtcen;//总开关,在写时需要打开BIT_OPSfuncClksel;//default as 0BIT_OPSfuncCntsel;//default as 0BIT_OPSfuncClkrst;//RTC clock count reset//BIT_OPSfuncInqIRQ_Tick;//enable/disable the irq of tick//BIT_OPSfuncInqIRQ_Alarm;//enable/disable the irq of alarmBIT_OPSfuncInt_en;//tick time interrupt enableSETFREQfuncSetFreq;//0~127SETALMENfuncGetAlmEn;BIT_OPSfuncAlm_en;BIT_OPSfuncYear_en;BIT_OPSfuncMon_en;BIT_OPSfuncDate_en;BIT_OPSfuncHour_en;BIT_OPSfuncMin_en;BIT_OPSfuncSec_en;READTIMfuncGetTime;SETTIMfuncSetTime;READTIMfuncGetAlm;SETTIMfuncSetAlm;};


                在rtc处再负责将一些太过琐碎soft的操作组合成较容易理解的操作,到这一步就已经屏蔽了硬件的具体地址细节,之后就可以专心的实现硬件的具体逻辑细节(比如怎么设置值,怎么使能)。

struct tagRTC_Driver;typedef bool (*RTC_EN)( struct tagRTC_Driver *rthis, bool isTrue);typedef bool (*RTC_TIME_OPS)( struct tagRTC_Driver *rthis, struct rtc_time *buf);typedef bool (*RTC_SETTICKEN)( struct tagRTC_Driver *rthis, bool isTrue);typedef bool (*RTC_SETTICKFREQ)( struct tagRTC_Driver *rthis, int freq);typedef bool (*RTC_SETALARMEN)( struct tagRTC_Driver *rthis, uint8 mask);typedef bool (*RTC_GETALARMEN)( struct tagRTC_Driver *rthid, uint8 *mask);struct tagRTC_Driver {//user operation/** resources*/struct cdevcdev;dev_tdevNum;struct semaphoresem;struct class*pClas;struct device*pDev;struct fasync_struct*async_queue;struct tagSoftware*soft_ops;/** public function*/RTC_ENfuncEn;RTC_TIME_OPSfuncGetTime;RTC_TIME_OPSfuncSetTime;RTC_TIME_OPSfuncGetAlarm;RTC_TIME_OPSfuncSetAlarm;RTC_SETTICKENfuncSetTickEn;RTC_SETTICKFREQfuncSetTickFreq;RTC_SETALARMENfuncSetAlarmEn;RTC_GETALARMENfuncGetAlarmEn;};


                上面的RTC层提供的函数为操作硬件提供了较友好的接口,现在就可以专注内核接口的设计。

二. 一些知识要点

        2.1 异步通知

                异步通知的实现原理较简单,分别从user 和 kernel两条线来看。

                从kernel线,凡是申请了异步通知的进程会被登记到一个队列中。当触发条件到达时,就根据队列中的记录信息通知相应的进程。登记信息用到的函数为

           fasync_helper(int fd,struct file * filp,int on,struct fasync_struct * * fapp)

               根据队列信息通知用户层用到的函数为

           kill_fasync(struct fasync_struct * * fp,int sig,int band)

    

               从user线,一个驱动的通知信息只能到达设备文件,一个进程如果要获取通知信息需要使驱动知道自己,这可以通过 fcntl()实现,以及开通自己在这个文件下的异步通知功能。一般这样

           fcntl( this->fd, F_SETOWN, getpid());           oflags = fcntl( this->fd, F_GETFL);           fcntl( this->fd, F_SETFL, oflags|FASYNC);

        2.2 设备添加

                在设备模型里面,设备--总线--驱动 三个构成了实际的功能。如果驱动依照这个模型来设计,那么还需要实现的是将设备挂载到总线的设备列表中。关于添加方式,在

                        http://blog.csdn.net/u012301943/article/details/23095215
                已经分析过了自己的思路。

 

三. RTC驱动代码

       3.1 driver
//when a tick-irq or alarm-irq arrived, a asynchronous signal ,SIGIO, will be send to user.//a message package , record all information about this interrupt,will be ready for user untill next // interrupt arrive. At this moment, you should read this package immediately to ensure it wouldn't// be lost.#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/cdev.h>#include <asm/uaccess.h>#include <linux/device.h>#include <linux/platform_device.h>#include <asm/io.h>#include <linux/interrupt.h>#include <linux/module.h>#include <linux/fs.h>#include <linux/string.h>#include <linux/init.h>#include <linux/platform_device.h>#include <linux/interrupt.h>#include <linux/bcd.h>#include <linux/clk.h>#include <mach/hardware.h>#include <asm/irq.h>#include "TQ_rtc_drv2.h"typedef  unsigned charuint8;/** relative address*/#define RTC_BASE_ADDR0x57000040//for ensure relative address.#define RTC_END_ADDR0x5700008b#define RELA_ADDR(x)( x -RTC_BASE_ADDR)#define RTCCON_ADDRRELA_ADDR(0x57000040)#define TICNT_ADDRRELA_ADDR(0x57000044)#define RTCALM_ADDRRELA_ADDR(0x57000050)#define ALMSEC_ADDRRELA_ADDR(0x57000054)#define ALMMIN_ADDRRELA_ADDR(0x57000058)#define ALMHOUR_ADDRRELA_ADDR(0x5700005c)#define ALMDATE_ADDRRELA_ADDR(0x57000060)#define ALMMON_ADDRRELA_ADDR(0x57000064)#define ALMYEAR_ADDRRELA_ADDR(0x57000068)#define BCDSEC_ADDRRELA_ADDR(0x57000070)#define BCDMIN_ADDR RELA_ADDR(0x57000074)#define BCDHOUR_ADDRRELA_ADDR(0x57000078)#define BCDDATE_ADDRRELA_ADDR(0x5700007c)#define BCDDAY_ADDRRELA_ADDR(0x57000080)#define BCDMON_ADDRRELA_ADDR(0x57000084)#define BCDYEAR_ADDRRELA_ADDR(0x57000088)/*****************************************************************///state: the entire software was divided into three parts: Hardware, Software,// and rtc( user operation)////Hardware: basic register operation//Software: some basic operation for user//rtc: complex operation///*****************************************************************//** hardware operation*/struct tagHardware;typedef bool (*REG_OPS_R)( struct tagHardware *hthis, uint8 *val);typedef bool (*REG_OPS_W)( struct tagHardware *hthis, uint8 val);struct tagHardware {/** resource*/struct resource*res;struct resource*res_mem;void __iomem*base;/** operation*///control registerREG_OPS_RfuncCon_r;REG_OPS_WfuncCon_w;REG_OPS_RfuncTicnt_r;REG_OPS_WfuncTicnt_w;REG_OPS_RfuncAlm_r;REG_OPS_WfuncAlm_w;//time registerREG_OPS_RfuncSec_r;REG_OPS_WfuncSec_w;REG_OPS_RfuncMin_r;REG_OPS_WfuncMin_w;REG_OPS_RfuncHour_r;REG_OPS_WfuncHour_w;REG_OPS_RfuncDay_r;REG_OPS_WfuncDay_w;REG_OPS_RfuncDate_r;REG_OPS_WfuncDate_w;REG_OPS_RfuncMon_r;REG_OPS_WfuncMon_w;REG_OPS_RfuncYear_r;REG_OPS_WfuncYear_w;//alarm registerREG_OPS_RfuncASec_r;REG_OPS_WfuncASec_w;REG_OPS_RfuncAMin_r;REG_OPS_WfuncAMin_w;REG_OPS_RfuncAHour_r;REG_OPS_WfuncAHour_w;REG_OPS_RfuncADate_r;REG_OPS_WfuncADate_w;REG_OPS_RfuncAMon_r;REG_OPS_WfuncAMon_w;REG_OPS_RfuncAYear_r;REG_OPS_WfuncAYear_w;};struct tagSoftware;typedef bool (*BIT_OPS)( struct tagSoftware *sthis, bool isTure);typedef bool (*SETFREQ)( struct tagSoftware *sthis, int freq);typedef bool (*READTIM)( struct tagSoftware *sthis, struct rtc_time *buf);typedef bool (*SETTIM)( struct tagSoftware *sthis, const struct rtc_time *buf);typedef bool (*SETALMEN)( struct tagSoftware *sthis, uint8 *mask);/** basic operation*/struct tagSoftware {/** resource*/struct tagHardware*Hardware;struct resource*res_tickno;struct resource*res_alarmno;/** public function*/BIT_OPSfuncRtcen;//总开关,在写时需要打开BIT_OPSfuncClksel;//default as 0BIT_OPSfuncCntsel;//default as 0BIT_OPSfuncClkrst;//RTC clock count reset//BIT_OPSfuncInqIRQ_Tick;//enable/disable the irq of tick//BIT_OPSfuncInqIRQ_Alarm;//enable/disable the irq of alarmBIT_OPSfuncInt_en;//tick time interrupt enableSETFREQfuncSetFreq;//0~127SETALMENfuncGetAlmEn;BIT_OPSfuncAlm_en;BIT_OPSfuncYear_en;BIT_OPSfuncMon_en;BIT_OPSfuncDate_en;BIT_OPSfuncHour_en;BIT_OPSfuncMin_en;BIT_OPSfuncSec_en;READTIMfuncGetTime;SETTIMfuncSetTime;READTIMfuncGetAlm;SETTIMfuncSetAlm;};static bool hard_rRTCCON( struct tagHardware *hthis, uint8 *val){if( NULL==hthis)return false;if( NULL==hthis->base)return false;*val &=0;*val = readb( hthis->base + RTCCON_ADDR);return true;}static bool hard_wRTCCON( struct tagHardware *hthis, uint8 val){if( NULL==hthis)return false;if( NULL==hthis->base)return false;writeb( val, hthis->base + RTCCON_ADDR);return true;}static bool hard_rTICNT( struct tagHardware *hthis, uint8 *val){if( NULL==hthis)return false;if( NULL==hthis->base)return false;*val &= 0;*val = readb( hthis->base + TICNT_ADDR);return true;}static bool hard_wTICNT( struct tagHardware *hthis, uint8 val){if( NULL==hthis)return false;if( NULL==hthis->base)return false;writeb( val, hthis->base + TICNT_ADDR);return true;}static bool hard_rRTCALM( struct tagHardware *hthis, uint8 *val){if( NULL==hthis)return false;if( NULL==hthis->base)return false;*val &= 0;*val = readb( hthis->base + RTCALM_ADDR);return true;}static bool hard_wRTCALM( struct tagHardware *hthis, uint8 val){if( NULL==hthis)return false;if( NULL==hthis->base)return false;writeb( val, hthis->base + RTCALM_ADDR);return true;}static bool hard_rBCDSEC( struct tagHardware *hthis, uint8 *val){if( NULL==hthis)return false;if( NULL==hthis->base)return false;*val &= 0;*val = readb( hthis->base + BCDSEC_ADDR);return true;}static bool hard_wBCDSEC( struct tagHardware *hthis, uint8 val){if( NULL==hthis)return false;if( NULL==hthis->base)return false;writeb( val, hthis->base + BCDSEC_ADDR);return true;}static bool hard_rBCDMIN( struct tagHardware *hthis, uint8 *val){if( NULL==hthis)return false;if( NULL==hthis->base)return false;*val &= 0;*val = readb( hthis->base + BCDMIN_ADDR);return true;}static bool hard_wBCDMIN( struct tagHardware *hthis, uint8 val){if( NULL==hthis)return false;if( NULL==hthis->base)return false;writeb( val, hthis->base + BCDMIN_ADDR);return true;}static bool hard_rBCDHOUR( struct tagHardware *hthis, uint8 *val){if( NULL==hthis)return false;if( NULL==hthis->base)return false;*val &= 0;*val = readb( hthis->base + BCDHOUR_ADDR);return true;}static bool hard_wBCDHOUR( struct tagHardware *hthis, uint8 val){if( NULL==hthis)return false;if( NULL==hthis->base)return false;writeb( val, hthis->base + BCDHOUR_ADDR);return true;}static bool hard_rBCDDAY( struct tagHardware *hthis, uint8 *val){if( NULL==hthis)return false;if( NULL==hthis->base)return false;*val &= 0;*val = readb( hthis->base + BCDDAY_ADDR);return true;}static bool hard_wBCDDAY( struct tagHardware *hthis, uint8 val){if( NULL==hthis)return false;if( NULL==hthis->base)return false;writeb( val, hthis->base + BCDDAY_ADDR);return true;}static bool hard_rBCDDATE( struct tagHardware *hthis, uint8 *val){if( NULL==hthis)return false;if( NULL==hthis->base)return false;*val &= 0;*val = readb( hthis->base + BCDDATE_ADDR);return true;}static bool hard_wBCDDATE( struct tagHardware *hthis, uint8 val){if( NULL==hthis)return false;if( NULL==hthis->base)return false;writeb( val, hthis->base + BCDDATE_ADDR);return true;}static bool hard_rBCDMON( struct tagHardware *hthis, uint8 *val){if( NULL==hthis)return false;if( NULL==hthis->base)return false;*val &= 0;*val = readb( hthis->base + BCDMON_ADDR);return true;}static bool hard_wBCDMON( struct tagHardware *hthis, uint8 val){if( NULL==hthis)return false;if( NULL==hthis->base)return false;writeb( val, hthis->base + BCDMON_ADDR);return true;}static bool hard_rBCDYEAR( struct tagHardware *hthis, uint8 *val){if( NULL==hthis)return false;if( NULL==hthis->base)return false;*val &= 0;*val = readb( hthis->base + BCDYEAR_ADDR);return true;}static bool hard_wBCDYEAR( struct tagHardware *hthis, uint8 val){if( NULL==hthis)return false;if( NULL==hthis->base)return false;writeb( val, hthis->base + BCDYEAR_ADDR);return true;}static bool hard_rALMSEC( struct tagHardware *hthis, uint8 *val){if( NULL==hthis)return false;if( NULL==hthis->base)return false;*val &= 0;*val = readb( hthis->base + ALMSEC_ADDR);return true;}static bool hard_wALMSEC( struct tagHardware *hthis, uint8 val){if( NULL==hthis)return false;if( NULL==hthis->base)return false;writeb( val, hthis->base + ALMSEC_ADDR);return true;}static bool hard_rALMMIN( struct tagHardware *hthis, uint8 *val){if( NULL==hthis)return false;if( NULL==hthis->base)return false;*val &= 0;*val = readb( hthis->base + ALMMIN_ADDR);return true;}static bool hard_wALMMIN( struct tagHardware *hthis, uint8 val){if( NULL==hthis)return false;if( NULL==hthis->base)return false;writeb( val, hthis->base + ALMMIN_ADDR);return true;}static bool hard_rALMHOUR( struct tagHardware *hthis, uint8 *val){if( NULL==hthis)return false;if( NULL==hthis->base)return false;*val &= 0;*val = readb( hthis->base + ALMHOUR_ADDR);return true;}static bool hard_wALMHOUR( struct tagHardware *hthis, uint8 val){if( NULL==hthis)return false;if( NULL==hthis->base)return false;writeb( val, hthis->base + ALMHOUR_ADDR);return true;}static bool hard_rALMDATE( struct tagHardware *hthis, uint8 *val){if( NULL==hthis)return false;if( NULL==hthis->base)return false;*val &= 0;*val = readb( hthis->base + ALMDATE_ADDR);return true;}static bool hard_wALMDATE( struct tagHardware *hthis, uint8 val){if( NULL==hthis)return false;if( NULL==hthis->base)return false;writeb( val, hthis->base + ALMDATE_ADDR);return true;}static bool hard_rALMMON( struct tagHardware *hthis, uint8 *val){if( NULL==hthis)return false;if( NULL==hthis->base)return false;*val &= 0;*val = readb( hthis->base + ALMMON_ADDR);return true;}static bool hard_wALMMON( struct tagHardware *hthis, uint8 val){if( NULL==hthis)return false;if( NULL==hthis->base)return false;writeb( val, hthis->base + ALMMON_ADDR);return true;}static bool hard_rALMYEAR( struct tagHardware *hthis, uint8 *val){if( NULL==hthis)return false;if( NULL==hthis->base)return false;*val &= 0;*val = readb( hthis->base + ALMYEAR_ADDR);return true;}static bool hard_wALMYEAR( struct tagHardware *hthis, uint8 val){if( NULL==hthis)return false;if( NULL==hthis->base)return false;writeb( val, hthis->base + ALMYEAR_ADDR);return true;}static struct tagHardwarehardwar = {/** resource*/.res = NULL,.res_mem = NULL,.base = NULL,/** public function*///control register.funcCon_r = hard_rRTCCON,.funcCon_w = hard_wRTCCON,.funcTicnt_r = hard_rTICNT,.funcTicnt_w = hard_wTICNT,.funcAlm_r = hard_rRTCALM,.funcAlm_w = hard_wRTCALM,//time register.funcSec_r = hard_rBCDSEC,.funcSec_w = hard_wBCDSEC,.funcMin_r = hard_rBCDMIN,.funcMin_w = hard_wBCDMIN,.funcHour_r = hard_rBCDHOUR,.funcHour_w = hard_wBCDHOUR,.funcDay_r = hard_rBCDDAY,.funcDay_w = hard_wBCDDAY,.funcDate_r = hard_rBCDDATE,.funcDate_w = hard_wBCDDATE,.funcMon_r = hard_rBCDMON,.funcMon_w = hard_wBCDMON,.funcYear_r = hard_rBCDYEAR,.funcYear_w = hard_wBCDYEAR,//alarm.funcASec_r = hard_rALMSEC,.funcASec_w = hard_wALMSEC,.funcAMin_r = hard_rALMMIN,.funcAMin_w = hard_wALMMIN,.funcAHour_r = hard_rALMHOUR,.funcAHour_w = hard_wALMHOUR,.funcADate_r = hard_rALMDATE,.funcADate_w = hard_wALMDATE,.funcAMon_r = hard_rALMMON,.funcAMon_w = hard_wALMMON,.funcAYear_r = hard_rALMYEAR,.funcAYear_w = hard_wALMYEAR,};static bool __RTCCON_BIT(struct tagSoftware *sthis, bool isTrue, uint8 bitval){struct tagHardware*phard;if( NULL==sthis)return false;phard = sthis->Hardware;if( (NULL!=phard)&&(NULL!=phard->funcCon_r)&&(NULL!=phard->funcCon_w) ){uint8reg;if( phard->funcCon_r( phard, &reg) ){if( isTrue)reg |= bitval;elsereg &= (~bitval);return phard->funcCon_w( phard, reg);}}return false;}static bool soft_RTCEN( struct tagSoftware *sthis, bool isTrue)//总开关,在写时需要打开{#define BIT_RTCEN(0x1)return __RTCCON_BIT( sthis, isTrue, BIT_RTCEN);}static bool soft_CLKSEL( struct tagSoftware *sthis, bool isTrue)//default as 0{#define BIT_CLKSEL(0x1<<1)return __RTCCON_BIT( sthis, isTrue, BIT_CLKSEL);}static bool soft_CNTSEL( struct tagSoftware *sthis, bool isTrue)//default as 0{#define BIT_CNTSEL(0x1<<2)return __RTCCON_BIT( sthis, isTrue, BIT_CNTSEL);}static bool soft_CLKRST( struct tagSoftware *sthis, bool isTrue)//RTC clock count reset{#define BIT_CLKRST(0x1<<3)return __RTCCON_BIT( sthis, isTrue, BIT_CLKRST);}static bool soft_SetTickEn( struct tagSoftware*sthis, bool isTrue)//tick time interrupt enable{#define BIT_TICNT_EN(0x1<<7)struct tagHardware*phard;if( NULL==sthis)return false;phard = sthis->Hardware;if( (NULL!=phard)&&(NULL!=phard->funcTicnt_r)&&(NULL!=phard->funcTicnt_w) ){uint8reg;if( phard->funcTicnt_r( phard, &reg) ){if( isTrue)reg |= BIT_TICNT_EN;elsereg &= (~BIT_TICNT_EN);return phard->funcTicnt_w( phard, reg);}}return false;}static bool soft_SetTickFreq( struct tagSoftware *sthis, int freq)//0~127{struct tagHardware*hard ;uint8 val ;if( NULL==sthis)return false;hard = sthis->Hardware;if( (NULL!=hard)&&(NULL!= hard->funcTicnt_r)&&(NULL!= hard->funcTicnt_w)){uint8reg;if( hard->funcTicnt_r( hard, &reg) ){reg &= (BIT_TICNT_EN) ;val = 128/freq -1;reg |= val;return hard->funcTicnt_w( hard, reg);}}return false;}static bool __RTCALM_BIT(struct tagSoftware *sthis, bool isTrue, uint8 bitval){struct tagHardware*phard;if( NULL==sthis)return false;phard = sthis->Hardware;if( (NULL!=phard)&&(NULL!=phard->funcAlm_r)&&(NULL!=phard->funcAlm_w) ){uint8reg;if( phard->funcAlm_r( phard, &reg) ){if( isTrue)reg |= bitval;elsereg &= (~bitval);//printk("========================3, %x \n", reg);return phard->funcAlm_w( phard, reg);}}return false;}static bool soft_GetAlmEn( struct tagSoftware *sthis, uint8 *mask){struct tagHardware*phard;if( NULL==sthis)return false;if( NULL==mask)return false;phard = sthis->Hardware;if( (NULL!=phard)&&(NULL!=phard->funcAlm_r)){return phard->funcAlm_r( phard, mask);}return false;}static bool soft_ALMEN( struct tagSoftware *sthis, bool isTrue)//alarm global enable{#define BIT_ALMEN(0x1<<6)return __RTCALM_BIT( sthis, isTrue, BIT_ALMEN);}static bool soft_YEAREN( struct tagSoftware *sthis, bool isTrue){#define BIT_YEAREN(0x1<<5)return __RTCALM_BIT( sthis, isTrue, BIT_YEAREN);}static bool soft_MONEN( struct tagSoftware *sthis, bool isTrue){#define BIT_MONEN(0x1<<4)return __RTCALM_BIT( sthis, isTrue, BIT_MONEN);}static bool soft_DATEEN( struct tagSoftware *sthis, bool isTrue){#define BIT_DATEEN(0x1<<3)return __RTCALM_BIT( sthis, isTrue, BIT_DATEEN);}static bool soft_HOUREN( struct tagSoftware *sthis, bool isTrue){#define BIT_HOUREN(0x1<<2)return __RTCALM_BIT( sthis, isTrue, BIT_HOUREN);}static bool soft_MINEN( struct tagSoftware *sthis, bool isTrue){#define BIT_MINEN(0x1<<1)return __RTCALM_BIT( sthis, isTrue, BIT_MINEN);}static bool soft_SECEN( struct tagSoftware *sthis, bool isTrue){#define BIT_SECEN(0x1<<0)return __RTCALM_BIT( sthis, isTrue, BIT_SECEN);}static bool soft_GetTIM( struct tagSoftware *sthis, struct rtc_time *buf){struct tagHardware *hard;if( (NULL==sthis)||(NULL==buf) )return false;hard = sthis->Hardware;if( (NULL==hard))return false;if( NULL!=hard->funcSec_r)hard->funcSec_r( hard, &(buf->sec));if( NULL!=hard->funcMin_r)hard->funcMin_r( hard, &(buf->min));if( NULL!=hard->funcHour_r)hard->funcHour_r( hard, &(buf->hour));if( NULL!=hard->funcDate_r)hard->funcDate_r( hard, &(buf->date));if( NULL!=hard->funcMon_r)hard->funcMon_r( hard, &(buf->mon));if( NULL!=hard->funcYear_r)hard->funcYear_r( hard, &(buf->year));if( NULL!=hard->funcDay_r)hard->funcDay_r( hard, &(buf->day));return true;}static bool soft_SetTIM( struct tagSoftware *sthis, const struct rtc_time *buf){uint8reg_rtccon;struct tagHardware*hard;if( (NULL==sthis)||(NULL==buf) )return false;//check RTCEN, it must be on if want write to those registers of RTChard = sthis->Hardware;if( (NULL==hard)||(NULL==hard->funcCon_r))return false;hard->funcCon_r( hard, &reg_rtccon);if( (!reg_rtccon)&BIT_RTCEN )return false;//write dateif( NULL!=hard->funcSec_w)hard->funcSec_w( hard, buf->sec);if( NULL!=hard->funcMin_w)hard->funcMin_w( hard, buf->min);if( NULL!=hard->funcHour_w)hard->funcHour_w( hard, buf->hour);if( NULL!=hard->funcDate_w)hard->funcDate_w( hard, buf->date);if( NULL!=hard->funcMon_w)hard->funcMon_w( hard, buf->mon);if( NULL!=hard->funcYear_w)hard->funcYear_w( hard, buf->year);if( NULL!=hard->funcDay_w)hard->funcDay_w( hard, buf->day);return true;}static bool soft_GetALM( struct tagSoftware *sthis, struct rtc_time *buf){struct tagHardware *hard;if( (NULL==sthis)||(NULL==buf) )return false;hard = sthis->Hardware;if( (NULL==hard))return false;if( NULL!=hard->funcASec_r)hard->funcASec_r( hard, &(buf->sec));if( NULL!=hard->funcAMin_r)hard->funcAMin_r( hard, &(buf->min));if( NULL!=hard->funcAHour_r)hard->funcAHour_r( hard, &(buf->hour));if( NULL!=hard->funcADate_r)hard->funcADate_r( hard, &(buf->date));if( NULL!=hard->funcAMon_r)hard->funcAMon_r( hard, &(buf->mon));if( NULL!=hard->funcAYear_r)hard->funcAYear_r( hard, &(buf->year));return true;}static bool soft_SetALM( struct tagSoftware *sthis,const struct rtc_time *buf){uint8reg_rtccon;struct tagHardware*hard;if( (NULL==sthis)||(NULL==buf) )return false;//check RTCEN, it must be on if want write to those registers of RTChard = sthis->Hardware;if( (NULL==hard)||(NULL==hard->funcCon_r))return false;hard->funcCon_r( hard, &reg_rtccon);if( (!reg_rtccon)&BIT_RTCEN )return false;//write dateif( NULL!=hard->funcASec_w)hard->funcASec_w( hard, buf->sec);if( NULL!=hard->funcAMin_w)hard->funcAMin_w( hard, buf->min);if( NULL!=hard->funcAHour_w)hard->funcAHour_w( hard, buf->hour);if( NULL!=hard->funcADate_w)hard->funcADate_w( hard, buf->date);if( NULL!=hard->funcAMon_w)hard->funcAMon_w( hard, buf->mon);if( NULL!=hard->funcAYear_w)hard->funcAYear_w( hard, buf->year);return true;}static struct tagSoftwaresoft = {/** resource*/.Hardware = &hardwar,/** public function*/.funcRtcen = soft_RTCEN,//总开关,在写时需要打开.funcClksel = soft_CLKSEL,//default as 0.funcCntsel = soft_CNTSEL,//default as 0.funcClkrst = soft_CLKRST,//RTC clock count reset.funcInt_en = soft_SetTickEn,//tick time interrupt enable.funcSetFreq = soft_SetTickFreq,//0~127.funcGetAlmEn= soft_GetAlmEn,.funcAlm_en = soft_ALMEN,.funcYear_en = soft_YEAREN,.funcMon_en = soft_MONEN,.funcDate_en = soft_DATEEN,.funcHour_en = soft_HOUREN,.funcMin_en = soft_MINEN,.funcSec_en = soft_SECEN,.funcGetTime = soft_GetTIM,.funcSetTime = soft_SetTIM,.funcGetAlm = soft_GetALM,.funcSetAlm = soft_SetALM,};/**********************device************************************//*****************************************************************/#define RTC_CLAS_NAME"clas_rtc_test"#define RTC_NAME"rtc_test"#define RTC_DRV_NAME"rtc_drv_test"#define MAJOR_NUM0//自动申请设备号#define MINOR_NUM0struct tagRTC_Driver;typedef bool (*RTC_EN)( struct tagRTC_Driver *rthis, bool isTrue);typedef bool (*RTC_TIME_OPS)( struct tagRTC_Driver *rthis, struct rtc_time *buf);typedef bool (*RTC_SETTICKEN)( struct tagRTC_Driver *rthis, bool isTrue);typedef bool (*RTC_SETTICKFREQ)( struct tagRTC_Driver *rthis, int freq);typedef bool (*RTC_SETALARMEN)( struct tagRTC_Driver *rthis, uint8 mask);typedef bool (*RTC_GETALARMEN)( struct tagRTC_Driver *rthid, uint8 *mask);struct tagRTC_Driver {//user operation/** resources*/struct cdevcdev;dev_tdevNum;struct semaphoresem;struct class*pClas;struct device*pDev;struct fasync_struct*async_queue;struct tagSoftware*soft_ops;/** public function*/RTC_ENfuncEn;RTC_TIME_OPSfuncGetTime;RTC_TIME_OPSfuncSetTime;RTC_TIME_OPSfuncGetAlarm;RTC_TIME_OPSfuncSetAlarm;RTC_SETTICKENfuncSetTickEn;RTC_SETTICKFREQfuncSetTickFreq;RTC_SETALARMENfuncSetAlarmEn;RTC_GETALARMENfuncGetAlarmEn;};static bool rtc_en( struct tagRTC_Driver *rthis, bool isTrue){struct tagSoftware*soft;if( NULL==rthis)return false;soft = rthis->soft_ops;if( NULL==soft)return false;if( isTrue ){if( ( NULL!=soft->funcRtcen)&&(NULL!=soft->funcClksel)&&(NULL!=soft->funcCntsel)&&(NULL!=soft->funcClkrst) ){soft->funcRtcen( soft, true);soft->funcClksel( soft, false);soft->funcCntsel( soft, false);soft->funcClkrst( soft, false);}}else{if( (NULL!=soft->funcRtcen)&&(NULL!=soft->funcInt_en)){soft->funcRtcen( soft, false);soft->funcInt_en( soft, false);}}return true;}static bool rtc_GetTime( struct tagRTC_Driver *rthis, struct rtc_time *buf){struct tagSoftware*soft ;if( (NULL==rthis)||(NULL==buf) )return false;soft = rthis->soft_ops;if( (NULL!=soft)&&(NULL!=soft->funcGetTime))return soft->funcGetTime( soft, buf);return true;}static bool rtc_setTime( struct tagRTC_Driver *rthis, struct rtc_time *buf){struct tagSoftware*soft;if( (NULL==rthis)||(NULL==buf) )return false;soft = rthis->soft_ops;if( (NULL!=soft)&&(NULL!=soft->funcSetTime)){return soft->funcSetTime( soft, buf);}return true;}static bool rtc_GetAlarm( struct tagRTC_Driver *rthis, struct rtc_time *buf){struct tagSoftware*soft ;if( (NULL==rthis)||(NULL==buf) )return false;soft = rthis->soft_ops;if( (NULL!=soft)&&(NULL!=soft->funcGetAlm))return soft->funcGetAlm( soft, buf);return true;}static bool rtc_setAlarm( struct tagRTC_Driver *rthis, struct rtc_time *buf){struct tagSoftware*soft;if( (NULL==rthis)||(NULL==buf) )return false;soft = rthis->soft_ops;if( (NULL!=soft)&&(NULL!=soft->funcSetAlm)){return soft->funcSetAlm( soft, buf);}return true;}#if 0static bool rtc_setFreq( struct tagRTC_Driver *rthis, int freq, bool isTrue){struct tagSoftware*soft ;if( NULL==rthis)return false;soft = rthis->soft_ops;if( ( NULL!=soft)&&( NULL!=soft->funcInt_en)&&( soft->funcInt_en( soft, isTrue) ) ){freq%=128;return soft->funcSetFreq( soft, freq);}return false;}#endifstatic bool rtc_SetTickEn( struct tagRTC_Driver *rthis, bool isTrue){struct tagSoftware*soft;if( NULL==rthis)return false;soft = rthis->soft_ops;if( ( NULL!=soft)&&( NULL!=soft->funcInt_en) ){return soft->funcInt_en( soft, isTrue);}return false;}static bool rtc_SetTickFreq( struct tagRTC_Driver *rthis, int freq){struct tagSoftware*soft ;if( NULL==rthis)return false;soft = rthis->soft_ops;if( ( NULL!=soft)&&( NULL!=soft->funcSetFreq) ){freq%=128;return soft->funcSetFreq( soft, freq);}return false;}static bool _rtc_SetBit( struct tagSoftware *soft, BIT_OPS func, int mask, int x){bool val;if( NULL==func)return false;val = GETBIT(mask,x);return func( soft, val);}// 1 meaning for enablestatic bool rtc_SetAlarmEn( struct tagRTC_Driver *rthis, uint8 mask){struct tagSoftware*soft;boolret = true;if( NULL==rthis)return false;soft = rthis->soft_ops;if( NULL==soft)return false;if(!_rtc_SetBit( soft, soft->funcSec_en, mask, 0))ret = false;if(!_rtc_SetBit( soft, soft->funcMin_en, mask, 1))ret = false;if(!_rtc_SetBit( soft, soft->funcHour_en, mask, 2))ret = false;if(!_rtc_SetBit( soft, soft->funcDate_en, mask, 3))ret = false;if(!_rtc_SetBit( soft, soft->funcMon_en, mask, 4))ret = false;if(!_rtc_SetBit( soft, soft->funcYear_en, mask, 5))ret = false;if(!_rtc_SetBit( soft, soft->funcAlm_en, mask, 6))ret = false;return ret;}static bool rtc_GetAlarmEn( struct tagRTC_Driver *rthis, uint8 *mask){struct tagSoftware*soft;if( NULL==rthis)return false;soft = rthis->soft_ops;if(  (NULL!=soft)&&( NULL!=soft->funcGetAlmEn)){return soft->funcGetAlmEn( soft, mask);}return false;}static struct tagRTC_DriverdrvDate = {/** resources*/.soft_ops = &soft,/** public function*/.funcEn= rtc_en,.funcGetTime= rtc_GetTime ,.funcSetTime= rtc_setTime ,.funcGetAlarm= rtc_GetAlarm ,.funcSetAlarm= rtc_setAlarm ,.funcSetTickEn= rtc_SetTickEn ,.funcSetTickFreq= rtc_SetTickFreq ,.funcSetAlarmEn= rtc_SetAlarmEn ,.funcGetAlarmEn= rtc_GetAlarmEn ,};/*********************************************************/#define EVENT_MAX7struct tagEventQueue;typedef bool (*EVE_OPS)( struct tagEventQueue *ethis, struct rtc_event *eve);struct tagEventQueue {/** data*/inthead;inttail;struct rtc_eventqueue[EVENT_MAX];/** function*/EVE_OPSAdd;EVE_OPSGet;};static bool AddEvent( struct tagEventQueue *ethis, struct rtc_event *inEve){if( NULL==ethis)return false;if( NULL==inEve)return false;ethis->queue[ethis->tail] = *inEve;ethis->tail ++;if( ethis->tail>=EVENT_MAX ){ethis->tail = 0;if( ethis->head==0){ethis->head ++;}}return true;}static bool GetEvent( struct tagEventQueue *ethis, struct rtc_event *OutEve){if( NULL==ethis)return false;if( NULL==OutEve)return false;if( ethis->head==ethis->tail){memset( OutEve, 0, sizeof(struct rtc_event));return false;}*OutEve = ethis->queue[ethis->head];ethis->head ++ ;if( ethis->head>=EVENT_MAX)ethis->head = 0;return true;}static struct  tagEventQueueevents = {.head = 0,.tail= 0,.Add = AddEvent ,.Get = GetEvent ,};static irqreturn_t rtc_alarmirq( int irq, void *id){struct rtc_eventEve;printk(" congratulation!!you get alarm-irq\n");Eve.type = rtc_alarm;Eve.data.alarm.irqnum = irq;if( !events.Add( &events, &Eve)){printk("warn: fail to record event information, %s, %d\n", __FILE__, __LINE__);}//a notification will be send to user process.kill_fasync( &(drvDate.async_queue), SIGIO, POLL_IN);return IRQ_HANDLED;}static irqreturn_t rtc_tickirq( int irq, void *id){struct rtc_eventEve;printk(" congratulation!!you get tick-irq, \n");Eve.type = rtc_tick;Eve.data.tick.irqnum = irq;if( !events.Add( &events, &Eve)){printk("warn: fail to record event information, %s, %d\n", __FILE__, __LINE__);}kill_fasync( &(drvDate.async_queue), SIGIO, POLL_IN);return IRQ_HANDLED;}static int rtc_open ( struct inode *id, struct file *fp){//printk("rtc_open...................\n");intret;intirq_tick, irq_alarm;if( down_trylock( &(drvDate.sem))){return -EBUSY;}if( (NULL==drvDate.soft_ops->res_tickno)||(NULL==drvDate.soft_ops->res_alarmno) ){printk("error: invalid resource, %s, %d \n", __FILE__, __LINE__);return -EIO;}irq_tick = drvDate.soft_ops->res_tickno->start;ret = request_irq( irq_tick, rtc_tickirq,  IRQF_DISABLED,  "TQ_rtc_drv2 alarm", &drvDate);if (ret) {printk("error : fail to request irq-alarm\n");goto ERR_TICK;}irq_alarm = drvDate.soft_ops->res_alarmno->start;ret = request_irq( irq_alarm, rtc_alarmirq,  IRQF_DISABLED,  "TQ_rtc_drv2 tick", &drvDate);if (ret) {printk("error : fail to request irq-tick\n");goto ERR_ALARM;}/***************tmp*********************************//****************************************************/return 0;free_irq( drvDate.soft_ops->res_alarmno->start, &drvDate);ERR_ALARM:free_irq( drvDate.soft_ops->res_tickno->start, &drvDate);ERR_TICK:up(&(drvDate.sem));return ret;}static int rtc_release ( struct inode *id, struct file *fp){//printk("rtc_release...................\n");intret = 0;intirq_tick, irq_alarm;up(&(drvDate.sem));//close tick closeif( (NULL!=drvDate.funcSetTickEn)&&( !drvDate.funcSetTickEn( &drvDate, false)) ){printk(" error : fail to close tick clock, %s, %d\n", __FILE__, __LINE__);ret = -1;}//release irqif( NULL!=drvDate.soft_ops ){if( NULL!=drvDate.soft_ops->res_tickno){irq_tick = drvDate.soft_ops->res_tickno->start;free_irq( irq_tick, &drvDate);}if( NULL!=drvDate.soft_ops->res_alarmno){irq_alarm = drvDate.soft_ops->res_alarmno->start;free_irq( irq_alarm, &drvDate);}}return ret;}static ssize_t rtc_read ( struct file *fp, char __user *buf, size_t len, loff_t *off){struct rtc_timetime;unsigned longret = 0;if( (NULL!=drvDate.funcGetTime)&&( !(drvDate.funcGetTime( &drvDate, &time)))){return 0;}ret = copy_to_user( buf, &time, len);if( ret<0){printk("warn: fail to copy data to user,  %s, %d\n", __FILE__, __LINE__);return 0;}return len;}static ssize_t rtc_write ( struct file *fp, const char __user *buf, size_t len, loff_t *off){//void __iomem *base = rtcData.addr.base;struct rtc_timetime;//unsigned long ret = 0;//printk("rtc_write...................\n");memset( &time, 0, sizeof(struct rtc_time));len = copy_from_user( &time, buf, len);if( (NULL!=drvDate.funcSetTime)&&( drvDate.funcSetTime( &drvDate, &time)) ){return len;//还有len个字节数据没写入}return -1;}static int rtc_ioctl(struct inode *in, struct file *fp, unsigned int cmd, unsigned long arg){intret = -1;//printk(" ioctl : %x, %lx\n", cmd, arg);switch( cmd){case CMD_SETTIME:{struct rtc_time time;memset( &time, 0, sizeof(struct rtc_time));if(copy_from_user( &time, (struct rtc_time *)arg, sizeof(struct rtc_time))){break;}if( (NULL!=drvDate.funcSetTime)&& ( drvDate.funcSetTime( &drvDate, &time)) ){ret = 0;}break;}case CMD_GETTIME:{struct rtc_time time;if( (NULL!=drvDate.funcGetTime)&&( !(drvDate.funcGetTime( &drvDate, &time)))){break;}if( (0!=arg)&&(copy_to_user( (struct rtc_time *)arg, &time, sizeof(struct rtc_time))<0) ){printk("warn: fail to copy data to user,  %s, %d\n", __FILE__, __LINE__);break;}ret = 0;break;}case CMD_SETALARM:{if( 0!=arg){struct rtc_timetime;copy_from_user( &time, (struct rtc_time *)arg, sizeof(struct rtc_time));if( (NULL!=drvDate.funcSetAlarm)&&(drvDate.funcSetAlarm( &drvDate, &time))){ret = 0;}}break;}case CMD_GETALARM:{if( 0!=arg){struct rtc_time time;if( (NULL!=drvDate.funcGetAlarm)&&(drvDate.funcGetAlarm( &drvDate, &time))){copy_to_user( (struct rtc_time *)arg, &time, sizeof(struct rtc_time));ret = 0;}}break;}case CMD_ENTICK:{if( ( NULL!=drvDate.funcSetTickEn)&&(drvDate.funcSetTickEn( &drvDate, true)) ){ret = 0;}break;}case CMD_DISABTICK:{if( ( NULL!=drvDate.funcSetTickEn)&&(drvDate.funcSetTickEn( &drvDate, false)) ){ret = 0;}break;}case CMD_SETFREQ:{int freq = arg%128;if( ( NULL!=drvDate.funcSetTickFreq)&&(drvDate.funcSetTickFreq( &drvDate, freq)) ){ret = 0;}break;}case CMD_SETALARMEN:{intmask = (int)arg;if( ( NULL!=drvDate.funcSetAlarmEn)&&(drvDate.funcSetAlarmEn( &drvDate, mask)) ){ret = 0;}break;}case CMD_GETALARMEN:{if( 0!=arg){int*mask = (int *)arg;if( ( NULL!=drvDate.funcGetAlarmEn)&&(drvDate.funcGetAlarmEn( &drvDate, (uint8 *)mask)) ){ret = 0;}}break;}case CMD_GETEVENT:{struct rtc_eventEve;if( events.Get( &events, &Eve) ){ret = 0;}if( 0!=arg)copy_to_user( (struct rtc_event *)arg, &Eve, sizeof( struct rtc_event));break;}default :printk("warn: invalid command\n");break;}return ret;}static int rtc_fasync(int fd, struct file *filp, int mode){//process, which is alloc aychronous notification, will be record on the queue by the help of this function.return fasync_helper( fd, filp, mode, &(drvDate.async_queue));}static struct file_operations rtc_ops = {.fasync= rtc_fasync ,.open= rtc_open,.release= rtc_release,.read= rtc_read,.write= rtc_write,.ioctl= rtc_ioctl,};/********************************************************************/static int rtc_probe(struct platform_device *dev){printk("rtc_probe............\n");//init cdev_init( &(drvDate.cdev), &rtc_ops);drvDate.devNum = 0;drvDate.cdev.owner = THIS_MODULE;sema_init( &(drvDate.sem), 1);drvDate.pClas = NULL;drvDate.pDev= NULL;drvDate.soft_ops = &soft;//alloc device-numberif( MAJOR_NUM!=0){drvDate.devNum = MKDEV( MAJOR_NUM, MINOR_NUM);if(register_chrdev_region( drvDate.devNum, 1, RTC_DRV_NAME))goto ERR_REG;}else{if(alloc_chrdev_region( &(drvDate.devNum), MINOR_NUM, 1, RTC_DRV_NAME))goto ERR_REG;}//add char-deviceif(cdev_add( &(drvDate.cdev), drvDate.devNum, 1)<0)goto ERR_CDEV;//create classdrvDate.pClas = class_create( THIS_MODULE, RTC_CLAS_NAME);if( NULL==drvDate.pClas)goto ERR_CLAS;//create devicedrvDate.pDev= device_create( drvDate.pClas, NULL, drvDate.devNum, NULL, "rtc_device_test");if( NULL==drvDate.pDev)goto ERR_DEVICE;/***********init device****************************************/drvDate.soft_ops->Hardware->res = platform_get_resource( dev, IORESOURCE_MEM, 0);if( NULL==drvDate.soft_ops->Hardware->res){printk("error: %s, %d\n", __FILE__, __LINE__);goto ERR_DEVICE;}drvDate.soft_ops->res_alarmno = platform_get_resource( dev, IORESOURCE_IRQ, 0);if( NULL==drvDate.soft_ops->res_alarmno){printk("error: %s, %d\n", __FILE__, __LINE__);goto ERR_DEVICE;}drvDate.soft_ops->res_tickno = platform_get_resource( dev, IORESOURCE_IRQ, 1);if( NULL==drvDate.soft_ops->res_tickno){printk("error: %s, %d\n", __FILE__, __LINE__);goto ERR_DEVICE;}drvDate.soft_ops->Hardware->res_mem = request_mem_region( drvDate.soft_ops->Hardware->res->start, drvDate.soft_ops->Hardware->res->end - drvDate.soft_ops->Hardware->res->start + 1, dev->name);if( NULL==drvDate.soft_ops->Hardware->res_mem ){printk("error: %s, %d\n", __FILE__, __LINE__);goto ERR_REQ;} drvDate.soft_ops->Hardware->base = ioremap( drvDate.soft_ops->Hardware->res->start, drvDate.soft_ops->Hardware->res->end - drvDate.soft_ops->Hardware->res->start + 1 );if( NULL==drvDate.soft_ops->Hardware->base){printk("error: %s, %d\n", __FILE__, __LINE__);goto ERR_REMAP;}if( (NULL==drvDate.funcEn)||(!(drvDate.funcEn( &drvDate, true)) ) )goto ERR_EN;/***********************************************************/return 0;//返回0表示接受这次探测ERR_EN:iounmap( drvDate.soft_ops->Hardware->base);ERR_REMAP:release_resource( drvDate.soft_ops->Hardware->res_mem);ERR_REQ:device_destroy( drvDate.pClas, drvDate.devNum);ERR_DEVICE:class_destroy( drvDate.pClas);ERR_CLAS:cdev_del( &(drvDate.cdev));ERR_CDEV:unregister_chrdev_region( drvDate.devNum, 1);ERR_REG:return -1;}static int rtc_remove( struct platform_device *dev){printk(" rtc_remove.........................\n");if( NULL!=drvDate.funcEn)drvDate.funcEn( &drvDate, false);iounmap(drvDate.soft_ops->Hardware->base);release_resource( drvDate.soft_ops->Hardware->res_mem);device_destroy( drvDate.pClas, drvDate.devNum);class_destroy( drvDate.pClas);cdev_del( &(drvDate.cdev));unregister_chrdev_region( drvDate.devNum, 1);return 0;}static struct platform_driver rtc_drv = {.probe = rtc_probe,.remove = rtc_remove,.driver = {.name = RTC_NAME,.owner = THIS_MODULE,},};static int __init rtc_init( void){printk("vision : %s\n", __TIME__);return platform_driver_register( &rtc_drv);}static void __exit rtc_exit( void){printk("vision : %s\n", __TIME__);platform_driver_unregister( &rtc_drv);}MODULE_LICENSE("GPL");module_init( rtc_init);module_exit( rtc_exit);

 

       3.2 device
#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/cdev.h>#include <asm/uaccess.h>#include <linux/device.h>#include <linux/platform_device.h>#include <asm/irq.h>#define RTC_NAME"rtc_test"#define RTC_BASE_ADDR0x57000040#define RTC_END_ADDR0x5700008bstatic struct resource rtc_res[] = {[0] = {.start = RTC_BASE_ADDR,.end = RTC_END_ADDR,.flags = IORESOURCE_MEM,},[1] = {.start = IRQ_RTC,.end   = IRQ_RTC,.flags = IORESOURCE_IRQ,},[2] = {.start = IRQ_TICK,.end   = IRQ_TICK,.flags = IORESOURCE_IRQ},};static struct platform_devicertc_dev = {.name = RTC_NAME,.id = 0,.num_resources = ARRAY_SIZE(rtc_res),.resource = rtc_res,};static int __init rtc_init( void){printk("%s\n", __TIME__);return platform_device_register( &(rtc_dev));}static void __exit rtc_exit( void){printk("%s\n", __TIME__);platform_device_unregister( &rtc_dev);}MODULE_LICENSE("GPL");module_init( rtc_init);module_exit( rtc_exit);


 

 

 

 

0 0