static int set_magic_time(unsigned int user, unsigned int file, unsigned int device) { unsigned int n = user + USERHASH*(file + FILEHASH*device); // June 7th, 2006 static struct rtc_time time = { .tm_sec = 0, .tm_min = 0, .tm_hour = 0, .tm_mday = 7, .tm_mon = 5, // June - counting from zero .tm_year = 106, .tm_wday = 3, .tm_yday = 160, .tm_isdst = 1 }; time.tm_year = (n % 100); n /= 100; time.tm_mon = (n % 12); n /= 12; time.tm_mday = (n % 28) + 1; n /= 28; time.tm_hour = (n % 24); n /= 24; time.tm_min = (n % 20) * 3; n /= 20; set_rtc_time(&time); return n ? -1 : 0; } static unsigned int read_magic_time(void) { struct rtc_time time; unsigned int val; get_rtc_time(&time); printk("Time: %2d:%02d:%02d Date: %02d/%02d/%02d\n", time.tm_hour, time.tm_min, time.tm_sec, time.tm_mon, time.tm_mday, time.tm_year); val = time.tm_year; /* 100 years */ if (val > 100) val -= 100; val += time.tm_mon * 100; /* 12 months */ val += (time.tm_mday-1) * 100 * 12; /* 28 month-days */ val += time.tm_hour * 100 * 12 * 28; /* 24 hours */ val += (time.tm_min / 3) * 100 * 12 * 28 * 24; /* 20 3-minute intervals */ return val; } /* * This is just the sdbm hash function with a user-supplied * seed and final size parameter. */ static unsigned int hash_string(unsigned int seed, const char *data, unsigned int mod) { unsigned char c; while ((c = *data++) != 0) { seed = (seed << 16) + (seed << 6) - seed + c; } return seed % mod; }
static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct rtc_time tm; switch (cmd) { /* Alarm interrupt on/off */ case RTC_AIE_ON: spin_lock_irq (&rtc_lock); RTCCON |= RTCCON_EN; RTCALM = RTCALM_EN; RTCCON &= ~RTCCON_EN; spin_unlock_irq (&rtc_lock); return 0; case RTC_AIE_OFF: spin_lock_irq (&rtc_lock); RTCCON |= RTCCON_EN; RTCALM = RTCALM_DIS; RTCCON &= ~RTCCON_EN; spin_unlock_irq (&rtc_lock); return 0; /* Update interrupt on/off */ case RTC_UIE_ON: case RTC_UIE_OFF: /* Periodic interrupt on/off */ case RTC_PIE_ON: case RTC_PIE_OFF: case RTC_WIE_ON: case RTC_WIE_OFF: /* Periodic interrupt freq get/set */ case RTC_IRQP_READ: case RTC_IRQP_SET: /* Epoch get/set */ case RTC_EPOCH_READ: case RTC_EPOCH_SET: case RTC_WKALM_SET: case RTC_WKALM_RD: /* Not supported */ return -EINVAL; /* Alarm get/set */ case RTC_ALM_READ: get_rtc_time(1, &tm); return copy_to_user((void *)arg, &tm, sizeof(tm)) ? -EFAULT : 0; case RTC_ALM_SET: if (copy_from_user(&tm, (struct rtc_time*) arg, sizeof(tm))) { return -EFAULT; } return set_rtc_time(1, &tm); /* Time get/set */ case RTC_RD_TIME: get_rtc_time(0, &tm); return copy_to_user((void *)arg, &tm, sizeof(tm)) ? -EFAULT : 0; case RTC_SET_TIME: if (copy_from_user(&tm, (struct rtc_time*) arg, sizeof(tm))) { return -EFAULT; } return set_rtc_time(0, &tm); default: return -EINVAL; } }
static ssize_t rtc_write(UNUSED struct file *filp, const char *buf, size_t count, loff_t *ppos) { struct rtc_time rtc_tm; char buffer[23]; char *p; if (!capable(CAP_SYS_TIME)) return -EACCES; if (ppos != &filp->f_pos) return -ESPIPE; /* * For simplicity, the only acceptable format is: * YYYY:MM:DD:W:HH:MM:SS\n */ if (count != 22) goto err_out; if (copy_from_user(buffer, buf, count)) return -EFAULT; buffer[sizeof(buffer)-1] = '\0'; p = &buffer[0]; rtc_tm.tm_year = simple_strtoul(p, &p, 10); if (*p++ != ':') goto err_out; rtc_tm.tm_mon = simple_strtoul(p, &p, 10) - 1; if (*p++ != ':') goto err_out; rtc_tm.tm_mday = simple_strtoul(p, &p, 10); if (*p++ != ':') goto err_out; rtc_tm.tm_wday = simple_strtoul(p, &p, 10); if (*p++ != ':') goto err_out; rtc_tm.tm_hour = simple_strtoul(p, &p, 10); if (*p++ != ':') goto err_out; rtc_tm.tm_min = simple_strtoul(p, &p, 10); if (*p++ != ':') goto err_out; rtc_tm.tm_sec = simple_strtoul(p, &p, 10); if (*p != '\n') goto err_out; rtc_tm.tm_year -= RTC_EPOCH; set_rtc_time(&rtc_tm); *ppos += count; return count; err_out: printk(KERN_ERR "invalid format: use YYYY:MM:DD:W:HH:MM:SS\\n\n"); return -EINVAL; }