| init.config |
| 1 | 1 | # driver <name> = '<filename>' load a file into memory to be run priviledged. |
| 2 | 2 | # program <name> = '<filename>' load a file into memory to be run normally. |
| 3 | | #driver driver_lcd = "lcd.elf" |
| 4 | | #driver driver_buzzer = "buzzer.elf" |
| 3 | driver driver_lcd = "lcd.elf" |
| 4 | driver driver_buzzer = "buzzer.elf" |
| 5 | 5 | driver driver_gpio = "gpio.elf" |
| 6 | | #program alarm = "alarm.elf" |
| 7 | | #program gui = "gui.elf" |
| 8 | | #driver nand = "nand.elf" |
| 6 | program alarm = "alarm.elf" |
| 7 | program gui = "gui.elf" |
| 8 | driver nand = "nand.elf" |
| 9 | 9 | driver sdmmc = "sd+mmc.elf" |
| 10 | 10 | program partition = "partition.elf" |
| 11 | 11 | program fat = "fat.elf" |
| 12 | 12 | program test = "test.elf" |
| 13 | 13 | |
| 14 | 14 | # receive <name> / <type> [, <index>] = <cap> prepare to accept a capability from a named program. |
| 15 | | #receive driver_lcd / Display = display |
| 16 | | #receive driver_lcd / Setting = display_bright |
| 17 | | #receive driver_buzzer / Buzzer = buzzer |
| 15 | receive driver_lcd / Display = display |
| 16 | receive driver_lcd / Setting = display_bright |
| 17 | receive driver_buzzer / Buzzer = buzzer |
| 18 | 18 | receive driver_gpio / Keyboard , 0 = keyboard |
| 19 | 19 | receive driver_gpio / Keyboard , 1 = sysreq |
| 20 | 20 | receive driver_gpio / Event = sdmmc_gpio |
| 21 | | #receive alarm / UI = ui |
| 21 | receive alarm / UI = ui |
| 22 | 22 | receive sdmmc / WString = sdmmc |
| 23 | 23 | receive partition / WString, 0 = p0 |
| 24 | 24 | receive partition / WString, 1 = p1 |
| ... | ... | |
| 30 | 30 | sysreq sysreq |
| 31 | 31 | |
| 32 | 32 | # give <name> / <type> [, <index>] = <cap> give this capability to this program when it requests it. |
| 33 | | #give gui / UI = ui |
| 34 | | #give gui / Display = display |
| 35 | | #give gui / Setting = display_bright |
| 36 | | #give gui / Buzzer = buzzer |
| 37 | | #give gui / Keyboard = keyboard |
| 33 | give gui / UI = ui |
| 34 | give gui / Display = display |
| 35 | give gui / Setting = display_bright |
| 36 | give gui / Buzzer = buzzer |
| 37 | give gui / Keyboard = keyboard |
| 38 | 38 | give sdmmc / Event = sdmmc_gpio |
| 39 | 39 | give partition / WString = sdmmc |
| 40 | 40 | give fat / WString = p0 |
| source/fat.ccp |
| 296 | 296 | else if bits == 12 && fat[c] == 0xfff || bits == 16 && fat[c] == 0xffff || bits == 32 && fat[c] == 0xfffffff: |
| 297 | 297 | // Last cluster in chain. |
| 298 | 298 | fat[c] = ~0 |
| 299 | | kdebug ("last cluster: ") |
| 300 | | kdebug_num (c) |
| 301 | | kdebug ("\n") |
| 299 | //kdebug ("last cluster: ") |
| 300 | //kdebug_num (c) |
| 301 | //kdebug ("\n") |
| 302 | 302 | else if bits == 12 && fat[c] == 0xff7 || bits == 16 && fat[c] == 0xfff7 || bits == 32 && fat[c] == 0xffffff7: |
| 303 | 303 | // Bad cluster. |
| 304 | 304 | fat[c] = first_bad_cluster |
| ... | ... | |
| 307 | 307 | else: |
| 308 | 308 | // Non-last cluster in chain. |
| 309 | 309 | fat[c] -= 2 |
| 310 | | kdebug_num (c) |
| 311 | | kdebug (" -> ") |
| 312 | | kdebug_num (fat[c]) |
| 313 | | kdebug ("\n") |
| 310 | //kdebug_num (c) |
| 311 | //kdebug (" -> ") |
| 312 | //kdebug_num (fat[c]) |
| 313 | //kdebug ("\n") |
| 314 | 314 | unsigned fat_lookup (unsigned first_cluster, unsigned cluster): |
| 315 | 315 | //kdebug ("looking up ") |
| 316 | 316 | //kdebug_num (first_cluster) |
| ... | ... | |
| 334 | 334 | bool archive, readonly, system, hidden, directory, volume |
| 335 | 335 | unsigned create_second, create_minute_hour, create_date, access_date, time, date |
| 336 | 336 | unsigned checksum |
| 337 | | void load_cluster (unsigned idx, Iris::Page p = page, unsigned offset = 0): |
| 337 | void load_cluster (unsigned idx, unsigned offset_in_cluster, Iris::Page p = page, unsigned offset = 0): |
| 338 | 338 | unsigned cluster = fat->fat_lookup (first_cluster, idx >> fat->cluster_size_bits) |
| 339 | 339 | //kdebug ("loading cluster ") |
| 340 | 340 | //kdebug_num (idx) |
| 341 | //kdebug ("+") |
| 342 | //kdebug_num (offset_in_cluster) |
| 341 | 343 | //kdebug ("@") |
| 342 | 344 | //kdebug_num (cluster) |
| 343 | 345 | //kdebug (" from file\n") |
| 344 | 346 | if cluster == ~0: |
| 345 | 347 | kdebug ("invalid cluster requested from file\n") |
| 346 | 348 | return |
| 347 | | read_block ((fat->header_sectors + (Iris::Num (cluster).value () << fat->sectors_per_cluster_bits)) << fat->sector_size_bits, p, 1 << fat->cluster_size_bits, offset) |
| 348 | | //kdebug ("sector ") |
| 349 | | //kdebug_num (fat->header_sectors + (Iris::Num (cluster).value () << fat->sectors_per_cluster_bits)) |
| 350 | | //kdebug ("\n") |
| 349 | read_block (((fat->header_sectors + (Iris::Num (cluster).value () << fat->sectors_per_cluster_bits)) << fat->sector_size_bits) + offset_in_cluster, p, fat->cluster_size_bits < PAGE_BITS ? 1 << fat->cluster_size_bits : PAGE_SIZE, offset) |
| 351 | 350 | char *load_dir_entry (unsigned dir, unsigned idx): |
| 352 | 351 | unsigned sector = idx >> (sector_size_bits - 5) |
| 353 | 352 | unsigned num = (idx << 5) & ~BLOCK_MASK |
| ... | ... | |
| 398 | 397 | kdebug ("unable to load dir entry\n") |
| 399 | 398 | return false |
| 400 | 399 | f->fat = this |
| 400 | //kdebug ("loading dir entry for ") |
| 401 | 401 | for unsigned i = 0; i < 11; ++i: |
| 402 | 402 | f->name[i] = e[i] |
| 403 | //kdebug_char (f->name[i]) |
| 404 | //kdebug ("\n") |
| 403 | 405 | f->readonly = e[0xb] & 0x1 |
| 404 | 406 | f->system = e[0xb] & 0x2 |
| 405 | 407 | f->hidden = e[0xb] & 0x4 |
| ... | ... | |
| 589 | 591 | unsigned size = Iris::recv.data[0].h >> 16 |
| 590 | 592 | unsigned offset = Iris::recv.data[0].h & 0xffff |
| 591 | 593 | unsigned cmd = Iris::recv.data[0].l |
| 592 | | if !fat.find_idx (dir, &idx): |
| 593 | | Iris::panic (0, "file not found") |
| 594 | 594 | Fat::File f |
| 595 | 595 | fat.get_dir_entry (dir, idx, &f) |
| 596 | 596 | switch cmd: |
| ... | ... | |
| 600 | 600 | break |
| 601 | 601 | case Iris::String::GET_CHARS: |
| 602 | 602 | //kdebug ("file chars requested\n") |
| 603 | | unsigned mask = 1 << (fat.cluster_size_bits) - 1 |
| 604 | | f.load_cluster (num.l & ~mask) |
| 603 | unsigned mask = (1 << fat.cluster_size_bits) - 1 |
| 604 | f.load_cluster (num.l & ~mask, num.l & mask) |
| 605 | 605 | unsigned n = num.l & mask & ~0xf |
| 606 | 606 | unsigned *dat = (unsigned *)(data + n) |
| 607 | 607 | reply.invoke (Iris::Num (dat[0], dat[1]), Iris::Num (dat[2], dat[3])) |
| 608 | 608 | break |
| 609 | 609 | case Iris::String::GET_ALIGN_BITS: |
| 610 | 610 | //kdebug ("file align requested\n") |
| 611 | | reply.invoke (fat.cluster_size_bits) |
| 611 | reply.invoke (fat.cluster_size_bits <= PAGE_BITS ? fat.cluster_size_bits : PAGE_BITS) |
| 612 | 612 | break |
| 613 | 613 | case Iris::String::GET_BLOCK: |
| 614 | 614 | //kdebug ("file block requested\n") |
| 615 | | unsigned mask = 1 << (fat.cluster_size_bits) - 1 |
| 615 | unsigned mask = (1 << fat.cluster_size_bits) - 1 |
| 616 | //kdebug ("mask = ") |
| 617 | //kdebug_num (mask) |
| 618 | //kdebug ("\n") |
| 616 | 619 | if offset > PAGE_SIZE: |
| 617 | 620 | //kdebug ("invalid offset requested\n") |
| 618 | 621 | break |
| 619 | 622 | if size + offset > PAGE_SIZE: |
| 623 | Iris::panic (size, "invalid size requested") |
| 620 | 624 | size = PAGE_SIZE - offset |
| 621 | 625 | for unsigned i = 0; i < size; i += 1 << fat.cluster_size_bits: |
| 622 | | f.load_cluster ((num.l & ~mask) + i, arg, i + offset) |
| 626 | f.load_cluster ((num.l & ~mask) + i, num.l & mask, arg, i + offset) |
| 623 | 627 | reply.invoke () |
| 624 | 628 | break |
| 625 | 629 | case Iris::WString::TRUNCATE: |
| ... | ... | |
| 652 | 656 | Iris::Cap reply = Iris::get_reply () |
| 653 | 657 | dir = Iris::recv.protected_data.l |
| 654 | 658 | unsigned idx = Iris::recv.data[1].l |
| 659 | unsigned oldidx = idx |
| 655 | 660 | if !fat.find_idx (dir, &idx): |
| 656 | | Iris::panic (0, "file not found") |
| 661 | kdebug_num (oldidx) |
| 662 | kdebug ("\n") |
| 663 | Iris::panic (1, "file not found") |
| 657 | 664 | Fat::File f |
| 658 | 665 | fat.get_dir_entry (dir, idx, &f) |
| 659 | 666 | Iris::Cap ret |
| 660 | 667 | if f.directory: |
| 668 | //kdebug ("dir provided: ") |
| 669 | //kdebug_num (f.first_cluster) |
| 670 | //kdebug ("\n") |
| 661 | 671 | ret = Iris::my_receiver.create_capability (Iris::Num (f.first_cluster, 0)) |
| 662 | 672 | else: |
| 663 | 673 | ret = Iris::my_receiver.create_capability (Iris::Num (idx, dir)) |
| ... | ... | |
| 670 | 680 | Iris::Cap reply = Iris::get_reply () |
| 671 | 681 | dir = Iris::recv.protected_data.l |
| 672 | 682 | unsigned idx = Iris::recv.data[1].l |
| 683 | unsigned oldidx = idx |
| 673 | 684 | if !fat.find_idx (dir, &idx): |
| 674 | | Iris::panic (0, "file not found") |
| 685 | kdebug_num (oldidx) |
| 686 | kdebug ("\n") |
| 687 | Iris::panic (2, "file not found") |
| 675 | 688 | unsigned type = Iris::recv.data[0].h |
| 676 | 689 | Fat::File f |
| 677 | 690 | fat.get_dir_entry (dir, idx, &f) |
| source/sd+mmc.ccp |
| 24 | 24 | public: |
| 25 | 25 | enum Response_type: |
| 26 | 26 | NONE = MSC_CMDAT_RESPONSE_NONE |
| 27 | | DATA = MSC_CMDAT_RESPONSE_R1 | MSC_CMDAT_DATA_EN |
| 27 | RD_DATA = MSC_CMDAT_RESPONSE_R1 | MSC_CMDAT_DATA_EN | MSC_CMDAT_READ |
| 28 | WR_DATA = MSC_CMDAT_RESPONSE_R1 | MSC_CMDAT_DATA_EN | MSC_CMDAT_WRITE |
| 28 | 29 | R1 = MSC_CMDAT_RESPONSE_R1 |
| 29 | 30 | R1B = MSC_CMDAT_RESPONSE_R1 | MSC_CMDAT_BUSY |
| 30 | 31 | R2 = MSC_CMDAT_RESPONSE_R2 |
| ... | ... | |
| 68 | 69 | unsigned get_block_bits (): |
| 69 | 70 | return hc ? 9 : csd.read_bl_len > csd.write_bl_len ? csd.read_bl_len : csd.write_bl_len |
| 70 | 71 | void fill_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset) |
| 72 | void write_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset) |
| 73 | void wait_write () |
| 71 | 74 | private: |
| 72 | 75 | unsigned rca |
| 73 | 76 | bool have_sdmem, have_io |
| ... | ... | |
| 82 | 85 | MSC_CMD = cmd |
| 83 | 86 | MSC_ARG = arg |
| 84 | 87 | MSC_CMDAT = response_type |
| 88 | MSC_IMASK = ~MSC_IMASK_END_CMD_RES |
| 85 | 89 | Iris::register_interrupt (IRQ_MSC) |
| 86 | 90 | msc_start_op () |
| 87 | 91 | Iris::wait_for_interrupt (IRQ_MSC) |
| 92 | MSC_IMASK = ~0 |
| 88 | 93 | //kdebug ("cmd: ") |
| 89 | 94 | //kdebug_num (cmd) |
| 90 | 95 | unsigned stat = MSC_STAT |
| ... | ... | |
| 178 | 183 | else if r >> 8 != cmd: |
| 179 | 184 | kdebug ("stat: ") |
| 180 | 185 | kdebug_num (MSC_STAT) |
| 186 | kdebug ("; response: ") |
| 187 | kdebug_num (r) |
| 188 | kdebug ("; cmd: ") |
| 189 | kdebug_num (cmd) |
| 181 | 190 | Iris::panic (r, "response doesn't match command") |
| 182 | 191 | r <<= 24 |
| 183 | 192 | r |= MSC_RES << 8 |
| ... | ... | |
| 199 | 208 | Iris::my_memory.map (buffer_page, buffer) |
| 200 | 209 | // Reset all state, by faking a release event. |
| 201 | 210 | release () |
| 202 | | // Enable slow clock to msc. |
| 203 | | CPM_MSCCDR = ~0 |
| 211 | // Enable 25 MHz clock to msc. |
| 212 | CPM_MSCCDR = 13 |
| 204 | 213 | cpm_start_msc () |
| 205 | 214 | // Enable msc pins. |
| 206 | 215 | gpio_as_msc () |
| ... | ... | |
| 223 | 232 | Iris::sleep (1) |
| 224 | 233 | |
| 225 | 234 | // Initialize registers. |
| 226 | | MSC_CLKRT = MSC_CLKRT_CLK_RATE_DIV_128 |
| 235 | MSC_CLKRT = MSC_CLKRT_CLK_RATE_DIV_1 |
| 227 | 236 | MSC_RESTO = 64 |
| 228 | 237 | MSC_RDTO = ~0 |
| 229 | 238 | MSC_BLKLEN = 0x200 |
| 230 | 239 | MSC_NOB = 0 |
| 231 | 240 | MSC_IREG = ~0 |
| 232 | | MSC_IMASK = ~(MSC_IMASK_END_CMD_RES | MSC_IMASK_RXFIFO_RD_REQ | MSC_IMASK_TXFIFO_WR_REQ) |
| 241 | MSC_IMASK = ~(MSC_IMASK_END_CMD_RES | MSC_IMASK_RXFIFO_RD_REQ) |
| 233 | 242 | MSC_ARG = 0 |
| 234 | 243 | |
| 235 | 244 | // Start the clock. |
| ... | ... | |
| 237 | 246 | // Set cards, if any, to idle. |
| 238 | 247 | send (0, 0, NONE) |
| 239 | 248 | |
| 240 | | // Reset SDIO device, if any. |
| 241 | | send (52, 0x88000c08, R5) |
| 249 | // Reset SDIO device, if any. Don't do this, because it breaks for some reason. |
| 250 | //send (52, 0x88000c08, R5) |
| 242 | 251 | |
| 243 | 252 | void Mmc::check_mmc (): |
| 244 | 253 | //kdebug ("checking mmc\n") |
| ... | ... | |
| 378 | 387 | //kdebug ("/") |
| 379 | 388 | //kdebug_num (size) |
| 380 | 389 | //kdebug (" ==> ") |
| 381 | | if !send (17, p + a, DATA): |
| 390 | if !send (17, p + a, RD_DATA): |
| 382 | 391 | Iris::panic (0, "unable to request data") |
| 392 | MSC_IMASK = ~MSC_IMASK_RXFIFO_RD_REQ |
| 383 | 393 | for unsigned aa = 0; aa < 1 << 9; aa += 4: |
| 384 | 394 | while MSC_STAT & MSC_STAT_DATA_FIFO_EMPTY: |
| 385 | 395 | Iris::register_interrupt (IRQ_MSC) |
| ... | ... | |
| 392 | 402 | //kdebug (" ") |
| 393 | 403 | //kdebug_num (d >> (8 * i), 2) |
| 394 | 404 | //kdebug ("\n") |
| 405 | MSC_IMASK = ~0 |
| 395 | 406 | MSC_IREG = MSC_IREG_DATA_TRAN_DONE |
| 396 | 407 | //kdebug ("done filling page\n") |
| 397 | 408 | |
| 409 | void Mmc::write_page (Iris::Page page, Iris::Num address, unsigned size, unsigned offset): |
| 410 | if address.h: |
| 411 | Iris::panic (1, "page too high: not supported") |
| 412 | return |
| 413 | unsigned blockmask = ~((1 << 9) - 1) |
| 414 | unsigned p = address.l & blockmask |
| 415 | size &= blockmask |
| 416 | offset &= ~PAGE_MASK |
| 417 | if size + offset > PAGE_SIZE: |
| 418 | size = PAGE_SIZE - offset |
| 419 | page.share (buffer_page) |
| 420 | buffer_page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME) |
| 421 | MSC_NOB = 1 |
| 422 | MSC_BLKLEN = 1 << 9 |
| 423 | for unsigned a = 0; a < size; a += 1 << 9: |
| 424 | //kdebug_num (a) |
| 425 | //kdebug ("/") |
| 426 | //kdebug_num (size) |
| 427 | //kdebug ("\n") |
| 428 | if !send (24, p + a, WR_DATA): |
| 429 | Iris::panic (0, "unable to send data") |
| 430 | MSC_IMASK = ~MSC_IMASK_TXFIFO_WR_REQ |
| 431 | for unsigned aa = 0; aa < 1 << 9; aa += 4: |
| 432 | while MSC_STAT & MSC_STAT_DATA_FIFO_FULL: |
| 433 | Iris::register_interrupt (IRQ_MSC) |
| 434 | Iris::wait_for_interrupt (IRQ_MSC) |
| 435 | MSC_TXFIFO = *(unsigned *)(buffer + a + aa + offset) |
| 436 | MSC_IMASK = ~0 |
| 437 | MSC_IREG = MSC_IREG_DATA_TRAN_DONE |
| 438 | //kdebug ("done writing page\n") |
| 439 | |
| 440 | void Mmc::wait_write (): |
| 441 | MSC_IMASK = ~MSC_IMASK_PRG_DONE |
| 442 | while !MSC_STAT & MSC_STAT_PRG_DONE: |
| 443 | Iris::register_interrupt (IRQ_MSC) |
| 444 | Iris::wait_for_interrupt (IRQ_MSC) |
| 445 | MSC_IREG = MSC_IREG_PRG_DONE |
| 446 | |
| 398 | 447 | static Mmc mmc |
| 399 | 448 | |
| 400 | 449 | enum types: |
| ... | ... | |
| 464 | 513 | Iris::free_cap (page) |
| 465 | 514 | Iris::free_cap (reply) |
| 466 | 515 | break |
| 467 | | case Iris::WString::SET_CHARS: |
| 468 | 516 | case Iris::WString::SET_BLOCK: |
| 469 | | // Fall through: don't support writing yet. |
| 517 | Iris::Cap reply = Iris::get_reply () |
| 518 | Iris::Page page = Iris::get_arg () |
| 519 | mmc.write_page (page, Iris::recv.data[1], Iris::recv.data[0].h >> 16, Iris::recv.data[0].h & 0xffff) |
| 520 | reply.invoke () |
| 521 | Iris::free_cap (page) |
| 522 | Iris::free_cap (reply) |
| 523 | mmc.wait_write () |
| 524 | break |
| 525 | case Iris::WString::SET_CHARS: |
| 526 | // Fall through: don't support writing single characters. |
| 470 | 527 | case Iris::WString::TRUNCATE: |
| 528 | // Fall through: don't support resizing. |
| 471 | 529 | default: |
| 472 | 530 | Iris::panic (0, "unexpected event for sd+mmc") |
| 473 | 531 | break |