Exemple #1
0
static void
convert_from_efi_time(efi_time_t *eft, struct rtc_time *wtime)
{
	memset(wtime, 0, sizeof(*wtime));
	wtime->tm_sec  = eft->second;
	wtime->tm_min  = eft->minute;
	wtime->tm_hour = eft->hour;
	wtime->tm_mday = eft->day;
	wtime->tm_mon  = eft->month - 1;
	wtime->tm_year = eft->year - 1900;

	/* day of the week [0-6], Sunday=0 */
	wtime->tm_wday = compute_wday(eft);

	/* day in the year [1-365]*/
	wtime->tm_yday = compute_yday(eft);


	switch (eft->daylight & EFI_ISDST) {
		case EFI_ISDST:
			wtime->tm_isdst = 1;
			break;
		case EFI_TIME_ADJUST_DAYLIGHT:
			wtime->tm_isdst = 0;
			break;
		default:
			wtime->tm_isdst = -1;
	}
}
Exemple #2
0
static bool
convert_from_efi_time(efi_time_t *eft, struct rtc_time *wtime)
{
	memset(wtime, 0, sizeof(*wtime));

	if (eft->second >= 60)
		return false;
	wtime->tm_sec  = eft->second;

	if (eft->minute >= 60)
		return false;
	wtime->tm_min  = eft->minute;

	if (eft->hour >= 24)
		return false;
	wtime->tm_hour = eft->hour;

	if (!eft->day || eft->day > 31)
		return false;
	wtime->tm_mday = eft->day;

	if (!eft->month || eft->month > 12)
		return false;
	wtime->tm_mon  = eft->month - 1;

	if (eft->year < 1900 || eft->year > 9999)
		return false;
	wtime->tm_year = eft->year - 1900;

	/* day in the year [1-365]*/
	wtime->tm_yday = compute_yday(eft);

	/* day of the week [0-6], Sunday=0 */
	wtime->tm_wday = compute_wday(eft, wtime->tm_yday);

	switch (eft->daylight & EFI_ISDST) {
	case EFI_ISDST:
		wtime->tm_isdst = 1;
		break;
	case EFI_TIME_ADJUST_DAYLIGHT:
		wtime->tm_isdst = 0;
		break;
	default:
		wtime->tm_isdst = -1;
	}

	return true;
}
static int
compute_wday(efi_time_t *eft)
{
	int y;
	int ndays = 0;

	if ( eft->year < 1998 ) {
		printk(KERN_ERR "efirtc: EFI year < 1998, invalid date\n");
		return -1;
	}

	for(y=EFI_RTC_EPOCH; y < eft->year; y++ ) {
		ndays += 365 + (is_leap(y) ? 1 : 0);
	}
	ndays += compute_yday(eft);

	return (ndays + 4) % 7;
}
/*
 * returns day of the week [0-6] 0=Sunday
 *
 * Don't try to provide a year that's before 1998, please !
 */
static int
compute_wday(efi_time_t *eft)
{
	int y;
	int ndays = 0;

	if (eft->year < 1998) {
		pr_err("EFI year < 1998, invalid date\n");
		return -1;
	}

	for (y = EFI_RTC_EPOCH; y < eft->year; y++)
		ndays += 365 + (is_leap_year(y) ? 1 : 0);

	ndays += compute_yday(eft);

	/*
	 * 4=1/1/1998 was a Thursday
	 */
	return (ndays + 4) % 7;
}
/*
 * Handle commands from user-space
 */
static int at91_rtc_ioctl(struct inode *inode, struct file *file,
			  unsigned int cmd, unsigned long arg)
{
	struct rtc_time tm, tm2;
	int ret = 0;

	spin_lock_irq(&at91_rtc_lock);
	switch (cmd) {
	case RTC_AIE_OFF:	/* alarm off */
		AT91_SYS->RTC_IDR = AT91C_RTC_ALARM;
		rtc_irq_data = 0;
		break;
	case RTC_AIE_ON:	/* alarm on */
		AT91_SYS->RTC_IER = AT91C_RTC_ALARM;
		rtc_irq_data = 0;
		break;
	case RTC_UIE_OFF:	/* update off */
		AT91_SYS->RTC_IDR = AT91C_RTC_SECEV;
		rtc_irq_data = 0;
		break;
	case RTC_UIE_ON:	/* update on */
		AT91_SYS->RTC_IER = AT91C_RTC_SECEV;
		rtc_irq_data = 0;
		break;
	case RTC_PIE_OFF:	/* periodic off */
		AT91_SYS->RTC_IDR = AT91C_RTC_SECEV;
		rtc_irq_data = 0;
		break;
	case RTC_PIE_ON:	/* periodic on */
		AT91_SYS->RTC_IER = AT91C_RTC_SECEV;
		rtc_irq_data = 0;
		break;
	case RTC_ALM_READ:	/* read alarm */
		at91_rtc_decodetime(&(AT91_SYS->RTC_TIMALR), &(AT91_SYS->RTC_CALALR), &tm);
		tm.tm_yday = compute_yday(tm.tm_year, tm.tm_mon, tm.tm_mday);
		tm.tm_year = at91_alarm_year - 1900;
		ret = copy_to_user((void *) arg, &tm, sizeof(tm)) ? -EFAULT : 0;
		break;
	case RTC_ALM_SET:	/* set alarm */
		if (copy_from_user(&tm2, (struct rtc_time *) arg, sizeof(tm2)))
			ret = -EFAULT;
		else {
			at91_rtc_decodetime(&(AT91_SYS->RTC_TIMR), &(AT91_SYS->RTC_CALR), &tm);
			at91_alarm_year = tm.tm_year;
			if ((unsigned) tm2.tm_hour < 24)	/* do some range checking */
				tm.tm_hour = tm2.tm_hour;
			if ((unsigned) tm2.tm_min < 60)
				tm.tm_min = tm2.tm_min;
			if ((unsigned) tm2.tm_sec < 60)
				tm.tm_sec = tm2.tm_sec;
			AT91_SYS->RTC_TIMALR = BIN2BCD(tm.tm_sec) << 0
				| BIN2BCD(tm.tm_min) << 8
				| BIN2BCD(tm.tm_hour) << 16
				| AT91C_RTC_HOUREN | AT91C_RTC_MINEN
				| AT91C_RTC_SECEN;
			AT91_SYS->RTC_CALALR = BIN2BCD(tm.tm_mon + 1) << 16	/* tm_mon starts at zero */
				| BIN2BCD(tm.tm_mday) << 24
				| AT91C_RTC_DATEEN | AT91C_RTC_MONTHEN;
		}
		break;
	case RTC_RD_TIME:	/* read time */
		at91_rtc_decodetime(&(AT91_SYS->RTC_TIMR), &(AT91_SYS->RTC_CALR), &tm);
		tm.tm_yday = compute_yday(tm.tm_year, tm.tm_mon, tm.tm_mday);
		tm.tm_year = tm.tm_year - 1900;
		ret = copy_to_user((void *) arg, &tm, sizeof(tm)) ? -EFAULT : 0;
		break;
	case RTC_SET_TIME:	/* set time */
		if (!capable(CAP_SYS_TIME))
			ret = -EACCES;
		else {
			if (copy_from_user(&tm, (struct rtc_time *) arg, sizeof(tm)))
				ret = -EFAULT;
			else {
				int tm_year = tm.tm_year + 1900;
				if (tm_year < EPOCH
				    || (unsigned) tm.tm_mon >= 12
				    || tm.tm_mday < 1
				    || tm.tm_mday > (days_in_mo[tm.tm_mon] + (tm.tm_mon == 1 && is_leap(tm_year)))
				    || (unsigned) tm.tm_hour >= 24
				    || (unsigned) tm.tm_min >= 60
				    || (unsigned) tm.tm_sec >= 60)
					ret = -EINVAL;
				else
					at91_rtc_settime(&tm);
			}
		}
		break;
	case RTC_IRQP_READ:	/* read periodic alarm frequency */
		ret = put_user(AT91_RTC_FREQ, (unsigned long *) arg);
		break;
	case RTC_IRQP_SET:	/* set periodic alarm frequency */
		if (arg != AT91_RTC_FREQ)
			ret = -EINVAL;
		break;
	case RTC_EPOCH_READ:	/* read epoch */
		ret = put_user(EPOCH, (unsigned long *) arg);
		break;
	default:
		ret = -EINVAL;
		break;
	}
	spin_unlock_irq(&at91_rtc_lock);
	return ret;
}