⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtc_fpc.c

📁 IBM source for pallas/vulcan/vesta
💻 C
字号:
//vulcan/drv/rtc_fpc/rtc_fpc.c/*----------------------------------------------------------------------------+||       This source code has been made available to you by IBM on an AS-IS|       basis.  Anyone receiving this source is licensed under IBM|       copyrights to use it in any way he or she deems fit, including|       copying it, modifying it, compiling it, and redistributing it either|       with or without modifications.  No license under IBM patents or|       patent applications is to be implied by the copyright license.||       Any user of this software should understand that IBM cannot provide|       technical support for this software and will not be responsible for|       any consequences resulting from the use of this software.||       Any person who transfers this source code or any derivative work|       must include the IBM copyright notice, this paragraph, and the|       preceding two paragraphs in the transferred software.||       COPYRIGHT   I B M   CORPORATION 1998|       LICENSED MATERIAL  -  PROGRAM PROPERTY OF I B M+----------------------------------------------------------------------------*/#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/devfs_fs_kernel.h>#include <linux/ioctl.h>#include <asm/io.h>#include <asm/uaccess.h>#include "rtc_fpc/rtc_fpc.h"#include "rtc_fpc_local.h"#include "os/pversion.h"#define   RTC_FPC_DRIVER_NAME   "STBx25xx STBRTC"//#define RTC_FPC_DEBUGstatic unsigned char disp_seg_val[] = {0xFC, 0x60, 0xDA, 0xF2, 0x66, 0xB6, 0xBE, 0xE0, 0xFE, 0xF6};static unsigned long   ul_int_rtc;static unsigned long   ul_24hr_fmt;static DECLARE_WAIT_QUEUE_HEAD(wrtc_fpc_q);static unsigned long  ul_alrm_wait;static int rtc_fpc_get_time(STB_RTC_TIME *arg);static int rtc_fpc_set_time(STB_RTC_TIME *arg);static int rtc_fpc_get_alm_time(STB_RTC_TIME *arg);static int rtc_fpc_set_alm_time(STB_RTC_TIME *arg);static void rtc_fpc_interrupt(int irq, void *dev_id, struct pt_regs *pregs); static int rtc_fpc_open(struct inode *inode, struct file *file);static int rtc_fpc_release(struct inode *inode, struct file *file);static int rtc_fpc_ioctl(struct inode *inode, struct file *file, unsigned int ioctl_cmd, unsigned long ioctl_parm);static struct file_operations rtc_fpc_fops = {    open:       rtc_fpc_open,    release:    rtc_fpc_release,     ioctl:      rtc_fpc_ioctl};// just dummy open static int rtc_fpc_open(struct inode *inode, struct file *file){    MOD_INC_USE_COUNT;  // MODULE    return 0;}// just dummy closestatic int rtc_fpc_release(struct inode *inode, struct file *file){    MOD_DEC_USE_COUNT;    return 0;}static int rtc_fpc_get_time(STB_RTC_TIME *pst_stb_rtc){    STB_RTC_TIME   st_rtc_time;  unsigned int   min_10part, min_1part;  unsigned int   hr_10part, hr_1part;  unsigned long  ul_cur_rtc;  unsigned long  flags;  //Protect this read from getting interrupted. Read the rtc register from the interrupt context//Other option is block here till you get the next Update Ended Interrupt so that the real//clock is read. Can protect it with spin_lock_irq, but this would do for time-being for STB system.  save_flags(flags);  cli();  ul_cur_rtc = ul_int_rtc;  restore_flags(flags);//End of block.  st_rtc_time.days = ul_cur_rtc & 0x3F;  st_rtc_time.am_pm = (ul_cur_rtc >> 6) & 0x1;  hr_1part = (ul_cur_rtc >> 8) & 0xF;  hr_10part = (ul_cur_rtc >> 12) & 0x3;  st_rtc_time.hours = hr_10part*10 + hr_1part;  min_1part = (ul_cur_rtc >> 16) & 0xF;  min_10part = (ul_cur_rtc >> 20) & 0x7;  st_rtc_time.mins = min_10part*10 + min_1part;  st_rtc_time.secs = (ul_cur_rtc >> 24) & 0x3F;  copy_to_user(pst_stb_rtc, &st_rtc_time, sizeof(STB_RTC_TIME) );  return 0;}static int rtc_fpc_set_time(STB_RTC_TIME *pst_stb_rtc){  STB_RTC_TIME   st_rtc_time;  unsigned int   min_10part, min_1part;  unsigned int   hr_10part, hr_1part;  unsigned long  val, ul_reg;  copy_from_user(&st_rtc_time, pst_stb_rtc, sizeof(STB_RTC_TIME) );    min_10part = st_rtc_time.mins /10;  min_1part  = st_rtc_time.mins %10;  hr_10part = st_rtc_time.hours /10;  hr_1part = st_rtc_time.hours %10;  val = (st_rtc_time.secs << 24) |        (min_10part << 20) | (min_1part << 16) |        (hr_10part << 12 ) | (hr_1part << 8)   |        (st_rtc_time.am_pm << 6) |        (st_rtc_time.days & 0x3F);  ul_reg = mfdcr(DCR_RTC_FPC_CNTL);  mtdcr(DCR_RTC_FPC_CNTL, (ul_reg & ~0x01000000) );  mtdcr(DCR_RTC_FPC_TIME, val);       mtdcr(DCR_RTC_FPC_CNTL, ul_reg);  return 0;}static int rtc_fpc_get_alm_time(STB_RTC_TIME *pst_stb_rtc){  STB_RTC_TIME   st_alm_time;  unsigned int   min_10part, min_1part;  unsigned int   hr_10part, hr_1part;  unsigned long  ul_cur_alm;  ul_cur_alm = mfdcr(DCR_RTC_FPC_ALRM);  st_alm_time.days = ul_cur_alm & 0x3F;  st_alm_time.am_pm = (ul_cur_alm >> 6) & 0x1;  hr_1part = (ul_cur_alm >> 8) & 0xF;  hr_10part = (ul_cur_alm >> 12) & 0x3;  st_alm_time.hours = hr_10part*10 + hr_1part;  min_1part = (ul_cur_alm >> 16) & 0xF;  min_10part = (ul_cur_alm >> 20) & 0x7;  st_alm_time.mins = min_10part*10 + min_1part;  st_alm_time.secs = (ul_cur_alm >> 24) & 0x3F;  copy_to_user(pst_stb_rtc, &st_alm_time, sizeof(STB_RTC_TIME) );  return 0;}static int rtc_fpc_set_alm_time(STB_RTC_TIME *pst_stb_rtc){  STB_RTC_TIME   st_alm_time;  unsigned int   min_10part, min_1part;  unsigned int   hr_10part, hr_1part;  unsigned long  val;  copy_from_user(&st_alm_time, pst_stb_rtc, sizeof(STB_RTC_TIME) );    min_10part = st_alm_time.mins /10;  min_1part  = st_alm_time.mins %10;  hr_10part = st_alm_time.hours /10;  hr_1part = st_alm_time.hours %10;  val = (st_alm_time.secs << 24) |        (min_10part << 20) | (min_1part << 16) |        (hr_10part << 12 ) | (hr_1part << 8)   |        (st_alm_time.am_pm << 6) |        (st_alm_time.days & 0x3F);  mtdcr(DCR_RTC_FPC_ALRM, val);    return 0;}static int rtc_fpc_ioctl(struct inode *inode, struct file *file, unsigned int ioctl_cmd, unsigned long ioctl_parm){  int rc = 0;  unsigned long ul_regs; #ifdef RTC_FPC_DEBUG  printk("rtc_fpc_ioctl: cmd %d\n", ioctl_cmd);#endif  switch(ioctl_cmd){       case IOC_RTC_FPC_GET_TIME:    rc = rtc_fpc_get_time( (STB_RTC_TIME *)ioctl_parm );    break;       case IOC_RTC_FPC_SET_TIME:    rc = rtc_fpc_set_time( (STB_RTC_TIME *)ioctl_parm );    break;  case IOC_RTC_FPC_GET_ALRM_TIME:    rc = rtc_fpc_get_alm_time( (STB_RTC_TIME *)ioctl_parm );    break;  case IOC_RTC_FPC_SET_ALRM_TIME:    rc = rtc_fpc_set_alm_time( (STB_RTC_TIME *)ioctl_parm );    break;  case IOC_RTC_FPC_SET_FP_DATA:  {    unsigned char dat[5], i;        copy_from_user(dat, (unsigned char *)ioctl_parm, 5);        for(i = 0; i < 5; i++){      if(dat[i] > 9)        dat[i] = 9;    }    mtdcr(DCR_RTC_FPC_D1, (disp_seg_val[dat[0]] << 24) );    mtdcr(DCR_RTC_FPC_D2, (disp_seg_val[dat[1]] << 24) );    mtdcr(DCR_RTC_FPC_D3, (disp_seg_val[dat[2]] << 24) );    mtdcr(DCR_RTC_FPC_D4, (disp_seg_val[dat[3]] << 24) );    mtdcr(DCR_RTC_FPC_D5, (disp_seg_val[dat[4]] << 24) );    break;  }  case IOC_RTC_FPC_ENA_ALMINT:    mtdcr(DCR_RTC_FPC_CNTL, (mfdcr(DCR_RTC_FPC_CNTL) | 0x20000000) );    break;  case IOC_RTC_FPC_DIS_ALMINT:    mtdcr(DCR_RTC_FPC_CNTL, (mfdcr(DCR_RTC_FPC_CNTL) & ~0x20000000) );    break;    case IOC_RTC_FPC_ENA_UPEINT:    mtdcr(DCR_RTC_FPC_CNTL, (mfdcr(DCR_RTC_FPC_CNTL) | 0x10000000) );    break;  case IOC_RTC_FPC_DIS_UPEINT:    mtdcr(DCR_RTC_FPC_CNTL, (mfdcr(DCR_RTC_FPC_CNTL) & ~0x10000000) );    break;  //Front Panel Controller Ioctl  case IOC_RTC_FPC_ENA_DISPDAT:    mtdcr(DCR_RTC_FPC_FCNTL, (mfdcr(DCR_RTC_FPC_FCNTL) & ~0x03000000) );    break;  case IOC_RTC_FPC_ENA_DISPRTC:    mtdcr(DCR_RTC_FPC_FCNTL, (mfdcr(DCR_RTC_FPC_FCNTL) | 0x03000000) );    break;  case IOC_RTC_FPC_SET_24TOFM:    mtdcr(DCR_RTC_FPC_FCNTL, (mfdcr(DCR_RTC_FPC_FCNTL) | 0x04000000) );    ul_24hr_fmt = 1;    break;  case IOC_RTC_FPC_SET_12TOFM:    mtdcr(DCR_RTC_FPC_FCNTL, (mfdcr(DCR_RTC_FPC_FCNTL) & ~0x04000000) );    ul_24hr_fmt = 0;    break;     //This is for a process to wait for Alarm to happen.  case IOC_RTC_FPC_WAIT_FOR_ALRM:    ul_alrm_wait = 1;    ul_regs =  mfdcr(DCR_RTC_FPC_CNTL);       //Put the process to sleep. Alarm time got to be bigger than     //the current time. Otherwise, it would wrap for a long time.    //The process should enable the Alarm interrupt, just be safe    mtdcr(DCR_RTC_FPC_CNTL, (ul_regs | 0x20000000) );    interruptible_sleep_on(&wrtc_fpc_q);    mtdcr(DCR_RTC_FPC_CNTL, ul_regs);    break;  }    return rc;}static void rtc_fpc_interrupt(int irq, void *dev_id, struct pt_regs *pregs){  unsigned long ul_int_stat;  unsigned long ul_cntl_reg;  ul_int_stat = mfdcr(DCR_RTC_FPC_INT);  if(ul_int_stat & 0x10000000){    //Read the real time every time there is Update End Interrupt    //This is assigned to the value when user wants to get the real time.    ul_int_rtc =  mfdcr(DCR_RTC_FPC_TIME);#ifdef RTC_FPC_DEBUG    printk("rtc_fpc_interrupt: Update Ended Interrupt, Time 0x%x\n", (unsigned int) ul_int_rtc);#endif  }   if(ul_int_stat & 0x20000000){#ifdef RTC_FPC_DEBUG    printk("rtc_fpc_interrupt: Alarm Interrupt\n");#endif    //printk("***ALARM INTERRUPT ***\n");    if(ul_alrm_wait){         ul_alrm_wait = 0;         //Wake up the process that was put to sleep         wake_up_interruptible(&wrtc_fpc_q);    }    ul_cntl_reg =  mfdcr(DCR_RTC_FPC_CNTL);      mtdcr(DCR_RTC_FPC_CNTL, (ul_cntl_reg & ~0x20000000) );  }  //Clear the interrupt by writing the bits back into the stat register.  //The UIC interrupt gets cleared through the main interrupt handler.  mtdcr(DCR_RTC_FPC_INT, ul_int_stat);  return;}static devfs_handle_t devfs_handle;static int __init rtc_fpc_init(void){#ifdef RTC_FPC_DEBUG  printk("\nrtc_fpc_init\n");#endif    PVERSION(RTC_FPC_DRIVER_NAME);      if(devfs_register_chrdev(RTC_FPC_DEV_MAJOR, RTC_FPC_DEV_NAME, &rtc_fpc_fops) < 0){    return -1;  }       devfs_handle = devfs_find_handle(NULL, RTC_FPC_DEV_NAME,                                0, 0, DEVFS_SPECIAL_CHR,0);      if(devfs_handle == NULL)  {            devfs_handle = devfs_register(NULL, RTC_FPC_DEV_NAME, DEVFS_FL_DEFAULT,                                RTC_FPC_DEV_MAJOR, 0,                                S_IFCHR | S_IRUSR | S_IWUSR,                                &rtc_fpc_fops, NULL);  }  else    devfs_handle = NULL;  if(request_irq(IRQ_RTCFPC, rtc_fpc_interrupt, SA_INTERRUPT, "stbrtc", NULL) != 0){    printk("rtc_fpc_init: could not install interrupt handler \n");    return -1;   }    mtdcr(DCR_RTC_FPC_CNTL,  0x11000000);  mtdcr(DCR_RTC_FPC_FCNTL, 0x83000000);   return 0;}static void __exit rtc_fpc_exit(void){#ifdef RTC_FPC_DEBUG  printk("\nrtc_fpc_exit\n");#endif  devfs_unregister_chrdev(RTC_FPC_DEV_MAJOR, RTC_FPC_DEV_NAME);  if(devfs_handle != NULL)    devfs_unregister(devfs_handle);  free_irq(IRQ_RTCFPC, NULL);  mtdcr(DCR_RTC_FPC_CNTL,  0x0);  mtdcr(DCR_RTC_FPC_FCNTL, 0x0);  return;}module_init(rtc_fpc_init);module_exit(rtc_fpc_exit);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -