1/** 2 * \file 3 */ 4 5/* 6 * Copyright (c) 2009, ETH Zurich. 7 * All rights reserved. 8 * 9 * This file is distributed under the terms in the attached LICENSE file. 10 * If you do not find this file, copies can be found by writing to: 11 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 12 */ 13 14/* A lot of the information used to build these models is take from: 15 * http://www.intel.com/Assets/PDF/datasheet/313082.pdf */ 16 17#include "vmkitmon.h" 18#include "lpc.h" 19#include <stdlib.h> 20 21 22#define TCW_RW_LSB 1 23#define TCW_RW_MSB 2 24#define TCW_RW_LSB_MSB 3 25 26#define LPC_PIT_MODE_ONE_SHOT 0 27#define LPC_PIT_MODE_RATEN 2 28#define LPC_PIT_MODE_SWAVE 3 29#define LPC_PIT_TIMER0_PERIOD_NS 838 30 31#define PIC_EOI_NSEOI 1 32#define PIC_EOI_SEOI 3 33 34#define PIT_IRQ 0 35#define RTC_IRQ 8 36 37 38static inline uint8_t 39bcd2bin (uint8_t val) 40{ 41 return (val & 0x0f) + (val >> 4) * 10; 42} 43 44static inline uint8_t 45bin2bcd(unsigned val) 46{ 47 assert(val < 100); 48 return ((val / 10) << 4) + val % 10; 49} 50 51static inline bool 52pic_irq_masked (struct lpc *l, int irq) { 53 assert(irq < 16); 54 55 // if the IRQ is comming from the slave controller check whether it is 56 // masked on the first controller (IRQ2) 57 if (irq > 7 && l->ocw1[0].u.irq_mask & (1 << 2)) { 58 return true; 59 } 60 61 uint8_t rel_irq = irq & 0x7; 62 int ctrlr = irq >> 3; 63 return l->ocw1[ctrlr].u.irq_mask & (1 << rel_irq); 64} 65 66/** 67 * \brief Scan all pending IRQs and send the most important one up to APIC. 68 */ 69void 70lpc_pic_process_irqs (struct lpc *l) 71{ 72 bool pending = false; 73 74 // check whether the CPU has an interrupt pending 75 if (l->virq_pending(l->virq_user_data, NULL, NULL)) { 76 assert(l->current_irq >= 0 && l->current_irq < 16); 77 pending = true; 78 } 79 80 // find the most priorized IRQ 81 for (int irq = 0; irq < 16; irq++) { 82 // check whether this IRQ is pending 83 if (l->irq_state[irq] == LPC_PIC_IRQ_PENDING) { 84 assert(irq != 2); 85 86 // check whether this irq has a higher (0 beeing high) priority as 87 // a possible pending one 88 if (pending && irq >= l->current_irq) { 89 // we may return here since no further IRQ may have a higher prior 90 return; 91 } 92 93 // check whether we have to remove a pending interrupt 94 if (pending) { 95 // there is an irq pending with lower priority than the current 96 // one, we have to put it back into pending, it will be replaced 97 // by this interrupt 98 assert(l->irq_state[l->current_irq] == LPC_PIC_IRQ_ISR); 99 l->irq_state[l->current_irq] = LPC_PIC_IRQ_PENDING; 100 } 101 102 // process the irq 103 l->irq_state[irq] = LPC_PIC_IRQ_ISR; 104 l->current_irq = irq; 105 106 // assert the virtual interrupt to the CPU 107 // find out the real irq as it is mapped through the PIC init 108 int ctrlr = irq >> 3; 109 assert(ctrlr == 0 || ctrlr == 1); 110 assert(irq <= 7 || ctrlr == 1); 111 uint8_t real_irq = (l->icw2[ctrlr].u.intr_vec_base_addr << 3) | 112 (irq & 0x7); 113 /*if (irq != 0) { 114 printf("PIC: assert IRQ%u (real %u), pending %u, current_irq %u\n", irq, real_irq, pending, l->current_irq); 115 }*/ 116 l->virq_handler(l->virq_user_data, real_irq, irq); 117 return; 118 } 119 } 120} 121 122/** 123 * \brief Assert an IRQ through the PIC. 124 * 125 * This method asserts an IRQ to the CPU. It does not actually generate virtual 126 * interrupts and instead pushed the IRQ forward to the APIC. 127 */ 128void 129lpc_pic_assert_irq (struct lpc *l, uint8_t irq) 130{ 131 assert(irq < 16 && irq != 2); 132 133 if (!pic_irq_masked(l, irq) && l->irq_state[irq] == LPC_PIC_IRQ_AVAIL) { 134 // assert the irq 135 l->irq_state[irq] = LPC_PIC_IRQ_PENDING; 136 } 137 138 lpc_pic_process_irqs(l); 139} 140 141static void 142pic_eoi (struct lpc *l, int ctrlr) 143{ 144 assert(ctrlr == 0 || ctrlr == 1); 145 146 switch (l->ocw2[ctrlr].u.rot_eio_codes) { 147 case PIC_EOI_NSEOI: { 148 // start at IRQ0 for the master and IRQ8 for the slave controller 149 int irq = ctrlr << 3; 150 for (int i = 0; i < 8; i++, irq++) { 151 if (l->irq_state[irq] == LPC_PIC_IRQ_ISR) { 152 l->irq_state[irq] = LPC_PIC_IRQ_AVAIL; 153 break; 154 } 155 } 156 break; 157 } 158 case PIC_EOI_SEOI: { 159 // irq_lvl_sel holds an number between 0 and 7 which represent the 160 // corresponding IRQ on the master and slave controller 161 int irq = l->ocw2[ctrlr].u.irq_lvl_sel | (ctrlr << 3); 162 l->irq_state[irq] = LPC_PIC_IRQ_AVAIL; 163 break; 164 } 165 default: 166 // we do no support all EOI methods yet 167 assert(!"not reached"); 168 break; 169 } 170 171 // after an EOI we should process the remaining IRQs 172 lpc_pic_process_irqs(l); 173} 174 175static inline uint64_t 176truncate_to_opsize (enum opsize size, uint64_t val) 177{ 178 switch (size) { 179 case OPSIZE_8: 180 return val & 0xff; 181 case OPSIZE_16: 182 return val & 0xffff; 183 case OPSIZE_32: 184 return val & 0xffffffff; 185 case OPSIZE_64: 186 return val; 187 } 188 189 assert(!"not reached"); 190 return 0; 191} 192 193static inline void 194cycle_counter_access_byte (struct lpc *l, int reg) 195{ 196 // check whether we have to cycle the byte pointer 197 if (l->sbytes[reg].u.rw_mode == TCW_RW_LSB_MSB) { 198 switch (l->counter_current_byte[reg]) { 199 case LPC_PIT_LSB: 200 l->counter_current_byte[reg] = LPC_PIT_MSB; 201 break; 202 case LPC_PIT_MSB: 203 l->counter_current_byte[reg] = LPC_PIT_LSB; 204 break; 205 case LPC_PIT_NONE: 206 assert(!"not reached"); 207 } 208 } 209} 210 211#if 0 212static inline uint32_t 213timer_countdown_reg_read (struct lpc *l, int reg) 214{ 215 uint32_t ret; 216 217 assert(l->counters_next_byte[reg] != LPC_PIT_NONE); 218 219 // write the requested byte 220 if (l->counters_next_byte[reg] != LPC_PIT_LSB) { 221 ret = l->counters[reg] & 0xff; 222 } else if (l->counters_next_byte[reg] != LPC_PIT_MSB) { 223 ret = (l->counters[reg] >> 8) & 0xff; 224 } 225 226 cycle_counter_access_byte(l, reg); 227 228 return ret; 229} 230#endif 231 232static inline void 233pit_write_current_byte (struct lpc *l, int reg, uint16_t src, uint8_t *dest) 234{ 235 // write the requested byte 236 if (l->counter_current_byte[reg] == LPC_PIT_LSB) { 237 *dest = src; 238 } else if (l->counter_current_byte[reg] == LPC_PIT_MSB) { 239 *dest = src >> 8; 240 } else { 241 assert(!"not reached"); 242 } 243} 244 245static inline uint8_t 246pit_counter_read (struct lpc *l, int reg) 247{ 248 assert(reg == 0 || reg == 2); 249 assert(l->counter_current_byte[reg] != LPC_PIT_NONE); 250 251 uint16_t val; 252 253 // read the current value 254 if (reg == 2 && !l->nmi_sc_reg.u.tim_cnt2_en) { 255 // if we are dealing with counter 2 and it is disabled we just return 256 // the initial value 257 val = l->initial_count[2]; 258 } else { 259 // otherwise we read the value from the real counter 260 261 // if the counter is latched then its value has been stored in the buffer 262 // otherwhise we take it directly from the counter 263 if (l->counter_latched[reg]) { 264 // the value was read before 265 val = l->buffer_val[reg]; 266 } else { 267 val = (timer_remaining(l->timer[reg]) * 1000 / 268 LPC_PIT_TIMER0_PERIOD_NS) % l->initial_count[reg]; 269 } 270 } 271 272 uint8_t ret_val; 273 if (l->counter_current_byte[reg] == LPC_PIT_LSB) { 274 ret_val = val; 275 } else { 276 ret_val = val >> 8; 277 // reset a possible latch command 278 l->counter_latched[reg] = false; 279 } 280 cycle_counter_access_byte(l, reg); 281 282 return ret_val; 283} 284 285/** 286 * \brief Handles writes to the ICW or OCW registers of both PICs. 287 * 288 * \param ctrlr 0 inidicates the master and 1 the slave controller 289 * \param port the relative port (0 or 1) based at 0x20 or 0xa0 accessed 290 */ 291static inline uint8_t 292pic_icw_ocw_read (struct lpc *l, int ctrlr, uint16_t port) 293{ 294 assert(ctrlr == 0 || ctrlr == 1); 295 assert(port == 0 || port == 1); 296 297 switch (port) { 298 case 0: 299 // ICW1, OCW2, OCW3 are write only 300 assert(!"not reached"); 301 break; 302 case 1: 303 return l->ocw1[ctrlr].raw; 304 } 305 306 assert(!"not reached"); 307 return 0; 308} 309 310int 311lpc_handle_pio_read (struct lpc *l, uint16_t port, enum opsize size, 312 uint32_t *val) 313{ 314 switch (port) { 315 // PIC 316 case 0x20: 317 case 0x21: 318 *val = pic_icw_ocw_read(l, 0, port - 0x20); 319 return HANDLER_ERR_OK; 320 case 0xa0: 321 case 0xa1: 322 *val = pic_icw_ocw_read(l, 1, port - 0xa0); 323 return HANDLER_ERR_OK; 324 325 // RTC 326 case 0x70: 327 case 0x72: 328 case 0x74: 329 case 0x76: 330 assert(!"these io-ports should not be read"); 331 break; 332 // primary ram bank access 333 case 0x71: 334 case 0x75: 335 if (l->rtc_prim_addr < 128) { 336 *val = l->rtc_prim_ram.raw[l->rtc_prim_addr]; 337 // clear register C on read 338 if (l->rtc_prim_addr == 0xc) { 339 l->rtc_prim_ram.u.C.raw = 0; 340 } 341 } 342 return HANDLER_ERR_OK; 343 // second ram bank access 344 case 0x73: 345 case 0x77: 346 if (l->rtc_sec_addr < 128) { 347 *val = l->rtc_sec_ram[l->rtc_sec_addr]; 348 } 349 return HANDLER_ERR_OK;; 350 351 // NMI 352 case 0x61: 353 // pass the out pin state of PIT counter 2 354 if (l->nmi_sc_reg.u.tim_cnt2_en) { 355 l->nmi_sc_reg.u.tmr2_out_sts = l->sbytes[2].u.out_pin_state; 356 } else { 357 l->nmi_sc_reg.u.tmr2_out_sts = 0; 358 } 359 360 *val = l->nmi_sc_reg.raw; 361 return HANDLER_ERR_OK; 362 363 // Timer 364 case 0x41: 365 assert(!"not reached"); 366 break; 367 case 0x40: 368 case 0x42: 369 *val = pit_counter_read(l, port - 0x40); 370 return HANDLER_ERR_OK; 371 case 0x43: 372 *val = 0; 373 return HANDLER_ERR_OK; 374 375 default: 376 printf("lpc: Unhandled read access to port %x\n", port); 377 return HANDLER_ERR_UNHANDELED; 378 } 379 380 return -1; 381} 382 383#if 0 384static void 385rtc_timer_callback (struct timer *t, void *data) 386{ 387 struct lpc *l = data; 388 389 // some restrictions 390 // all uniplemented features 391 assert(l->rtc_prim_ram.u.B.u.data_mode == 0); 392 assert(l->rtc_prim_ram.u.B.u.hour_format == 1); 393 assert(l->rtc_prim_ram.u.B.u.aie == 0); 394 assert(l->rtc_prim_ram.u.B.u.pie == 0); 395 assert(l->rtc_prim_ram.u.B.u.set == 0); 396 assert(l->rtc_prim_ram.u.B.u.sqwe == 0); 397 398 uint8_t sec = bcd2bin(l->rtc_prim_ram.u.seconds); 399 uint8_t min = bcd2bin(l->rtc_prim_ram.u.minutes); 400 uint8_t hour = bcd2bin(l->rtc_prim_ram.u.hours); 401 uint8_t dow = bcd2bin(l->rtc_prim_ram.u.day_of_week); 402 uint8_t dom = bcd2bin(l->rtc_prim_ram.u.day_of_month); 403 uint8_t mon = bcd2bin(l->rtc_prim_ram.u.month); 404 uint8_t year = bcd2bin(l->rtc_prim_ram.u.year); 405 406 // increment RTC by one second 407 sec++; 408 if (sec >= 60) { 409 sec = 0; 410 min++; 411 } 412 if (min >= 60) { 413 min = 0; 414 hour++; 415 } 416 if (hour >= 24) { 417 hour = 0; 418 dow++; 419 dom++; 420 } 421 if (dow > 7) { 422 dow = 0; 423 } 424 // FIXME: simply wrong! 425 if (dom > 30) { 426 dom = 0; 427 mon++; 428 } 429 if (mon >= 12) { 430 mon = 0; 431 year++; 432 } 433 434 l->rtc_prim_ram.u.seconds = bin2bcd(sec); 435 l->rtc_prim_ram.u.minutes = bin2bcd(min); 436 l->rtc_prim_ram.u.hours = bin2bcd(hour); 437 l->rtc_prim_ram.u.day_of_week = bin2bcd(dow); 438 l->rtc_prim_ram.u.day_of_month = bin2bcd(dom); 439 l->rtc_prim_ram.u.month = bin2bcd(mon); 440 l->rtc_prim_ram.u.year = bin2bcd(year); 441 442 // trigger update interrupt if desired 443 if (l->rtc_prim_ram.u.B.u.uie) { 444 l->rtc_prim_ram.u.C.u.uf = 1; 445 lpc_pic_assert_irq(l, RTC_IRQ); 446 } 447 448} 449#endif 450 451static void 452handle_counter_timer (struct timer *t, void *user_data) 453{ 454 struct lpc *l = user_data; 455 456 int reg; 457 if (t == l->timer[0]) { 458 reg = 0; 459 // assert the IRQ 460 lpc_pic_assert_irq(l, PIT_IRQ); 461 } else if (t == l->timer[2]) { 462 reg = 2; 463 } else { 464 assert(!"timer callback for unknown counter!"); 465 return; 466 } 467 468 switch (l->sbytes[reg].u.mode_type) { 469 case LPC_PIT_MODE_ONE_SHOT: 470 // set the out pin to high 471 l->sbytes[reg].u.out_pin_state = 1; 472 // destroy the timer 473 timer_destroy(t); 474 l->timer[reg] = NULL; 475 break; 476 477 case LPC_PIT_MODE_SWAVE: 478 // cycle between zero and one every time the counter rolls 479 // over its initial value 480 l->sbytes[reg].u.out_pin_state = !l->sbytes[reg].u.out_pin_state; 481 break; 482 483 case LPC_PIT_MODE_RATEN: 484 // we do not set the out pin to one for one cycle as it would be on 485 // real hardware 486 // the running timer is peridic therefore we do not need to do anything 487 // here 488 break; 489 } 490} 491 492static inline void 493timer_countdown_reg_write (struct lpc *l, int reg, uint8_t val) 494{ 495 uint16_t buf = l->initial_count[reg]; 496 497 assert(l->counter_current_byte[reg] != LPC_PIT_NONE); 498 499 // write the requested byte 500 if (l->counter_current_byte[reg] == LPC_PIT_LSB) { 501 l->initial_count[reg] = (buf & 0xff00) | val; 502 } else if (l->counter_current_byte[reg] == LPC_PIT_MSB) { 503 l->initial_count[reg] = (val << 8) | (buf & 0xff); 504 } 505 506 // actions to be done at the end of a counter config cycle 507 // in LSB MSB mode this is the case after MSB has been written in all other 508 // modes this true after all writes 509 // TCW_RW_LSB_MSB ==> LPC_PIT_MSB 510 if (l->sbytes[reg].u.rw_mode != TCW_RW_LSB_MSB || 511 l->counter_current_byte[reg] == LPC_PIT_MSB) { 512 // counter 0 asserts an interrupt so start a timer on this event 513 if (reg == 0 || reg == 2) { 514 // destroy a possible running timer before creating a new one 515 if (l->timer[reg] != NULL) { 516 timer_destroy(l->timer[reg]); 517 } 518 519 // set up the new timer 520 bool periodic = l->sbytes[reg].u.mode_type != LPC_PIT_MODE_ONE_SHOT; 521 522 // start the PIT timer 523 l->timer[reg] = timer_create((uint64_t)l->initial_count[reg] * 524 LPC_PIT_TIMER0_PERIOD_NS / 1000, 525 periodic, handle_counter_timer, l); 526 // only start timer 2 if it is enabled 527 if (!(reg == 2 && !l->nmi_sc_reg.u.tim_cnt2_en)) { 528 timer_start(l->timer[reg]); 529 } 530 } 531 // other counters do not assert an IRQ so just pass on the config 532 else { 533 //lpc_timer_config(reg, l->sbytes[reg].u.mode_type, 534 // l->initial_count[reg]); 535 } 536 } 537 538 cycle_counter_access_byte(l, reg); 539} 540 541/** 542 * \brief Handles writes to the ICW or OCW registers of both PICs. 543 * 544 * \param ctrlr 0 inidicates the master and 1 the slave controller 545 * \param port the relative port (0 or 1) based at 0x20 or 0xa0 accessed 546 */ 547static inline void 548pic_icw_ocw_write (struct lpc *l, int ctrlr, uint16_t port, uint8_t val) 549{ 550 assert(ctrlr == 0 || ctrlr == 1); 551 assert(port == 0 || port == 1); 552 553 switch (port) { 554 case 0: 555 // check whether the IWC cycle should start 556 if (val & 0x10) { 557 // ICW cycle 558 l->icw1[ctrlr].raw = val; 559 assert(l->icw1[ctrlr].u.sigl_or_casc == 0); 560 assert(l->icw1[ctrlr].u.icw_sel != 0); 561 // start the cycle 562 l->current_icw[ctrlr] = LPC_PIC_ICW_2; 563 } else { 564 // OCW write 565 // bit 3 indicates which control word shall be written 566 if (val & 0x8) { 567 // OCW 3 568 l->ocw3[ctrlr].raw = val; 569 assert(l->ocw3[ctrlr].u.ocw_sel == 1); 570 } else { 571 // OCW 2 572 l->ocw2[ctrlr].raw = val; 573 assert(l->ocw2[ctrlr].u.ocw_sel == 0); 574 pic_eoi(l, ctrlr); 575 } 576 } 577 break; 578 case 1: 579 // check whether we are in IWC mode 580 if (l->current_icw[ctrlr] != LPC_PIC_ICW_NONE) { 581 switch (l->current_icw[ctrlr]) { 582 case LPC_PIC_ICW_2: 583 l->icw2[ctrlr].raw = val; 584 assert(l->icw2[ctrlr].u.intr_req_lvl == 0); 585 l->current_icw[ctrlr] = LPC_PIC_ICW_3; 586 break; 587 case LPC_PIC_ICW_3: 588 l->icw3[ctrlr].raw = val; 589 if (ctrlr == 0) { 590 assert(l->icw3[ctrlr].um.casc_slave_ctrlr == 1); 591 } 592 if (l->icw1[ctrlr].u.icw4_req) { 593 l->current_icw[ctrlr] = LPC_PIC_ICW_4; 594 } else { 595 l->current_icw[ctrlr] = LPC_PIC_ICW_NONE; 596 } 597 break; 598 case LPC_PIC_ICW_4: 599 l->icw4[ctrlr].raw = val; 600 assert(l->icw4[ctrlr].u.microproc_mode != 0); 601 assert(!l->icw4[ctrlr].u.buf_mode); 602 assert(!l->icw4[ctrlr].u.sfn_mod); 603 // AEOI not supported yet 604 assert(!l->icw4[ctrlr].u.aeoi); 605 l->current_icw[ctrlr] = LPC_PIC_ICW_NONE; 606 break; 607 default: 608 assert(!"not reached"); 609 break; 610 } 611 } 612 // OCW1 write 613 else { 614 l->ocw1[ctrlr].raw = val; 615 } 616 break; 617 default: 618 assert(!"not reached"); 619 } 620} 621 622int 623lpc_handle_pio_write (struct lpc *l, uint16_t port, enum opsize size, 624 uint32_t val) 625{ 626 switch (port) { 627 // PIC 628 case 0x20: 629 case 0x21: 630 pic_icw_ocw_write(l, 0, port - 0x20, val); 631 return HANDLER_ERR_OK; 632 case 0xa0: 633 case 0xa1: 634 pic_icw_ocw_write(l, 1, port - 0xa0, val); 635 return HANDLER_ERR_OK; 636 637 // RTC 638 case 0x70: 639 case 0x74: 640 if ((val >> 7) & 1) { 641 l->nmi_masked = true; 642 } else { 643 l->nmi_masked = false; 644 } 645 l->rtc_prim_addr = val & 0x7f; 646 return HANDLER_ERR_OK; 647 case 0x71: 648 case 0x75: 649 if (l->rtc_prim_addr < 128) { 650 l->rtc_prim_ram.raw[l->rtc_prim_addr] = val; 651 } 652 return HANDLER_ERR_OK; 653 case 0x72: 654 case 0x76: 655 l->rtc_sec_addr = val; 656 return HANDLER_ERR_OK; 657 case 0x73: 658 case 0x77: 659 if (l->rtc_sec_addr < 128) { 660 l->rtc_sec_ram[l->rtc_sec_addr] = val; 661 } 662 return HANDLER_ERR_OK; 663 664 // NMI Controller 665 case 0x61: 666 // only the first 4 bits are writable 667 l->nmi_sc_reg.raw |= val & 0xf; 668 // start/stop the counter 2 if required 669 if (l->timer[2]) { 670 if (l->nmi_sc_reg.u.tim_cnt2_en && !timer_is_running(l->timer[2])) { 671 timer_start(l->timer[2]); 672 } else if (!l->nmi_sc_reg.u.tim_cnt2_en 673 && timer_is_running(l->timer[2])) { 674 timer_stop(l->timer[2]); 675 } 676 } 677 return HANDLER_ERR_OK; 678 679 // Timer 680 // Write to the countdown registers 681 case 0x40: 682 timer_countdown_reg_write(l, 0, val); 683 return HANDLER_ERR_OK; 684 case 0x41: 685 timer_countdown_reg_write(l, 1, val); 686 return HANDLER_ERR_OK; 687 case 0x42: 688 timer_countdown_reg_write(l, 2, val); 689 return HANDLER_ERR_OK; 690 // Write to the timer control register (TCW) 691 case 0x43: { 692 union lpc_pit_tcw tcw = { .raw = val }; 693 694 // check for some unimplemented stuff 695 if (tcw.u.countdown_select != 0) { 696 printf("lpc timer: only binary countdown is supported\n"); 697 return HANDLER_ERR_FATAL; 698 } 699 // not all modes are implemented 700 assert(tcw.u.mode_select == LPC_PIT_MODE_ONE_SHOT || 701 tcw.u.mode_select == LPC_PIT_MODE_RATEN); 702 if (tcw.u.counter_select == 3) { 703 printf("lpc timer: read back command not implemented\n"); 704 return HANDLER_ERR_FATAL; 705 } 706 707 // we do not support counter 1 708 assert(tcw.u.counter_select != 1); 709 710 // check for latch command 711 if (tcw.u.rw_select == 0) { 712 l->counter_latched[tcw.u.counter_select] = true; 713 l->buffer_val[tcw.u.counter_select] = 714 (timer_remaining(l->timer[tcw.u.counter_select]) * 715 1000 / LPC_PIT_TIMER0_PERIOD_NS) % 716 l->initial_count[tcw.u.counter_select]; 717 return HANDLER_ERR_OK; 718 } 719 720 l->sbytes[tcw.u.counter_select].raw = (uint8_t)val; 721 l->sbytes[tcw.u.counter_select].u.count_avail = 0; 722 l->sbytes[tcw.u.counter_select].u.out_pin_state = 0; 723 724 // set the access mode 725 switch (tcw.u.rw_select) { 726 case TCW_RW_LSB_MSB: 727 l->counter_current_byte[tcw.u.counter_select] = LPC_PIT_LSB; 728 break; 729 // we only support LSB MSB mode atm 730 default: 731 assert(!"not reached"); 732 } 733 734 return HANDLER_ERR_OK; 735 } 736 737 default: 738 printf("lpc: Unhandled write access to port %x\n", port); 739 return HANDLER_ERR_UNHANDELED; 740 } 741 742 return -1; 743} 744 745struct lpc * 746lpc_new (lpc_virtual_irq_handler virq_handler, 747 lpc_virtual_irq_pending virq_pending, 748#ifndef CONFIG_SVM 749 lpc_virtual_irq_accepting virq_accepting, 750#endif 751 void *user_data, struct apic *apic) 752{ 753 struct lpc *ret = calloc(1, sizeof(struct lpc)); 754 755 ret->virq_handler = virq_handler; 756 ret->virq_pending = virq_pending; 757#ifndef CONFIG_SVM 758 ret->virq_accepting = virq_accepting; 759#endif 760 ret->virq_user_data = user_data; 761 ret->apic = apic; 762 763 ret->current_irq = -1; 764 765#if 0 766 // RTC init 767 ret->rtc_prim_ram.u.B.u.hour_format = 1; 768 // init some time 769 ret->rtc_prim_ram.u.day_of_month = bin2bcd(29); 770 ret->rtc_prim_ram.u.month = bin2bcd(8); 771 ret->rtc_prim_ram.u.year = bin2bcd(9); 772 // start the RTC timer to to be called every second 773 ret->rtc_timer = timer_create(1000000, true, rtc_timer_callback, ret); 774 timer_start(ret->rtc_timer); 775#endif 776 777 return ret; 778} 779 780void 781lpc_rtc_get_time_bcd (struct lpc *l, uint8_t *hour, uint8_t *min, uint8_t *sec) 782{ 783 if (hour != NULL) { 784 *hour = l->rtc_prim_ram.u.hours; 785 } 786 if (min != NULL) { 787 *min = l->rtc_prim_ram.u.minutes; 788 } 789 if (sec != NULL) { 790 *sec = l->rtc_prim_ram.u.seconds; 791 } 792} 793