__initfunc(int mcd_init(void)) { int count; unsigned char result[3]; char msg[80]; if (mcd_port <= 0 || mcd_irq <= 0) { printk("skip mcd_init\n"); return -EIO; } if (register_blkdev(MAJOR_NR, "mcd", &cdrom_fops) != 0) { printk("Unable to get major %d for Mitsumi CD-ROM\n", MAJOR_NR); return -EIO; } if (check_region(mcd_port, 4)) { cleanup(1); printk("Init failed, I/O port (%X) already in use\n", mcd_port); return -EIO; } blksize_size[MAJOR_NR] = mcd_blocksizes; blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; read_ahead[MAJOR_NR] = 4; /* check for card */ outb(0, MCDPORT(1)); /* send reset */ for (count = 0; count < 2000000; count++) (void) inb(MCDPORT(1)); /* delay a bit */ outb(0x40, MCDPORT(0)); /* send get-stat cmd */ for (count = 0; count < 2000000; count++) if (!(inb(MCDPORT(1)) & MFL_STATUS)) break; if (count >= 2000000) { printk("Init failed. No mcd device at 0x%x irq %d\n", mcd_port, mcd_irq); cleanup(1); return -EIO; } count = inb(MCDPORT(0)); /* pick up the status */ outb(MCMD_GET_VERSION,MCDPORT(0)); for(count=0;count<3;count++) if(getValue(result+count)) { printk("mitsumi get version failed at 0x%d\n", mcd_port); cleanup(1); return -EIO; } if (result[0] == result[1] && result[1] == result[2]) { cleanup(1); return -EIO; } mcdVersion=result[2]; if (mcdVersion >=4) outb(4,MCDPORT(2)); /* magic happens */ /* don't get the IRQ until we know for sure the drive is there */ if (request_irq(mcd_irq, mcd_interrupt, SA_INTERRUPT, "Mitsumi CD", NULL)) { printk("Unable to get IRQ%d for Mitsumi CD-ROM\n", mcd_irq); cleanup(1); return -EIO; } if (result[1] == 'D') { sprintf(msg, " mcd: Mitsumi Double Speed CD-ROM at port=0x%x," " irq=%d\n", mcd_port, mcd_irq); MCMD_DATA_READ = MCMD_2X_READ; mcd_info.speed = 2; /* Added flag to drop to 1x speed if too many errors */ mcdDouble = 1; } else { sprintf(msg, " mcd: Mitsumi Single Speed CD-ROM at port=0x%x," " irq=%d\n", mcd_port, mcd_irq); mcd_info.speed = 2; } request_region(mcd_port, 4, "mcd"); outb(MCMD_CONFIG_DRIVE, MCDPORT(0)); outb(0x02,MCDPORT(0)); outb(0x00,MCDPORT(0)); getValue(result); outb(MCMD_CONFIG_DRIVE, MCDPORT(0)); outb(0x10,MCDPORT(0)); outb(0x04,MCDPORT(0)); getValue(result); mcd_invalidate_buffers(); mcdPresent = 1; mcd_info.dev = MKDEV(MAJOR_NR,0); if (register_cdrom(&mcd_info) != 0) { printk("Cannot register Mitsumi CD-ROM!\n"); cleanup(3); return -EIO; } printk(msg); return 0; }
int __init mcd_init(void) { struct gendisk *disk = alloc_disk(1); int count; unsigned char result[3]; char msg[80]; if (!disk) { printk(KERN_INFO "mcd: can't allocated disk.\n"); return -ENOMEM; } if (mcd_port <= 0 || mcd_irq <= 0) { printk(KERN_INFO "mcd: not probing.\n"); put_disk(disk); return -EIO; } if (register_blkdev(MAJOR_NR, "mcd")) { put_disk(disk); return -EIO; } if (!request_region(mcd_port, 4, "mcd")) { printk(KERN_ERR "mcd: Initialization failed, I/O port (%X) already in use\n", mcd_port); goto out_region; } mcd_queue = blk_init_queue(do_mcd_request, &mcd_spinlock); if (!mcd_queue) goto out_queue; /* check for card */ outb(0, MCDPORT(1)); /* send reset */ for (count = 0; count < 2000000; count++) (void) inb(MCDPORT(1)); /* delay a bit */ outb(0x40, MCDPORT(0)); /* send get-stat cmd */ for (count = 0; count < 2000000; count++) if (!(inb(MCDPORT(1)) & MFL_STATUS)) break; if (count >= 2000000) { printk(KERN_INFO "mcd: initialisation failed - No mcd device at 0x%x irq %d\n", mcd_port, mcd_irq); goto out_probe; } count = inb(MCDPORT(0)); /* pick up the status */ outb(MCMD_GET_VERSION, MCDPORT(0)); for (count = 0; count < 3; count++) if (getValue(result + count)) { printk(KERN_ERR "mcd: mitsumi get version failed at 0x%x\n", mcd_port); goto out_probe; } if (result[0] == result[1] && result[1] == result[2]) goto out_probe; mcdVersion = result[2]; if (mcdVersion >= 4) outb(4, MCDPORT(2)); /* magic happens */ /* don't get the IRQ until we know for sure the drive is there */ if (request_irq(mcd_irq, mcd_interrupt, SA_INTERRUPT, "Mitsumi CD", NULL)) { printk(KERN_ERR "mcd: Unable to get IRQ%d for Mitsumi CD-ROM\n", mcd_irq); goto out_probe; } if (result[1] == 'D') { MCMD_DATA_READ = MCMD_2X_READ; /* Added flag to drop to 1x speed if too many errors */ mcdDouble = 1; } else mcd_info.speed = 1; sprintf(msg, " mcd: Mitsumi %s Speed CD-ROM at port=0x%x," " irq=%d\n", mcd_info.speed == 1 ? "Single" : "Double", mcd_port, mcd_irq); outb(MCMD_CONFIG_DRIVE, MCDPORT(0)); outb(0x02, MCDPORT(0)); outb(0x00, MCDPORT(0)); getValue(result); outb(MCMD_CONFIG_DRIVE, MCDPORT(0)); outb(0x10, MCDPORT(0)); outb(0x04, MCDPORT(0)); getValue(result); mcd_invalidate_buffers(); mcdPresent = 1; disk->major = MAJOR_NR; disk->first_minor = 0; sprintf(disk->disk_name, "mcd"); disk->fops = &mcd_bdops; disk->flags = GENHD_FL_CD; mcd_gendisk = disk; if (register_cdrom(&mcd_info) != 0) { printk(KERN_ERR "mcd: Unable to register Mitsumi CD-ROM.\n"); goto out_cdrom; } disk->queue = mcd_queue; add_disk(disk); printk(msg); return 0; out_cdrom: free_irq(mcd_irq, NULL); out_queue: release_region(mcd_port, 4); out_probe: blk_cleanup_queue(mcd_queue); out_region: unregister_blkdev(MAJOR_NR, "mcd"); put_disk(disk); return -EIO; }
int __init mcd_init(void) { int count; unsigned char result[3]; char msg[80]; if (mcd_port <= 0 || mcd_irq <= 0) { printk(KERN_INFO "mcd: not probing.\n"); return -EIO; } if (devfs_register_blkdev(MAJOR_NR, "mcd", &mcd_bdops) != 0) { printk(KERN_ERR "mcd: Unable to get major %d for Mitsumi CD-ROM\n", MAJOR_NR); return -EIO; } if (check_region(mcd_port, 4)) { cleanup(1); printk(KERN_ERR "mcd: Initialization failed, I/O port (%X) already in use\n", mcd_port); return -EIO; } blksize_size[MAJOR_NR] = mcd_blocksizes; blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST, &mcd_spinlock); read_ahead[MAJOR_NR] = 4; /* check for card */ outb(0, MCDPORT(1)); /* send reset */ for (count = 0; count < 2000000; count++) (void) inb(MCDPORT(1)); /* delay a bit */ outb(0x40, MCDPORT(0)); /* send get-stat cmd */ for (count = 0; count < 2000000; count++) if (!(inb(MCDPORT(1)) & MFL_STATUS)) break; if (count >= 2000000) { printk(KERN_INFO "mcd: initialisation failed - No mcd device at 0x%x irq %d\n", mcd_port, mcd_irq); cleanup(1); return -EIO; } count = inb(MCDPORT(0)); /* pick up the status */ outb(MCMD_GET_VERSION, MCDPORT(0)); for (count = 0; count < 3; count++) if (getValue(result + count)) { printk(KERN_ERR "mcd: mitsumi get version failed at 0x%x\n", mcd_port); cleanup(1); return -EIO; } if (result[0] == result[1] && result[1] == result[2]) { cleanup(1); return -EIO; } mcdVersion = result[2]; if (mcdVersion >= 4) outb(4, MCDPORT(2)); /* magic happens */ /* don't get the IRQ until we know for sure the drive is there */ if (request_irq(mcd_irq, mcd_interrupt, SA_INTERRUPT, "Mitsumi CD", NULL)) { printk(KERN_ERR "mcd: Unable to get IRQ%d for Mitsumi CD-ROM\n", mcd_irq); cleanup(1); return -EIO; } if (result[1] == 'D') { MCMD_DATA_READ = MCMD_2X_READ; /* Added flag to drop to 1x speed if too many errors */ mcdDouble = 1; } else mcd_info.speed = 1; sprintf(msg, " mcd: Mitsumi %s Speed CD-ROM at port=0x%x," " irq=%d\n", mcd_info.speed == 1 ? "Single" : "Double", mcd_port, mcd_irq); request_region(mcd_port, 4, "mcd"); outb(MCMD_CONFIG_DRIVE, MCDPORT(0)); outb(0x02, MCDPORT(0)); outb(0x00, MCDPORT(0)); getValue(result); outb(MCMD_CONFIG_DRIVE, MCDPORT(0)); outb(0x10, MCDPORT(0)); outb(0x04, MCDPORT(0)); getValue(result); mcd_invalidate_buffers(); mcdPresent = 1; mcd_info.dev = mk_kdev(MAJOR_NR, 0); if (register_cdrom(&mcd_info) != 0) { printk(KERN_ERR "mcd: Unable to register Mitsumi CD-ROM.\n"); cleanup(3); return -EIO; } devfs_plain_cdrom(&mcd_info, &mcd_bdops); printk(msg); return 0; }
static int __init mcdx_init_drive(int drive) { struct s_version version; struct gendisk *disk; struct s_drive_stuff *stuffp; int size = sizeof(*stuffp); char msg[80]; xtrace(INIT, "init() try drive %d\n", drive); xtrace(INIT, "kmalloc space for stuffpt's\n"); xtrace(MALLOC, "init() malloc %d bytes\n", size); if (!(stuffp = kzalloc(size, GFP_KERNEL))) { xwarn("init() malloc failed\n"); return 1; } disk = alloc_disk(1); if (!disk) { xwarn("init() malloc failed\n"); kfree(stuffp); return 1; } xtrace(INIT, "init() got %d bytes for drive stuff @ %p\n", sizeof(*stuffp), stuffp); /* set default values */ stuffp->present = 0; /* this should be 0 already */ stuffp->toc = NULL; /* this should be NULL already */ /* setup our irq and i/o addresses */ stuffp->irq = irq(mcdx_drive_map[drive]); stuffp->wreg_data = stuffp->rreg_data = port(mcdx_drive_map[drive]); stuffp->wreg_reset = stuffp->rreg_status = stuffp->wreg_data + 1; stuffp->wreg_hcon = stuffp->wreg_reset + 1; stuffp->wreg_chn = stuffp->wreg_hcon + 1; init_waitqueue_head(&stuffp->busyq); init_waitqueue_head(&stuffp->lockq); init_waitqueue_head(&stuffp->sleepq); /* check if i/o addresses are available */ if (!request_region(stuffp->wreg_data, MCDX_IO_SIZE, "mcdx")) { xwarn("0x%03x,%d: Init failed. " "I/O ports (0x%03x..0x%03x) already in use.\n", stuffp->wreg_data, stuffp->irq, stuffp->wreg_data, stuffp->wreg_data + MCDX_IO_SIZE - 1); xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp); kfree(stuffp); put_disk(disk); xtrace(INIT, "init() continue at next drive\n"); return 0; /* next drive */ } xtrace(INIT, "init() i/o port is available at 0x%03x\n" stuffp->wreg_data); xtrace(INIT, "init() hardware reset\n"); mcdx_reset(stuffp, HARD, 1); xtrace(INIT, "init() get version\n"); if (-1 == mcdx_requestversion(stuffp, &version, 4)) { /* failed, next drive */ release_region(stuffp->wreg_data, MCDX_IO_SIZE); xwarn("%s=0x%03x,%d: Init failed. Can't get version.\n", MCDX, stuffp->wreg_data, stuffp->irq); xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp); kfree(stuffp); put_disk(disk); xtrace(INIT, "init() continue at next drive\n"); return 0; } switch (version.code) { case 'D': stuffp->readcmd = READ2X; stuffp->present = DOUBLE | DOOR | MULTI; break; case 'F': stuffp->readcmd = READ1X; stuffp->present = SINGLE | DOOR | MULTI; break; case 'M': stuffp->readcmd = READ1X; stuffp->present = SINGLE; break; default: stuffp->present = 0; break; } stuffp->playcmd = READ1X; if (!stuffp->present) { release_region(stuffp->wreg_data, MCDX_IO_SIZE); xwarn("%s=0x%03x,%d: Init failed. No Mitsumi CD-ROM?.\n", MCDX, stuffp->wreg_data, stuffp->irq); kfree(stuffp); put_disk(disk); return 0; /* next drive */ } xtrace(INIT, "init() register blkdev\n"); if (register_blkdev(MAJOR_NR, "mcdx")) { release_region(stuffp->wreg_data, MCDX_IO_SIZE); kfree(stuffp); put_disk(disk); return 1; } mcdx_queue = blk_init_queue(do_mcdx_request, &mcdx_lock); if (!mcdx_queue) { unregister_blkdev(MAJOR_NR, "mcdx"); release_region(stuffp->wreg_data, MCDX_IO_SIZE); kfree(stuffp); put_disk(disk); return 1; } xtrace(INIT, "init() subscribe irq and i/o\n"); if (request_irq(stuffp->irq, mcdx_intr, IRQF_DISABLED, "mcdx", stuffp)) { release_region(stuffp->wreg_data, MCDX_IO_SIZE); xwarn("%s=0x%03x,%d: Init failed. Can't get irq (%d).\n", MCDX, stuffp->wreg_data, stuffp->irq, stuffp->irq); stuffp->irq = 0; blk_cleanup_queue(mcdx_queue); kfree(stuffp); put_disk(disk); return 0; } xtrace(INIT, "init() get garbage\n"); { int i; mcdx_delay(stuffp, HZ / 2); for (i = 100; i; i--) (void) inb(stuffp->rreg_status); } #ifdef WE_KNOW_WHY /* irq 11 -> channel register */ outb(0x50, stuffp->wreg_chn); #endif xtrace(INIT, "init() set non dma but irq mode\n"); mcdx_config(stuffp, 1); stuffp->info.ops = &mcdx_dops; stuffp->info.speed = 2; stuffp->info.capacity = 1; stuffp->info.handle = stuffp; sprintf(stuffp->info.name, "mcdx%d", drive); disk->major = MAJOR_NR; disk->first_minor = drive; strcpy(disk->disk_name, stuffp->info.name); disk->fops = &mcdx_bdops; disk->flags = GENHD_FL_CD; stuffp->disk = disk; sprintf(msg, " mcdx: Mitsumi CD-ROM installed at 0x%03x, irq %d." " (Firmware version %c %x)\n", stuffp->wreg_data, stuffp->irq, version.code, version.ver); mcdx_stuffp[drive] = stuffp; xtrace(INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp); if (register_cdrom(&stuffp->info) != 0) { printk("Cannot register Mitsumi CD-ROM!\n"); free_irq(stuffp->irq, NULL); release_region(stuffp->wreg_data, MCDX_IO_SIZE); kfree(stuffp); put_disk(disk); if (unregister_blkdev(MAJOR_NR, "mcdx") != 0) xwarn("cleanup() unregister_blkdev() failed\n"); blk_cleanup_queue(mcdx_queue); return 2; } disk->private_data = stuffp; disk->queue = mcdx_queue; add_disk(disk); printk(msg); 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; }