After doing some poking around in the source code for the Zune's clock driver (available free from the Freescale website), I found the root cause of the now-infamous Zune 30 leapyear issue that struck everyone on New Year's Eve.
The Zune's real-time clock stores the time in terms of days and seconds since January 1st, 1980. When the Zune's clock is accessed, the driver turns the number of days into years/months/days and the number of seconds into hours/minutes/seconds. Likewise, when the clock is set, the driver does the opposite.
The Zune frontend first accesses the clock toward the end of the boot sequence. Doing this triggers the code that reads the clock and converts it to a date and time. Below is the part of this code that determines the year component of the date:
Code:
year = ORIGINYEAR; /* = 1980 */
while (days > 365)
{
if (IsLeapYear(year))
{
if (days > 366)
{
days -= 366;
year += 1;
}
}
else
{
days -= 365;
year += 1;
}
}
Under normal circumstances, this works just fine. The function keeps subtracting either 365 or 366 until it gets down to less than a year's worth of days, which it then turns into the month and day of month. Thing is, in the case of the last day of a leap year, it keeps going until it hits 366. Thanks to the if (days > 366), it stops subtracting anything if the loop happens to be on a leap year. But 366 is too large to break out of the main loop, meaning that the Zune keeps looping forever and doesn't do anything else.
The unfortunate part is that there isn't anything that can be done to fix this besides somehow changing what the clock is set to (which is exactly what the battery disconnection trick ends up doing). On the other hand, it shows that Microsoft is correct: tomorrow, everyone's Zunes will operate normally again. However, if Microsoft doesn't fix this part of the firmware, the whole thing will happen all over again in 4 more years.. Hopefully by then a fix will be in place.
That code is pretty simple to correct, it's just a simple enough goof. Just have to recompile the driver, put it into the firmware and send out a firmware update, unless I'm missing something.
I wonder how many people will still be using Zune 30's in 4 years.
Good point.
Quote:
Originally Posted by M&N
That code is pretty simple to correct, it's just a simple enough goof. Just have to recompile the driver, put it into the firmware and send out a firmware update, unless I'm missing something.
Yeah. The ZuneInsider post didn't seem to imply it was something they were planning on correcting right away though.
so how does one disconnect the battery, and is there a way I can trick my zune into thinking its tomorrow by possibly changing the date on my PC?
Disconnecting the battery requires opening it up, which is totally not worth it when it's going to start working again without any further action tomorrow.
AFAIK, the clock is set by downloading a file from Microsoft's DRM servers (to make it hard to mess with the clock and therefore listen to expired Zune Pass tracks), so your PC time doesn't even matter.
I think changing line 263 from "if(days > 366)" to "if(days >= 366)" might fix the bug:
That would prevent the infinite loop, but would introduce a new bug where it advances the year on the last day of a leap year. It would have thought today was December 31, 2009. That's better than locking up, but it also would mean that all time-limited DRM media would stop working. So, if you have a Zune Pass, none of your songs would play.
What's needed is a break within an else like this (I hope, my C's a little rusty, and was never that good to begin with):
Code:
year = ORIGINYEAR; /* = 1980 */
while (days > 365)
{
if (IsLeapYear(year))
{
if (days > 366)
{
days -= 366;
year += 1;
}
else
{
break;
}
}
else
{
days -= 365;
year += 1;
}
}
That would prevent the infinite loop, but would introduce a new bug where it advances the year on the last day of a leap year. It would have thought today was December 31, 2009. That's better than locking up, but it also would mean that all time-limited DRM media would stop working. So, if you have a Zune Pass, none of your songs would play.
What's needed is a break within an else like this (I hope, my C's a little rusty, and was never that good to begin with):
Code:
year = ORIGINYEAR; /* = 1980 */
while (days > 365)
{
if (IsLeapYear(year))
{
if (days > 366)
{
days -= 366;
year += 1;
}
else
{
break;
}
}
else
{
days -= 365;
year += 1;
}
}
Will the break release from the outer if statement? (edit: yes...see below)
This should work too:
Code:
year = ORIGINYEAR; /* = 1980 */
while (days > 365)
{
if (IsLeapYear(year))
{
if (days > 366)
{
days -= 366;
year += 1;
}
else if (days == 366)
days -= 366;
}
else
{
days -= 365;
year += 1;
}
}
Last edited by programphases; 12-31-2008 at 09:10 PM.