Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | /* * Linux/PowerPC Real Time Clock Driver * * heavily based on: * Linux/SPARC Real Time Clock Driver * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu) * * This is a little driver that lets a user-level program access * the PPC clocks chip. It is no use unless you * use the modified clock utility. * * Get the modified clock utility from: * ftp://vger.kernel.org/pub/linux/Sparc/userland/clock.c */ #include <linux/module.h> #include <linux/types.h> #include <linux/errno.h> #include <linux/miscdevice.h> #include <linux/malloc.h> #include <linux/fcntl.h> #include <linux/poll.h> #include <linux/init.h> #include <linux/mc146818rtc.h> #include <asm/system.h> #include <asm/uaccess.h> #include <asm/machdep.h> #include <asm/time.h> static int rtc_busy = 0; /* Retrieve the current date and time from the real time clock. */ void get_rtc_time(struct rtc_time *t) { unsigned long nowtime; nowtime = (ppc_md.get_rtc_time)(); to_tm(nowtime, t); t->tm_year -= 1900; t->tm_mon -= 1; t->tm_wday -= 1; } /* Set the current date and time inthe real time clock. */ void set_rtc_time(struct rtc_time *t) { unsigned long nowtime; printk(KERN_INFO "rtc.c:set_rtc_time: %04d-%02d-%02d %02d:%02d:%02d.\n", t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); nowtime = mktime(t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); printk(KERN_INFO "rtc.c:set_rtc_time: set rtc time to %d seconds.\n", nowtime); (ppc_md.set_rtc_time)(nowtime); } static long long rtc_lseek(struct file *file, long long offset, int origin) { return -ESPIPE; } static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct rtc_time rtc_tm; switch (cmd) { case RTC_RD_TIME: if (ppc_md.get_rtc_time) { get_rtc_time(&rtc_tm); copy_to_user_ret((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time), -EFAULT); return 0; } else return -EINVAL; case RTC_SET_TIME: if (!capable(CAP_SYS_TIME)) return -EPERM; if (ppc_md.set_rtc_time) { copy_from_user_ret(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time), -EFAULT); set_rtc_time(&rtc_tm); return 0; } else return -EINVAL; default: return -EINVAL; } } static int rtc_open(struct inode *inode, struct file *file) { if (rtc_busy) return -EBUSY; rtc_busy = 1; MOD_INC_USE_COUNT; return 0; } static int rtc_release(struct inode *inode, struct file *file) { MOD_DEC_USE_COUNT; rtc_busy = 0; return 0; } static struct file_operations rtc_fops = { rtc_lseek, NULL, /* rtc_read */ NULL, /* rtc_write */ NULL, /* rtc_readdir */ NULL, /* rtc_poll */ rtc_ioctl, NULL, /* rtc_mmap */ rtc_open, NULL, /* flush */ rtc_release }; static struct miscdevice rtc_dev = { RTC_MINOR, "rtc", &rtc_fops }; EXPORT_NO_SYMBOLS; #ifdef MODULE int init_module(void) #else __initfunc(int rtc_init(void)) #endif { int error; error = misc_register(&rtc_dev); if (error) { printk(KERN_ERR "rtc: unable to get misc minor\n"); return error; } return 0; } #ifdef MODULE void cleanup_module(void) { misc_deregister(&rtc_dev); } #endif |