void _machine_restart(void) { struct sb_halt_arg arg; arg.mode = SB_HALT_MODE_PWROFF; sbios(SB_HALT, &arg); }
int checkboard(void) { struct ps2_bootinfo *info = (void *) CKSEG0ADDR(PS2_BOOTINFO_OLDADDR); uint32_t size; volatile uint32_t *sbios_magic; int sbversion = 0; struct ps2_bootinfo bootinfo; puts("Board: Sony Playstation 2 MIPS r5900\n"); memset(&bootinfo, 0, sizeof(bootinfo)); size = info->size; if (size > sizeof(bootinfo)) { size = sizeof(bootinfo); } memcpy(&bootinfo, info, size); sbios_magic = (uint32_t *) SBIOS_MAGIC; if (*sbios_magic == SBIOS_MAGICVAL) { gd->arch._sbios = *(int (**)(int, void *))(SBIOS_BASE); } else gd->arch._sbios = NULL; sbversion = sbios(SB_GETVER, NULL); printf("SBIOS Version 0x%08x\n", sbversion); driver_init(); return 0; }
static void check_sif_irq(void) { if (inl(EE_DMAC_SIF0_CHCR) & CHCR_STR) { /* DMA not finished, no interrupt. */ return; } /* Emulate interrupt. */ sbios(SB_SIFCMDINTRHDLR, NULL); }
static void driver_init(void) { int rv; int result; rv = sbios(SB_SIFINIT, NULL); if (rv < 0) { error("SB_SIFINIT failed rv = %d\n", rv); return; } rv = sbios(SB_SIFINITCMD, NULL); if (rv < 0) { error("SB_SIFINITCMD failed rv = %d\n", rv); return; } rv = sbios(SB_SIFINITRPC, NULL); if (rv < 0) { error("SB_SIFINITRPC failed rv = %d\n", rv); return; } for (;;) { debug("Call SBR_IOPH_INIT\n"); rv = sbios_rpc(SBR_IOPH_INIT, NULL, &result); debug("rv = %d\n", rv); if (rv < 0) { error("SBR_IOPH_INIT failed rv = %d\n", rv); return; } debug("result = %d\n", result); if (result == 0) { /* Success */ break; } } debug("SBIOS drivers successfully initialized.\n"); }
static int sbios_rpc(int func, void *arg, int *result) { int ret; struct sbr_common_arg carg; volatile int woken = 0; carg.arg = arg; carg.func = rpc_wakeup; carg.para = (void *) &woken; carg.result = -1; do { debug("Call SBIOS %d\n", func); ret = sbios(func, &carg); debug("ret = %d\n", ret); switch (ret) { case 0: break; case -SIF_RPCE_SENDP: /* resource temporarily unavailable */ /* Time to check for interrupts. */ check_sif_irq(); break; default: *result = ret; error("sbios_rpc: RPC failed, func=%d result=%d\n", func, ret); return ret; } } while (ret < 0); while(woken == 0) { debug("check_sif_irq\n"); /* Time to check for interrupts. */ check_sif_irq(); } debug("carg.result %d\n", carg.result); *result = carg.result; return 0; }
static int ps2cdvd_reset(struct cdrom_device_info *cdi) { unsigned long flags; save_flags(flags); cli(); ps2sif_lock(ps2cdvd_lock, "cdvd_reset"); RESET_TIMER(); #ifdef CONFIG_PS2_SBIOS_VER_CHECK if (0x0201 <= sbios(SB_GETVER, NULL)) ps2cdvdcall_reset(); #else ps2cdvdcall_reset(); #endif invalidate_discinfo(); ps2cdvd_state = ps2cdvd_enter(STAT_WAIT_DISC); ps2sif_unlock(ps2cdvd_lock); restore_flags(flags); return 0; }
static void ps2cdvd_state_machine(struct ps2cdvd_event* ev) { unsigned long flags; int old_state = ps2cdvd_state; int new_state = ps2cdvd_state; struct sbr_common_arg *carg = ev->arg; DPRINT(DBG_STATE, "state: %s event: %s\n", ps2cdvd_getstatestr(old_state), ps2cdvd_geteventstr(ev->type)); save_flags(flags); cli(); switch (ps2cdvd_state) { case STAT_WAIT_DISC: switch (ev->type) { case EV_START: case EV_TIMEOUT: if (ps2cdvd_lowlevel_lock() < 0) { /* waiting for unlock... */ RESET_TIMER(); SET_TIMER(HZ * ps2cdvd_check_interval); } else { new_state = STAT_INIT_TRAYSTAT; } break; case EV_INTR: } break; case STAT_INIT_TRAYSTAT: switch (ev->type) { case EV_START: case EV_TIMEOUT: break; case EV_INTR: { if (carg->result != 0) { new_state = STAT_WAIT_DISC; } else { new_state = STAT_CHECK_DISCTYPE; } } break; } break; case STAT_CHECK_DISCTYPE: switch (ev->type) { case EV_START: case EV_TIMEOUT: break; case EV_INTR: disc_type = carg->result; DPRINT(DBG_INFO, "ps2cdvd_getdisctype()='%s', %d\n", ps2cdvd_getdisctypestr(disc_type), disc_type); switch (disc_type) { case SCECdPS2CDDA: /* PS2 CD DA */ case SCECdPS2CD: /* PS2 CD */ case SCECdPSCDDA: /* PS CD DA */ case SCECdPSCD: /* PS CD */ case SCECdCDDA: /* CD DA */ case SCECdPS2DVD: /* PS2 DVD */ case SCECdDVDV: /* DVD video */ new_state = STAT_INIT_CHECK_READY; break; case SCECdDETCTDVDD: /* DVD-dual detecting */ case SCECdDETCTDVDS: /* DVD-single detecting */ case SCECdDETCTCD: /* CD detecting */ case SCECdDETCT: /* detecting */ case SCECdNODISC: /* no disc */ new_state = disc_locked ? STAT_INVALID_DISC : STAT_WAIT_DISC; break; case SCECdIllgalMedia: /* illegal media */ case SCECdUNKNOWN: /* unknown */ printk(KERN_CRIT "ps2cdvd: illegal media\n"); new_state = disc_locked ? STAT_INVALID_DISC : STAT_WAIT_DISC; break; } break; } break; case STAT_INIT_CHECK_READY: switch (ev->type) { case EV_START: case EV_TIMEOUT: break; case EV_INTR: prev_read = jiffies; if (carg->result == SCECdComplete) { switch (disc_type) { case SCECdPS2CDDA: /* PS2 CD DA */ case SCECdPS2CD: /* PS2 CD */ case SCECdPSCDDA: /* PS CD DA */ case SCECdPSCD: /* PS CD */ case SCECdCDDA: /* CD DA */ new_state = STAT_TOC_READ; media_mode = SCECdCD; break; case SCECdPS2DVD: /* PS2 DVD */ case SCECdDVDV: /* DVD video */ new_state = STAT_SET_MMODE; media_mode = SCECdDVD; break; default: printk(KERN_CRIT "ps2cdvd: internal error at %s(%d)\n", __FILE__, __LINE__); new_state = disc_locked ? STAT_INVALID_DISC : STAT_WAIT_DISC; break; } } else { new_state = STAT_WAIT_DISC; } break; } break; case STAT_TOC_READ: switch (ev->type) { case EV_START: case EV_TIMEOUT: break; case EV_INTR: if (carg->result < 0) { DPRINT(DBG_DIAG, "gettoc() failed\n"); new_state = disc_locked ? STAT_INVALID_DISC : STAT_WAIT_DISC; } else { struct ps2cdvd_tocentry *toc; toc_valid = 1; toc = (struct ps2cdvd_tocentry *)tocbuf; leadout_start = msftolba(decode_bcd(toc[2].abs_msf[0]), decode_bcd(toc[2].abs_msf[1]), decode_bcd(toc[2].abs_msf[2])); #ifdef PS2CDVD_DEBUG if (ps2cdvd_debug & DBG_INFO) { struct sbr_cdvd_gettoc_arg *arg = carg->arg; if (arg->media == 0) { ps2cdvd_tocdump(DBG_LOG_LEVEL "ps2cdvd: ", (struct ps2cdvd_tocentry *)tocbuf); } else { /* * we have no interrest in DVD Physical format information ps2cdvd_hexdump(tocbuf, len); */ } } #endif new_state = STAT_SET_MMODE; } break; } break; case STAT_SET_MMODE: switch (ev->type) { case EV_START: case EV_TIMEOUT: break; case EV_INTR: if (carg->result == 0) { DPRINT(DBG_DIAG, "set_mmode() failed\n"); new_state = disc_locked ? STAT_INVALID_DISC : STAT_WAIT_DISC; } else { switch (disc_type) { case SCECdPS2DVD: /* PS2 DVD */ case SCECdPS2CDDA: /* PS2 CD DA */ case SCECdPS2CD: /* PS2 CD */ case SCECdPSCDDA: /* PS CD DA */ case SCECdPSCD: /* PS CD */ new_state = STAT_LABEL_READ; break; case SCECdDVDV: /* DVD video */ case SCECdCDDA: /* CD DA */ if (disc_locked && disc_lock_key_valid) { new_state = STAT_LABEL_READ; } else { disc_changed++; new_state = STAT_READY; } break; default: printk(KERN_CRIT "ps2cdvd: internal error at %s(%d)\n", __FILE__, __LINE__); new_state = disc_locked ? STAT_INVALID_DISC : STAT_WAIT_DISC; break; } break; } } break; case STAT_LABEL_READ: switch (ev->type) { case EV_START: case EV_TIMEOUT: break; case EV_INTR: new_state = STAT_LABEL_READ_ERROR_CHECK; break; } break; case STAT_LABEL_READ_ERROR_CHECK: switch (ev->type) { case EV_START: case EV_TIMEOUT: break; case EV_INTR: if (carg->result != SCECdErNO) { DPRINT(DBG_DIAG, "error: %s, code=0x%02x\n", ps2cdvd_geterrorstr(carg->result), carg->result); if (disc_locked && disc_lock_key_valid) { printk(KERN_CRIT "ps2cdvd: =============================\n"); printk(KERN_CRIT "ps2cdvd: wrong disc. \n"); printk(KERN_CRIT "ps2cdvd: =============================\n"); if (!ps2cdvd_wrong_disc_retry) { INIT_REQUEST; while (CURRENT) end_request(0); disc_changed++; } } new_state = disc_locked ? STAT_INVALID_DISC : STAT_WAIT_DISC; } else { unsigned long sum; #ifdef PS2CDVD_DEBUG struct iso_primary_descriptor *label; label = (struct iso_primary_descriptor*)labelbuf; if (ps2cdvd_debug & DBG_INFO) { printk(DBG_LOG_LEVEL "ps2cdvd: "); print_isofsstr(label->system_id, sizeof(label->system_id)); print_isofsstr(label->volume_id, sizeof(label->volume_id)); print_isofsstr(label->volume_set_id, sizeof(label->volume_set_id)); print_isofsstr(label->publisher_id, sizeof(label->publisher_id)); print_isofsstr(label->application_id, sizeof(label->application_id)); printk("\n"); /* ps2cdvd_hexdump(DBG_LOG_LEVEL "ps2cdvd: ", labelbuf, 2048); */ } #endif label_valid = 1; DPRINT(DBG_DLOCK, "label is valid\n"); sum = checksum((u_long*)labelbuf, 2048/sizeof(u_long)); if (disc_lock_key_valid && disc_locked && disc_lock_key != sum) { printk(KERN_CRIT "ps2cdvd: =============================\n"); printk(KERN_CRIT "ps2cdvd: wrong disc. \n"); printk(KERN_CRIT "ps2cdvd: =============================\n"); if (!ps2cdvd_wrong_disc_retry) { INIT_REQUEST; while (CURRENT) end_request(0); disc_changed++; } new_state = STAT_INVALID_DISC; } else { disc_lock_key = sum; if (!disc_lock_key_valid && disc_locked) { DPRINT(DBG_DLOCK, "disc lock key=%lX\n", sum); } disc_lock_key_valid = 1; new_state = STAT_READY; } } break; } break; case STAT_READY: switch (ev->type) { case EV_TICK: if (CURRENT == NULL || ps2sif_iswaiting(ps2cdvd_lock)) { break; } /* fall through */ case EV_START: case EV_TIMEOUT: if (ps2cdvd_lowlevel_lock() < 0) { /* waiting for unlock... */ RESET_TIMER(); SET_TIMER(HZ * ps2cdvd_check_interval); break; } if (CURRENT == NULL) { if (ps2cdvd_spindown * HZ < jiffies - prev_read) { new_state = STAT_SPINDOWN; } else { /* nothing to do */ ps2cdvd_lowlevel_unlock(); RESET_TIMER(); SET_TIMER(HZ * ps2cdvd_check_interval); } } else { prev_read = jiffies; if (jiffies - prev_tray_check < HZ/2) { new_state = STAT_READ; } else { prev_tray_check = jiffies; new_state = STAT_CHECK_TRAY; } } break; case EV_INTR: break; } break; case STAT_CHECK_TRAY: switch (ev->type) { case EV_START: case EV_TIMEOUT: break; case EV_INTR: if (carg->result < 0) { new_state = STAT_ERROR; } else { struct sbr_cdvd_trayreq_arg *arg = carg->arg; if (arg->traycount != 0) { if (disc_locked) { printk(KERN_CRIT"ps2cdvd: =============================\n"); printk(KERN_CRIT"ps2cdvd: the disc is currently locked.\n"); printk(KERN_CRIT"ps2cdvd: please don't take it away!\n"); printk(KERN_CRIT"ps2cdvd: =============================\n"); } invalidate_discinfo(); new_state = STAT_CHECK_DISCTYPE; } else { if (CURRENT) { new_state = STAT_READ; } else { new_state = STAT_READY; } } } break; } break; case STAT_READ: switch (ev->type) { case EV_START: case EV_TIMEOUT: break; case EV_INTR: new_state = STAT_READ_ERROR_CHECK; break; } break; case STAT_READ_EOM_RETRY: switch (ev->type) { case EV_START: case EV_TIMEOUT: break; case EV_INTR: new_state = STAT_READ_ERROR_CHECK; break; } break; case STAT_READ_ERROR_CHECK: switch (ev->type) { case EV_START: case EV_TIMEOUT: break; case EV_INTR: if (carg->result == SCECdErNO) { /* * succeeded */ while (CURRENT != NULL && ps2cdvd_databuf_addr <= CURRENT->sector/4 && CURRENT->sector/4 < ps2cdvd_databuf_addr + ps2cdvd_databuf_size) { memcpy(CURRENT->buffer, ps2cdvd_databuf + DATA_SECT_SIZE * (CURRENT->sector/4 - ps2cdvd_databuf_addr), DATA_SECT_SIZE); end_request(1); } if (!ps2sif_iswaiting(ps2cdvd_lock) && CURRENT != NULL) { /* tiny acceleration */ new_state = STAT_READ; } else { new_state = STAT_READY; } } else if (carg->result == 0x38) { /* * sector format error */ DPRINT(DBG_DIAG, "error: sector format error, code=0x38 (ignored)\n"); memset(CURRENT->buffer, 0, DATA_SECT_SIZE); end_request(1); if (!ps2sif_iswaiting(ps2cdvd_lock) && CURRENT != NULL) { /* tiny acceleration */ new_state = STAT_READ; } else { new_state = STAT_READY; } } else if (carg->result == SCECdErEOM && ps2cdvd_databuf_addr != CURRENT->sector/4 - ps2cdvd_databuf_size + 1 && ps2cdvd_databuf_size <= CURRENT->sector/4) { /* you got End Of Media and you have not retried */ DPRINT(DBG_DIAG, "error: %s, code=0x%02x (retry...)\n", ps2cdvd_geterrorstr(carg->result), carg->result); new_state = STAT_READ_EOM_RETRY; } else { DPRINT(DBG_DIAG, "error: %s, code=0x%02x\n", ps2cdvd_geterrorstr(carg->result), carg->result); ps2cdvd_databuf_addr = -1; end_request(0); /* I/O error */ new_state = STAT_READY; } break; } break; case STAT_INVALID_DISC: switch (ev->type) { case EV_START: case EV_TIMEOUT: if (ps2cdvd_lowlevel_lock() < 0) { /* waiting for unlock... */ RESET_TIMER(); SET_TIMER(HZ * ps2cdvd_check_interval); } else { new_state = STAT_CHECK_DISCTYPE; } break; case EV_INTR: break; } break; case STAT_SPINDOWN: switch (ev->type) { case EV_START: case EV_TIMEOUT: break; case EV_INTR: if (CURRENT == NULL) { new_state = STAT_IDLE; } else { DPRINT(DBG_VERBOSE, "re-spinup...\n"); new_state = STAT_CHECK_DISCTYPE; } break; } break; case STAT_IDLE: switch (ev->type) { case EV_START: case EV_TIMEOUT: if (ps2cdvd_lowlevel_lock() < 0) { /* waiting for unlock... */ RESET_TIMER(); SET_TIMER(HZ * ps2cdvd_check_interval); } else { new_state = STAT_CHECK_DISCTYPE; } break; case EV_INTR: break; } break; case STAT_ERROR: break; default: printk(KERN_ERR "ps2cdvd: invalid state"); ps2cdvd_state = STAT_WAIT_DISC; break; } if (new_state != old_state) { struct ps2cdvd_event tick; tick.type = EV_TICK; ps2cdvd_leave(old_state); ps2cdvd_state = ps2cdvd_enter(new_state); DPRINT(DBG_STATE, " -> new state: %s\n", ps2cdvd_getstatestr(ps2cdvd_state)); if (old_state != ps2cdvd_state && ps2cdvd_state == STAT_READY) { ps2cdvd_state_machine(&tick); } wake_up_interruptible(&statq); } restore_flags(flags); } __initfunc(int ps2cdvd_init(void)) { int res; DPRINT(DBG_VERBOSE, "init: get lock\n"); if ((ps2cdvd_lock = ps2sif_getlock(PS2LOCK_CDVD)) == NULL) { printk(KERN_ERR "ps2cdvd: Can't get lock\n"); ps2cdvd_cleanup(); return -EINVAL; } ps2sif_lockqueueinit(&ps2cdvd_lock_qi); ps2cdvd_lock_qi.name = "ps2cdvd"; DPRINT(DBG_VERBOSE, "init: initialize timer\n"); init_timer(&io_timer); io_timer.function = (void(*)(u_long))ps2cdvd_timer; ps2cdvd_state = STAT_WAIT_DISC; DPRINT(DBG_VERBOSE, "init: allocate diaklabel buffer\n"); labelbuf = kmalloc(2048, GFP_KERNEL); if (labelbuf == NULL) { printk(KERN_ERR "ps2cdvd: Can't allocate buffer\n"); ps2cdvd_cleanup(); return -ENOMEM; } initialized |= INIT_LABELBUF; DPRINT(DBG_VERBOSE, "allocate buffer\n"); ps2cdvd_databufx = kmalloc(ps2cdvd_databuf_size * AUDIO_SECT_SIZE + BUFFER_ALIGNMENT, GFP_KERNEL); if (ps2cdvd_databufx == NULL) { printk(KERN_ERR "ps2cdvd: Can't allocate buffer\n"); ps2cdvd_cleanup(); return -ENOMEM; } ps2cdvd_databuf = ALIGN(ps2cdvd_databufx, BUFFER_ALIGNMENT); initialized |= INIT_DATABUF; DPRINT(DBG_VERBOSE, "init: call sbios\n"); if (ps2cdvdcall_init()) { printk(KERN_ERR "ps2cdvd: Can't initialize CD/DVD-ROM subsystem\n"); ps2cdvd_cleanup(); return -EIO; } #ifdef CONFIG_PS2_SBIOS_VER_CHECK if (0x0201 <= sbios(SB_GETVER, NULL)) ps2cdvdcall_reset(); #else ps2cdvdcall_reset(); #endif initialized |= INIT_IOPSIDE; DPRINT(DBG_VERBOSE, "init: register block device\n"); if ((res = register_blkdev(MAJOR_NR, "ps2cdvd", &cdrom_fops)) < 0) { printk(KERN_ERR "ps2cdvd: Unable to get major %d for PS2 CD/DVD-ROM\n", MAJOR_NR); ps2cdvd_cleanup(); return -EIO; } if (MAJOR_NR == 0) MAJOR_NR = res; initialized |= INIT_BLKDEV; blksize_size[MAJOR_NR] = ps2cdvd_blocksizes; hardsect_size[MAJOR_NR] = ps2cdvd_hardsectsizes; blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; read_ahead[MAJOR_NR] = ps2cdvd_read_ahead; DPRINT(DBG_VERBOSE, "init: register cdrom\n"); ps2cdvd_info.dev = MKDEV(MAJOR_NR, 0); if (register_cdrom(&ps2cdvd_info) != 0) { printk(KERN_ERR "ps2cdvd: Cannot register PS2 CD/DVD-ROM\n"); ps2cdvd_cleanup(); return -EIO; } initialized |= INIT_CDROM; printk(KERN_INFO "PS2 CD/DVD-ROM driver\n"); if (ps2cdvd_lowlevel_lock() == 0) ps2cdvd_state = ps2cdvd_enter(STAT_INIT_TRAYSTAT); else ps2cdvd_state = ps2cdvd_enter(STAT_WAIT_DISC); return 0; }