- Timestamp:
- Jun 16, 2011 5:56:26 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/PC/DevRTC.cpp
r35353 r37511 204 204 205 205 #ifndef VBOX_DEVICE_STRUCT_TESTCASE 206 static void rtc_set_time(RTCState *s); 207 static void rtc_copy_date(RTCState *s); 208 209 static void rtc_timer_update(RTCState *s, int64_t current_time) 206 207 static void rtc_timer_update(RTCState *pThis, int64_t current_time) 210 208 { 211 209 int period_code, period; … … 213 211 uint32_t freq; 214 212 215 period_code = s->cmos_data[RTC_REG_A] & 0x0f; 216 if (period_code != 0 && 217 (s->cmos_data[RTC_REG_B] & REG_B_PIE)) { 213 period_code = pThis->cmos_data[RTC_REG_A] & 0x0f; 214 if ( period_code != 0 215 && (pThis->cmos_data[RTC_REG_B] & REG_B_PIE)) 216 { 218 217 if (period_code <= 2) 219 218 period_code += 7; … … 221 220 period = 1 << (period_code - 1); 222 221 /* compute 32 kHz clock */ 223 freq = TMTimerGetFreq( s->CTX_SUFF(pPeriodicTimer));222 freq = TMTimerGetFreq(pThis->CTX_SUFF(pPeriodicTimer)); 224 223 225 224 cur_clock = ASMMultU64ByU32DivByU32(current_time, 32768, freq); 226 225 next_irq_clock = (cur_clock & ~(uint64_t)(period - 1)) + period; 227 s->next_periodic_time = ASMMultU64ByU32DivByU32(next_irq_clock, freq, 32768) + 1;228 TMTimerSet( s->CTX_SUFF(pPeriodicTimer),s->next_periodic_time);226 pThis->next_periodic_time = ASMMultU64ByU32DivByU32(next_irq_clock, freq, 32768) + 1; 227 TMTimerSet(pThis->CTX_SUFF(pPeriodicTimer), pThis->next_periodic_time); 229 228 230 229 #ifdef IN_RING3 231 if (RT_UNLIKELY(period != s->CurLogPeriod))230 if (RT_UNLIKELY(period != pThis->CurLogPeriod)) 232 231 #else 233 if (RT_UNLIKELY(period != s->CurHintPeriod))232 if (RT_UNLIKELY(period != pThis->CurHintPeriod)) 234 233 #endif 235 234 { 236 235 #ifdef IN_RING3 237 if ( s->cRelLogEntries++ < 64)236 if (pThis->cRelLogEntries++ < 64) 238 237 LogRel(("RTC: period=%#x (%d) %u Hz\n", period, period, _32K / period)); 239 s->CurLogPeriod = period;238 pThis->CurLogPeriod = period; 240 239 #endif 241 s->CurHintPeriod = period;242 TMTimerSetFrequencyHint( s->CTX_SUFF(pPeriodicTimer), _32K / period);240 pThis->CurHintPeriod = period; 241 TMTimerSetFrequencyHint(pThis->CTX_SUFF(pPeriodicTimer), _32K / period); 243 242 } 244 } else { 245 if (TMTimerIsActive(s->CTX_SUFF(pPeriodicTimer)) && s->cRelLogEntries++ < 64) 243 } 244 else 245 { 246 if (TMTimerIsActive(pThis->CTX_SUFF(pPeriodicTimer)) && pThis->cRelLogEntries++ < 64) 246 247 LogRel(("RTC: stopped the periodic timer\n")); 247 TMTimerStop( s->CTX_SUFF(pPeriodicTimer));248 TMTimerStop(pThis->CTX_SUFF(pPeriodicTimer)); 248 249 } 249 250 } … … 255 256 } 256 257 257 static void rtc_periodic_timer(void *opaque) 258 { 259 RTCState *s = (RTCState*)opaque; 260 261 rtc_timer_update(s, s->next_periodic_time); 262 s->cmos_data[RTC_REG_C] |= 0xc0; 263 264 rtc_raise_irq(s, 1); 265 } 266 267 static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) 268 { 269 RTCState *s = (RTCState*)opaque; 270 uint32_t bank; 271 272 bank = (addr >> 1) & 1; 273 if ((addr & 1) == 0) { 274 s->cmos_index[bank] = (data & 0x7f) + (bank * 128); 275 } else { 276 Log(("CMOS: Write bank %d idx %#04x: %#04x (old %#04x)\n", bank, 277 s->cmos_index[bank], data, s->cmos_data[s->cmos_index[bank]])); 278 switch(s->cmos_index[bank]) { 279 case RTC_SECONDS_ALARM: 280 case RTC_MINUTES_ALARM: 281 case RTC_HOURS_ALARM: 282 s->cmos_data[s->cmos_index[0]] = data; 283 break; 284 case RTC_SECONDS: 285 case RTC_MINUTES: 286 case RTC_HOURS: 287 case RTC_DAY_OF_WEEK: 288 case RTC_DAY_OF_MONTH: 289 case RTC_MONTH: 290 case RTC_YEAR: 291 s->cmos_data[s->cmos_index[0]] = data; 292 /* if in set mode, do not update the time */ 293 if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { 294 rtc_set_time(s); 295 } 296 break; 297 case RTC_REG_A: 298 /* UIP bit is read only */ 299 s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) | 300 (s->cmos_data[RTC_REG_A] & REG_A_UIP); 301 rtc_timer_update(s, TMTimerGet(s->CTX_SUFF(pPeriodicTimer))); 302 break; 303 case RTC_REG_B: 304 if (data & REG_B_SET) { 305 /* set mode: reset UIP mode */ 306 s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; 307 #if 0 /* This is probably wrong as it breaks changing the time/date in OS/2. */ 308 data &= ~REG_B_UIE; 309 #endif 310 } else { 311 /* if disabling set mode, update the time */ 312 if (s->cmos_data[RTC_REG_B] & REG_B_SET) { 313 rtc_set_time(s); 314 } 315 } 316 s->cmos_data[RTC_REG_B] = data; 317 rtc_timer_update(s, TMTimerGet(s->CTX_SUFF(pPeriodicTimer))); 318 break; 319 case RTC_REG_C: 320 case RTC_REG_D: 321 /* cannot write to them */ 322 break; 323 default: 324 s->cmos_data[s->cmos_index[bank]] = data; 325 break; 326 } 327 } 328 } 329 330 static inline int to_bcd(RTCState *s, int a) 331 { 332 if (s->cmos_data[RTC_REG_B] & 0x04) { 258 259 DECLINLINE(int) to_bcd(RTCState *pThis, int a) 260 { 261 if (pThis->cmos_data[RTC_REG_B] & 0x04) { 333 262 return a; 334 263 } else { … … 337 266 } 338 267 339 static inline int from_bcd(RTCState *s, int a)340 { 341 if ( s->cmos_data[RTC_REG_B] & 0x04) {268 DECLINLINE(int) from_bcd(RTCState *pThis, int a) 269 { 270 if (pThis->cmos_data[RTC_REG_B] & 0x04) { 342 271 return a; 343 272 } else { … … 346 275 } 347 276 348 static void rtc_set_time(RTCState * s)349 { 350 struct my_tm *tm = & s->current_tm;351 352 tm->tm_sec = from_bcd(s,s->cmos_data[RTC_SECONDS]);353 tm->tm_min = from_bcd(s,s->cmos_data[RTC_MINUTES]);354 tm->tm_hour = from_bcd( s,s->cmos_data[RTC_HOURS] & 0x7f);355 if ( !(s->cmos_data[RTC_REG_B] & 0x02) &&356 (s->cmos_data[RTC_HOURS] & 0x80)) {277 static void rtc_set_time(RTCState *pThis) 278 { 279 struct my_tm *tm = &pThis->current_tm; 280 281 tm->tm_sec = from_bcd(pThis, pThis->cmos_data[RTC_SECONDS]); 282 tm->tm_min = from_bcd(pThis, pThis->cmos_data[RTC_MINUTES]); 283 tm->tm_hour = from_bcd(pThis, pThis->cmos_data[RTC_HOURS] & 0x7f); 284 if ( !(pThis->cmos_data[RTC_REG_B] & 0x02) 285 && (pThis->cmos_data[RTC_HOURS] & 0x80)) 357 286 tm->tm_hour += 12; 358 } 359 tm->tm_wday = from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]); 360 tm->tm_mday = from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]); 361 tm->tm_mon = from_bcd(s, s->cmos_data[RTC_MONTH]) - 1; 362 tm->tm_year = from_bcd(s, s->cmos_data[RTC_YEAR]) + 100; 363 } 364 365 static void rtc_copy_date(RTCState *s) 366 { 367 const struct my_tm *tm = &s->current_tm; 368 369 s->cmos_data[RTC_SECONDS] = to_bcd(s, tm->tm_sec); 370 s->cmos_data[RTC_MINUTES] = to_bcd(s, tm->tm_min); 371 if (s->cmos_data[RTC_REG_B] & 0x02) { 372 /* 24 hour format */ 373 s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour); 374 } else { 375 /* 12 hour format */ 376 s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour % 12); 377 if (tm->tm_hour >= 12) 378 s->cmos_data[RTC_HOURS] |= 0x80; 379 } 380 s->cmos_data[RTC_DAY_OF_WEEK] = to_bcd(s, tm->tm_wday); 381 s->cmos_data[RTC_DAY_OF_MONTH] = to_bcd(s, tm->tm_mday); 382 s->cmos_data[RTC_MONTH] = to_bcd(s, tm->tm_mon + 1); 383 s->cmos_data[RTC_YEAR] = to_bcd(s, tm->tm_year % 100); 384 } 287 tm->tm_wday = from_bcd(pThis, pThis->cmos_data[RTC_DAY_OF_WEEK]); 288 tm->tm_mday = from_bcd(pThis, pThis->cmos_data[RTC_DAY_OF_MONTH]); 289 tm->tm_mon = from_bcd(pThis, pThis->cmos_data[RTC_MONTH]) - 1; 290 tm->tm_year = from_bcd(pThis, pThis->cmos_data[RTC_YEAR]) + 100; 291 } 292 293 294 /* -=-=-=-=-=- I/O Port -=-=-=-=-=- */ 295 296 /** 297 * Port I/O Handler for IN operations. 298 * 299 * @returns VBox status code. 300 * 301 * @param pDevIns The device instance. 302 * @param pvUser User argument - ignored. 303 * @param uPort Port number used for the IN operation. 304 * @param pu32 Where to store the result. 305 * @param cb Number of bytes read. 306 */ 307 PDMBOTHCBDECL(int) rtcIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb) 308 { 309 NOREF(pvUser); 310 if (cb != 1) 311 return VERR_IOM_IOPORT_UNUSED; 312 313 RTCState *pThis = PDMINS_2_DATA(pDevIns, RTCState *); 314 if ((Port & 1) == 0) 315 *pu32 = 0xff; 316 else 317 { 318 unsigned bank = (Port >> 1) & 1; 319 switch (pThis->cmos_index[bank]) 320 { 321 case RTC_SECONDS: 322 case RTC_MINUTES: 323 case RTC_HOURS: 324 case RTC_DAY_OF_WEEK: 325 case RTC_DAY_OF_MONTH: 326 case RTC_MONTH: 327 case RTC_YEAR: 328 *pu32 = pThis->cmos_data[pThis->cmos_index[0]]; 329 break; 330 331 case RTC_REG_A: 332 *pu32 = pThis->cmos_data[pThis->cmos_index[0]]; 333 break; 334 335 case RTC_REG_C: 336 *pu32 = pThis->cmos_data[pThis->cmos_index[0]]; 337 rtc_raise_irq(pThis, 0); 338 pThis->cmos_data[RTC_REG_C] = 0x00; 339 break; 340 341 default: 342 *pu32 = pThis->cmos_data[pThis->cmos_index[bank]]; 343 break; 344 } 345 346 Log(("CMOS: Read bank %d idx %#04x: %#04x\n", bank, pThis->cmos_index[bank], *pu32)); 347 } 348 349 return VINF_SUCCESS; 350 } 351 352 353 /** 354 * Port I/O Handler for OUT operations. 355 * 356 * @returns VBox status code. 357 * 358 * @param pDevIns The device instance. 359 * @param pvUser User argument - ignored. 360 * @param uPort Port number used for the IN operation. 361 * @param u32 The value to output. 362 * @param cb The value size in bytes. 363 */ 364 PDMBOTHCBDECL(int) rtcIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb) 365 { 366 NOREF(pvUser); 367 if (cb != 1) 368 return VINF_SUCCESS; 369 370 RTCState *pThis = PDMINS_2_DATA(pDevIns, RTCState *); 371 uint32_t bank = (Port >> 1) & 1; 372 if ((Port & 1) == 0) 373 { 374 pThis->cmos_index[bank] = (u32 & 0x7f) + (bank * 128); 375 } 376 else 377 { 378 Log(("CMOS: Write bank %d idx %#04x: %#04x (old %#04x)\n", bank, 379 pThis->cmos_index[bank], u32, pThis->cmos_data[pThis->cmos_index[bank]])); 380 381 switch (pThis->cmos_index[bank]) 382 { 383 case RTC_SECONDS_ALARM: 384 case RTC_MINUTES_ALARM: 385 case RTC_HOURS_ALARM: 386 pThis->cmos_data[pThis->cmos_index[0]] = u32; 387 break; 388 389 case RTC_SECONDS: 390 case RTC_MINUTES: 391 case RTC_HOURS: 392 case RTC_DAY_OF_WEEK: 393 case RTC_DAY_OF_MONTH: 394 case RTC_MONTH: 395 case RTC_YEAR: 396 pThis->cmos_data[pThis->cmos_index[0]] = u32; 397 /* if in set mode, do not update the time */ 398 if (!(pThis->cmos_data[RTC_REG_B] & REG_B_SET)) 399 rtc_set_time(pThis); 400 break; 401 402 case RTC_REG_A: 403 /* UIP bit is read only */ 404 pThis->cmos_data[RTC_REG_A] = (u32 & ~REG_A_UIP) 405 | (pThis->cmos_data[RTC_REG_A] & REG_A_UIP); 406 rtc_timer_update(pThis, TMTimerGet(pThis->CTX_SUFF(pPeriodicTimer))); 407 break; 408 409 case RTC_REG_B: 410 if (u32 & REG_B_SET) 411 { 412 /* set mode: reset UIP mode */ 413 pThis->cmos_data[RTC_REG_A] &= ~REG_A_UIP; 414 #if 0 /* This is probably wrong as it breaks changing the time/date in OS/2. */ 415 u32 &= ~REG_B_UIE; 416 #endif 417 } 418 else 419 { 420 /* if disabling set mode, update the time */ 421 if (pThis->cmos_data[RTC_REG_B] & REG_B_SET) 422 rtc_set_time(pThis); 423 } 424 pThis->cmos_data[RTC_REG_B] = u32; 425 rtc_timer_update(pThis, TMTimerGet(pThis->CTX_SUFF(pPeriodicTimer))); 426 break; 427 428 case RTC_REG_C: 429 case RTC_REG_D: 430 /* cannot write to them */ 431 break; 432 433 default: 434 pThis->cmos_data[pThis->cmos_index[bank]] = u32; 435 break; 436 } 437 } 438 439 return VINF_SUCCESS; 440 } 441 442 #ifdef IN_RING3 443 444 /* -=-=-=-=-=- Timers and their support code -=-=-=-=-=- */ 445 446 447 /** 448 * Device timer callback function, periodic. 449 * 450 * @param pDevIns Device instance of the device which registered the timer. 451 * @param pTimer The timer handle. 452 * @param pvUser Pointer to the RTC state. 453 */ 454 static DECLCALLBACK(void) rtcTimerPeriodic(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser) 455 { 456 RTCState *pThis = PDMINS_2_DATA(pDevIns, RTCState *); 457 458 rtc_timer_update(pThis, pThis->next_periodic_time); 459 pThis->cmos_data[RTC_REG_C] |= 0xc0; 460 461 rtc_raise_irq(pThis, 1); 462 } 463 385 464 386 465 /* month is between 0 and 11. */ 387 466 static int get_days_in_month(int month, int year) 388 467 { 389 static const int days_tab[12] = { 468 static const int days_tab[12] = 469 { 390 470 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 391 471 }; 392 472 int d; 473 393 474 if ((unsigned )month >= 12) 394 475 return 31; 476 395 477 d = days_tab[month]; 396 if (month == 1) { 478 if (month == 1) 479 { 397 480 if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0)) 398 481 d++; … … 401 484 } 402 485 486 403 487 /* update 'tm' to the next second */ 404 488 static void rtc_next_second(struct my_tm *tm) … … 407 491 408 492 tm->tm_sec++; 409 if ((unsigned)tm->tm_sec >= 60) { 493 if ((unsigned)tm->tm_sec >= 60) 494 { 410 495 tm->tm_sec = 0; 411 496 tm->tm_min++; 412 if ((unsigned)tm->tm_min >= 60) { 497 if ((unsigned)tm->tm_min >= 60) 498 { 413 499 tm->tm_min = 0; 414 500 tm->tm_hour++; 415 if ((unsigned)tm->tm_hour >= 24) { 501 if ((unsigned)tm->tm_hour >= 24) 502 { 416 503 tm->tm_hour = 0; 417 504 /* next day */ … … 422 509 tm->tm_year + 1900); 423 510 tm->tm_mday++; 424 if (tm->tm_mday < 1) {511 if (tm->tm_mday < 1) 425 512 tm->tm_mday = 1; 426 } else if (tm->tm_mday > days_in_month) { 513 else if (tm->tm_mday > days_in_month) 514 { 427 515 tm->tm_mday = 1; 428 516 tm->tm_mon++; 429 if (tm->tm_mon >= 12) { 517 if (tm->tm_mon >= 12) 518 { 430 519 tm->tm_mon = 0; 431 520 tm->tm_year++; … … 438 527 439 528 440 static void rtc_update_second(void *opaque) 441 { 442 RTCState *s = (RTCState*)opaque; 443 444 /* if the oscillator is not in normal operation, we do not update */ 445 if ((s->cmos_data[RTC_REG_A] & 0x70) != 0x20) { 446 s->next_second_time += TMTimerGetFreq(s->CTX_SUFF(pSecondTimer)); 447 TMTimerSet(s->CTX_SUFF(pSecondTimer), s->next_second_time); 448 } else { 449 rtc_next_second(&s->current_tm); 450 451 if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { 452 /* update in progress bit */ 453 Log2(("RTC: UIP %x -> 1\n", !!(s->cmos_data[RTC_REG_A] & REG_A_UIP))); 454 s->cmos_data[RTC_REG_A] |= REG_A_UIP; 455 } 456 457 /* 244140 ns = 8 / 32768 seconds */ 458 uint64_t delay = TMTimerFromNano(s->CTX_SUFF(pSecondTimer2), 244140); 459 TMTimerSet(s->CTX_SUFF(pSecondTimer2), s->next_second_time + delay); 460 } 461 } 462 463 static void rtc_update_second2(void *opaque) 464 { 465 RTCState *s = (RTCState*)opaque; 466 467 if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { 468 rtc_copy_date(s); 469 } 470 471 /* check alarm */ 472 if (s->cmos_data[RTC_REG_B] & REG_B_AIE) { 473 if (((s->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0 || 474 from_bcd(s, s->cmos_data[RTC_SECONDS_ALARM]) == s->current_tm.tm_sec) && 475 ((s->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 || 476 from_bcd(s, s->cmos_data[RTC_MINUTES_ALARM]) == s->current_tm.tm_min) && 477 ((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 || 478 from_bcd(s, s->cmos_data[RTC_HOURS_ALARM]) == s->current_tm.tm_hour)) { 479 480 s->cmos_data[RTC_REG_C] |= 0xa0; 481 rtc_raise_irq(s, 1); 482 } 483 } 484 485 /* update ended interrupt */ 486 if (s->cmos_data[RTC_REG_B] & REG_B_UIE) { 487 s->cmos_data[RTC_REG_C] |= 0x90; 488 rtc_raise_irq(s, 1); 489 } 490 491 /* clear update in progress bit */ 492 Log2(("RTC: UIP %x -> 0\n", !!(s->cmos_data[RTC_REG_A] & REG_A_UIP))); 493 s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; 494 495 s->next_second_time += TMTimerGetFreq(s->CTX_SUFF(pSecondTimer)); 496 TMTimerSet(s->CTX_SUFF(pSecondTimer), s->next_second_time); 497 } 498 499 static uint32_t cmos_ioport_read(void *opaque, uint32_t addr) 500 { 501 RTCState *s = (RTCState*)opaque; 502 int ret; 503 unsigned bank; 504 505 bank = (addr >> 1) & 1; 506 if ((addr & 1) == 0) { 507 return 0xff; 508 } else { 509 switch(s->cmos_index[bank]) { 510 case RTC_SECONDS: 511 case RTC_MINUTES: 512 case RTC_HOURS: 513 case RTC_DAY_OF_WEEK: 514 case RTC_DAY_OF_MONTH: 515 case RTC_MONTH: 516 case RTC_YEAR: 517 ret = s->cmos_data[s->cmos_index[0]]; 518 break; 519 case RTC_REG_A: 520 ret = s->cmos_data[s->cmos_index[0]]; 521 break; 522 case RTC_REG_C: 523 ret = s->cmos_data[s->cmos_index[0]]; 524 rtc_raise_irq(s, 0); 525 s->cmos_data[RTC_REG_C] = 0x00; 526 break; 527 default: 528 ret = s->cmos_data[s->cmos_index[bank]]; 529 break; 530 } 531 Log(("CMOS: Read bank %d idx %#04x: %#04x\n", bank, s->cmos_index[bank], ret)); 532 return ret; 533 } 534 } 535 536 #ifdef IN_RING3 537 static void rtc_set_memory(RTCState *s, int addr, int val) 538 { 539 if (addr >= 0 && addr <= 127) 540 s->cmos_data[addr] = val; 541 } 542 543 static void rtc_set_date(RTCState *s, const struct my_tm *tm) 544 { 545 s->current_tm = *tm; 546 rtc_copy_date(s); 547 } 548 549 #endif /* IN_RING3 */ 550 551 /* -=-=-=-=-=- wrappers / stuff -=-=-=-=-=- */ 552 553 /** 554 * Port I/O Handler for IN operations. 555 * 556 * @returns VBox status code. 557 * 558 * @param pDevIns The device instance. 559 * @param pvUser User argument - ignored. 560 * @param uPort Port number used for the IN operation. 561 * @param pu32 Where to store the result. 562 * @param cb Number of bytes read. 563 */ 564 PDMBOTHCBDECL(int) rtcIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb) 565 { 566 NOREF(pvUser); 567 if (cb == 1) 568 { 569 *pu32 = cmos_ioport_read(PDMINS_2_DATA(pDevIns, RTCState *), Port); 570 return VINF_SUCCESS; 571 } 572 return VERR_IOM_IOPORT_UNUSED; 573 } 574 575 576 /** 577 * Port I/O Handler for OUT operations. 578 * 579 * @returns VBox status code. 580 * 581 * @param pDevIns The device instance. 582 * @param pvUser User argument - ignored. 583 * @param uPort Port number used for the IN operation. 584 * @param u32 The value to output. 585 * @param cb The value size in bytes. 586 */ 587 PDMBOTHCBDECL(int) rtcIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb) 588 { 589 NOREF(pvUser); 590 if (cb == 1) 591 cmos_ioport_write(PDMINS_2_DATA(pDevIns, RTCState *), Port, u32); 592 return VINF_SUCCESS; 593 } 594 595 596 /** 597 * Device timer callback function, periodic. 529 /** 530 * Device timer callback function, second. 598 531 * 599 532 * @param pDevIns Device instance of the device which registered the timer. … … 601 534 * @param pvUser Pointer to the RTC state. 602 535 */ 603 PDMBOTHCBDECL(void) rtcTimerPeriodic(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser) 604 { 605 rtc_periodic_timer((RTCState *)pvUser); 606 } 607 608 609 /** 610 * Device timer callback function, second. 536 static DECLCALLBACK(void) rtcTimerSecond(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser) 537 { 538 RTCState *pThis = PDMINS_2_DATA(pDevIns, RTCState *); 539 540 /* if the oscillator is not in normal operation, we do not update */ 541 if ((pThis->cmos_data[RTC_REG_A] & 0x70) != 0x20) 542 { 543 pThis->next_second_time += TMTimerGetFreq(pThis->CTX_SUFF(pSecondTimer)); 544 TMTimerSet(pThis->CTX_SUFF(pSecondTimer), pThis->next_second_time); 545 } 546 else 547 { 548 rtc_next_second(&pThis->current_tm); 549 550 if (!(pThis->cmos_data[RTC_REG_B] & REG_B_SET)) 551 { 552 /* update in progress bit */ 553 Log2(("RTC: UIP %x -> 1\n", !!(pThis->cmos_data[RTC_REG_A] & REG_A_UIP))); 554 pThis->cmos_data[RTC_REG_A] |= REG_A_UIP; 555 } 556 557 /* 244140 ns = 8 / 32768 seconds */ 558 uint64_t delay = TMTimerFromNano(pThis->CTX_SUFF(pSecondTimer2), 244140); 559 TMTimerSet(pThis->CTX_SUFF(pSecondTimer2), pThis->next_second_time + delay); 560 } 561 } 562 563 564 /* Used by rtc_set_date and rtcTimerSecond2. */ 565 static void rtc_copy_date(RTCState *pThis) 566 { 567 const struct my_tm *tm = &pThis->current_tm; 568 569 pThis->cmos_data[RTC_SECONDS] = to_bcd(pThis, tm->tm_sec); 570 pThis->cmos_data[RTC_MINUTES] = to_bcd(pThis, tm->tm_min); 571 if (pThis->cmos_data[RTC_REG_B] & 0x02) 572 { 573 /* 24 hour format */ 574 pThis->cmos_data[RTC_HOURS] = to_bcd(pThis, tm->tm_hour); 575 } 576 else 577 { 578 /* 12 hour format */ 579 pThis->cmos_data[RTC_HOURS] = to_bcd(pThis, tm->tm_hour % 12); 580 if (tm->tm_hour >= 12) 581 pThis->cmos_data[RTC_HOURS] |= 0x80; 582 } 583 pThis->cmos_data[RTC_DAY_OF_WEEK] = to_bcd(pThis, tm->tm_wday); 584 pThis->cmos_data[RTC_DAY_OF_MONTH] = to_bcd(pThis, tm->tm_mday); 585 pThis->cmos_data[RTC_MONTH] = to_bcd(pThis, tm->tm_mon + 1); 586 pThis->cmos_data[RTC_YEAR] = to_bcd(pThis, tm->tm_year % 100); 587 } 588 589 590 /** 591 * Device timer callback function, second2. 611 592 * 612 593 * @param pDevIns Device instance of the device which registered the timer. … … 614 595 * @param pvUser Pointer to the RTC state. 615 596 */ 616 PDMBOTHCBDECL(void) rtcTimerSecond(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser) 617 { 618 rtc_update_second((RTCState *)pvUser); 619 } 620 621 622 /** 623 * Device timer callback function, second2. 624 * 625 * @param pDevIns Device instance of the device which registered the timer. 626 * @param pTimer The timer handle. 627 * @param pvUser Pointer to the RTC state. 628 */ 629 PDMBOTHCBDECL(void) rtcTimerSecond2(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser) 630 { 631 rtc_update_second2((RTCState *)pvUser); 632 } 633 634 #ifdef IN_RING3 597 static DECLCALLBACK(void) rtcTimerSecond2(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser) 598 { 599 RTCState *pThis = PDMINS_2_DATA(pDevIns, RTCState *); 600 601 if (!(pThis->cmos_data[RTC_REG_B] & REG_B_SET)) 602 rtc_copy_date(pThis); 603 604 /* check alarm */ 605 if (pThis->cmos_data[RTC_REG_B] & REG_B_AIE) 606 { 607 if ( ( (pThis->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0 608 || from_bcd(pThis, pThis->cmos_data[RTC_SECONDS_ALARM]) == pThis->current_tm.tm_sec) 609 && ( (pThis->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 610 || from_bcd(pThis, pThis->cmos_data[RTC_MINUTES_ALARM]) == pThis->current_tm.tm_min) 611 && ( (pThis->cmos_data[RTC_HOURS_ALARM ] & 0xc0) == 0xc0 612 || from_bcd(pThis, pThis->cmos_data[RTC_HOURS_ALARM ]) == pThis->current_tm.tm_hour) 613 ) 614 { 615 pThis->cmos_data[RTC_REG_C] |= 0xa0; 616 rtc_raise_irq(pThis, 1); 617 } 618 } 619 620 /* update ended interrupt */ 621 if (pThis->cmos_data[RTC_REG_B] & REG_B_UIE) 622 { 623 pThis->cmos_data[RTC_REG_C] |= 0x90; 624 rtc_raise_irq(pThis, 1); 625 } 626 627 /* clear update in progress bit */ 628 Log2(("RTC: UIP %x -> 0\n", !!(pThis->cmos_data[RTC_REG_A] & REG_A_UIP))); 629 pThis->cmos_data[RTC_REG_A] &= ~REG_A_UIP; 630 631 pThis->next_second_time += TMTimerGetFreq(pThis->CTX_SUFF(pSecondTimer)); 632 TMTimerSet(pThis->CTX_SUFF(pSecondTimer), pThis->next_second_time); 633 } 634 635 636 /* -=-=-=-=-=- Saved State -=-=-=-=-=- */ 637 635 638 636 639 /** … … 787 790 for (i = RTC_CRC_START, u16 = 0; i <= RTC_CRC_LAST; i++) 788 791 u16 += pThis->cmos_data[i]; 789 pThis->cmos_data[RTC_CRC_LOW] = u16 & 0xff;792 pThis->cmos_data[RTC_CRC_LOW] = u16 & 0xff; 790 793 pThis->cmos_data[RTC_CRC_HIGH] = (u16 >> 8) & 0xff; 791 794 } … … 805 808 if (iReg < RT_ELEMENTS(pThis->cmos_data)) 806 809 { 810 PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED); 811 807 812 pThis->cmos_data[iReg] = u8Value; 808 813 … … 812 817 rtcCalcCRC(pThis); 813 818 819 PDMCritSectLeave(pDevIns->pCritSectRoR3); 814 820 return VINF_SUCCESS; 815 821 } 822 816 823 AssertMsgFailed(("iReg=%d\n", iReg)); 817 824 return VERR_INVALID_PARAMETER; … … 832 839 if (iReg < RT_ELEMENTS(pThis->cmos_data)) 833 840 { 841 PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED); 842 834 843 *pu8Value = pThis->cmos_data[iReg]; 844 845 PDMCritSectLeave(pDevIns->pCritSectRoR3); 835 846 return VINF_SUCCESS; 836 847 } … … 840 851 841 852 853 /** 854 * @interface_method_impl{PDMIHPETLEGACYNOTIFY,pfnModeChanged} 855 */ 856 static DECLCALLBACK(void) rtcHpetLegacyNotify_ModeChanged(PPDMIHPETLEGACYNOTIFY pInterface, bool fActivated) 857 { 858 RTCState *pThis = RT_FROM_MEMBER(pInterface, RTCState, IHpetLegacyNotify); 859 PDMCritSectEnter(pThis->pDevInsR3->pCritSectRoR3, VERR_IGNORED); 860 861 pThis->fDisabledByHpet = fActivated; 862 863 PDMCritSectLeave(pThis->pDevInsR3->pCritSectRoR3); 864 } 865 866 842 867 /* -=-=-=-=-=- based on bits from pc.c -=-=-=-=-=- */ 868 869 870 static void rtc_set_memory(RTCState *pThis, int addr, int val) 871 { 872 if (addr >= 0 && addr <= 127) 873 pThis->cmos_data[addr] = val; 874 } 875 876 877 static void rtc_set_date(RTCState *pThis, const struct my_tm *tm) 878 { 879 pThis->current_tm = *tm; 880 rtc_copy_date(pThis); 881 } 882 843 883 844 884 /** @copydoc FNPDMDEVINITCOMPLETE */ … … 900 940 return NULL; 901 941 } 902 903 904 /**905 * @interface_method_impl{PDMIHPETLEGACYNOTIFY,pfnModeChanged}906 */907 static DECLCALLBACK(void) rtcHpetLegacyNotify_ModeChanged(PPDMIHPETLEGACYNOTIFY pInterface, bool fActivated)908 {909 RTCState *pThis = RT_FROM_MEMBER(pInterface, RTCState, IHpetLegacyNotify);910 pThis->fDisabledByHpet = fActivated;911 }912 913 942 914 943 /** … … 1031 1060 return rc; 1032 1061 1062 1033 1063 rc = PDMDevHlpIOPortRegister(pDevIns, pThis->IOPortBase, 4, NULL, 1034 1064 rtcIOPortWrite, rtcIOPortRead, NULL, NULL, "MC146818 RTC/CMOS"); … … 1037 1067 if (fGCEnabled) 1038 1068 { 1039 rc = PDMDevHlpIOPortRegisterRC(pDevIns, pThis->IOPortBase, 4, 0,1069 rc = PDMDevHlpIOPortRegisterRC(pDevIns, pThis->IOPortBase, 4, NIL_RTRCPTR, 1040 1070 "rtcIOPortWrite", "rtcIOPortRead", NULL, NULL, "MC146818 RTC/CMOS"); 1041 1071 if (RT_FAILURE(rc)) … … 1044 1074 if (fR0Enabled) 1045 1075 { 1046 rc = PDMDevHlpIOPortRegisterR0(pDevIns, pThis->IOPortBase, 4, 0,1076 rc = PDMDevHlpIOPortRegisterR0(pDevIns, pThis->IOPortBase, 4, NIL_RTR0PTR, 1047 1077 "rtcIOPortWrite", "rtcIOPortRead", NULL, NULL, "MC146818 RTC/CMOS"); 1048 1078 if (RT_FAILURE(rc))
Note:
See TracChangeset
for help on using the changeset viewer.