/* * Open the device special file. Check that a disk is in. */ static int mcd_open(struct cdrom_device_info * cdi, int purpose) { int st, count=0; if (mcdPresent == 0) return -ENXIO; /* no hardware */ if (!mcd_open_count && mcd_state == MCD_S_IDLE) { mcd_invalidate_buffers(); do { st = statusCmd(); /* check drive status */ if (st == -1) return -EIO; /* drive doesn't respond */ if ((st & MST_READY) == 0) { /* no disk? wait a sec... */ current->state = TASK_INTERRUPTIBLE; schedule_timeout(HZ); } } while (((st & MST_READY) == 0) && count++ < MCD_RETRY_ATTEMPTS); if (updateToc() < 0) return -EIO; } ++mcd_open_count; MOD_INC_USE_COUNT; return 0; }
/* * Open the device special file. Check that a disk is in. */ static int mcd_open(struct cdrom_device_info *cdi, int purpose) { int st, count = 0; if (mcdPresent == 0) return -ENXIO; /* no hardware */ if (mcd_open_count || mcd_state != MCD_S_IDLE) goto bump_count; mcd_invalidate_buffers(); do { st = statusCmd(); /* check drive status */ if (st == -1) goto err_out; /* drive doesn't respond */ if ((st & MST_READY) == 0) /* no disk? wait a sec... */ msleep(1000); } while (((st & MST_READY) == 0) && count++ < MCD_RETRY_ATTEMPTS); if (updateToc() < 0) goto err_out; bump_count: ++mcd_open_count; return 0; err_out: return -EIO; }
static void mcd_release(struct inode * inode, struct file * file) { MOD_DEC_USE_COUNT; if (!--mcd_open_count) { mcd_invalidate_buffers(); sync_dev(inode->i_rdev); invalidate_buffers(inode -> i_rdev); } }
int mcd_open(struct inode *ip, struct file *fp) { int st; int count = 0; if (mcdPresent == 0) return -ENXIO; /* no hardware */ if (fp->f_mode & 2) /* write access? */ return -EROFS; if (!mcd_open_count && mcd_state == MCD_S_IDLE) { mcd_invalidate_buffers(); do { st = statusCmd(); /* check drive status */ if (st == -1) return -EIO; /* drive doesn't respond */ if ((st & MST_READY) == 0) { /* no disk? wait a sec... */ current->state = TASK_INTERRUPTIBLE; current->timeout = jiffies + HZ; schedule(); } } while (((st & MST_READY) == 0) && count++ < MCD_RETRY_ATTEMPTS); if ((st & MST_READY) == 0) /* no disk in drive */ { printk("mcd: no disk in drive\n"); return -EIO; } if (updateToc() < 0) return -EIO; } ++mcd_open_count; MOD_INC_USE_COUNT; return 0; }
static void mcd_poll(void) { int st; if (mcd_error) { if (mcd_error & 0xA5) { printk("mcd: I/O error 0x%02x", mcd_error); if (mcd_error & 0x80) printk(" (Door open)"); if (mcd_error & 0x20) printk(" (Disk changed)"); if (mcd_error & 0x04) { printk(" (Read error)"); /* Bitch about the problem. */ /* Time to get fancy! If at 2x speed and 1 error, drop to 1x speed! */ /* Interesting how it STAYS at MCD_RETRY_ATTEMPTS on first error! */ /* But I find that rather HANDY!!! */ /* Neat! it REALLY WORKS on those LOW QUALITY CD's!!! Smile! :) */ /* AJK [06/17/95] */ /* Slap the CD down to single speed! */ if (mcdDouble == 1 && McdTries == MCD_RETRY_ATTEMPTS && MCMD_DATA_READ == MCMD_2X_READ) { MCMD_DATA_READ = MCMD_PLAY_READ; /* Uhhh, Ummmm, muhuh-huh! */ mcd1xhold = SINGLE_HOLD_SECTORS; /* Hey Beavis! */ printk(" Speed now 1x"); /* Pull my finger! */ } } printk("\n"); mcd_invalidate_buffers(); #ifdef WARN_IF_READ_FAILURE if (McdTries == MCD_RETRY_ATTEMPTS) printk("mcd: read of block %d failed\n", mcd_next_bn); #endif if (!McdTries--) { /* Nuts! This cd is ready for recycling! */ /* When WAS the last time YOU cleaned it CORRECTLY?! */ printk("mcd: read of block %d failed, giving up\n", mcd_next_bn); if (mcd_transfer_is_active) { McdTries = 0; goto ret; } if (CURRENT_VALID) end_request(0); McdTries = MCD_RETRY_ATTEMPTS; } } mcd_error = 0; mcd_state = MCD_S_STOP; } /* Switch back to Double speed if enough GOOD sectors were read! */ /* Are we a double speed with a crappy CD?! */ if (mcdDouble == 1 && McdTries == MCD_RETRY_ATTEMPTS && MCMD_DATA_READ == MCMD_PLAY_READ) { /* We ARE a double speed and we ARE bitching! */ if (mcd1xhold == 0) /* Okay, Like are we STILL at single speed? */ { /* We need to switch back to double speed now... */ MCMD_DATA_READ = MCMD_2X_READ; /* Uhhh... BACK You GO! */ printk("mcd: Switching back to 2X speed!\n"); /* Tell 'em! */ } else mcd1xhold--; /* No?! Count down the good reads some more... */ /* and try, try again! */ } immediately: switch (mcd_state) { case MCD_S_IDLE: #ifdef TEST3 printk("MCD_S_IDLE\n"); #endif return; case MCD_S_START: #ifdef TEST3 printk("MCD_S_START\n"); #endif outb(MCMD_GET_STATUS, MCDPORT(0)); mcd_state = mcd_mode == 1 ? MCD_S_READ : MCD_S_MODE; McdTimeout = 3000; break; case MCD_S_MODE: #ifdef TEST3 printk("MCD_S_MODE\n"); #endif if ((st = mcdStatus()) != -1) { if (st & MST_DSK_CHG) { mcdDiskChanged = 1; tocUpToDate = 0; mcd_invalidate_buffers(); } set_mode_immediately: if ((st & MST_DOOR_OPEN) || !(st & MST_READY)) { mcdDiskChanged = 1; tocUpToDate = 0; if (mcd_transfer_is_active) { mcd_state = MCD_S_START; goto immediately; } printk((st & MST_DOOR_OPEN) ? "mcd: door open\n" : "mcd: disk removed\n"); mcd_state = MCD_S_IDLE; while (CURRENT_VALID) end_request(0); return; } outb(MCMD_SET_MODE, MCDPORT(0)); outb(1, MCDPORT(0)); mcd_mode = 1; mcd_state = MCD_S_READ; McdTimeout = 3000; } break; case MCD_S_READ: #ifdef TEST3 printk("MCD_S_READ\n"); #endif if ((st = mcdStatus()) != -1) { if (st & MST_DSK_CHG) { mcdDiskChanged = 1; tocUpToDate = 0; mcd_invalidate_buffers(); } read_immediately: if ((st & MST_DOOR_OPEN) || !(st & MST_READY)) { mcdDiskChanged = 1; tocUpToDate = 0; if (mcd_transfer_is_active) { mcd_state = MCD_S_START; goto immediately; } printk((st & MST_DOOR_OPEN) ? "mcd: door open\n" : "mcd: disk removed\n"); mcd_state = MCD_S_IDLE; while (CURRENT_VALID) end_request(0); return; } if (CURRENT_VALID) { struct mcd_Play_msf msf; mcd_next_bn = CURRENT -> sector / 4; hsg2msf(mcd_next_bn, &msf.start); msf.end.min = ~0; msf.end.sec = ~0; msf.end.frame = ~0; sendMcdCmd(MCMD_DATA_READ, &msf); mcd_state = MCD_S_DATA; McdTimeout = READ_TIMEOUT; } else { mcd_state = MCD_S_STOP; goto immediately; } } break; case MCD_S_DATA: #ifdef TEST3 printk("MCD_S_DATA\n"); #endif st = inb(MCDPORT(1)) & (MFL_STATUSorDATA); data_immediately: #ifdef TEST5 printk("Status %02x\n",st); #endif switch (st) { case MFL_DATA: #ifdef WARN_IF_READ_FAILURE if (McdTries == 5) printk("mcd: read of block %d failed\n", mcd_next_bn); #endif if (!McdTries--) { printk("mcd: read of block %d failed, giving up\n", mcd_next_bn); if (mcd_transfer_is_active) { McdTries = 0; break; } if (CURRENT_VALID) end_request(0); McdTries = 5; } mcd_state = MCD_S_START; McdTimeout = READ_TIMEOUT; goto immediately; case MFL_STATUSorDATA: break; default: McdTries = 5; if (!CURRENT_VALID && mcd_buf_in == mcd_buf_out) { mcd_state = MCD_S_STOP; goto immediately; } mcd_buf_bn[mcd_buf_in] = -1; READ_DATA(MCDPORT(0), mcd_buf + 2048 * mcd_buf_in, 2048); mcd_buf_bn[mcd_buf_in] = mcd_next_bn++; if (mcd_buf_out == -1) mcd_buf_out = mcd_buf_in; mcd_buf_in = mcd_buf_in + 1 == MCD_BUF_SIZ ? 0 : mcd_buf_in + 1; if (!mcd_transfer_is_active) { while (CURRENT_VALID) { mcd_transfer(); if (CURRENT -> nr_sectors == 0) end_request(1); else break; } } if (CURRENT_VALID && (CURRENT -> sector / 4 < mcd_next_bn || CURRENT -> sector / 4 > mcd_next_bn + 16)) { mcd_state = MCD_S_STOP; goto immediately; } McdTimeout = READ_TIMEOUT; #ifdef DOUBLE_QUICK_ONLY if (MCMD_DATA_READ != MCMD_PLAY_READ) #endif { int count= QUICK_LOOP_COUNT; while (count--) { QUICK_LOOP_DELAY; if ((st = (inb(MCDPORT(1))) & (MFL_STATUSorDATA)) != (MFL_STATUSorDATA)) { # ifdef TEST4 /* printk("Quickloop success at %d\n",QUICK_LOOP_COUNT-count); */ printk(" %d ",QUICK_LOOP_COUNT-count); # endif goto data_immediately; } } # ifdef TEST4 /* printk("Quickloop ended at %d\n",QUICK_LOOP_COUNT); */ printk("ended "); # endif } break; } break; case MCD_S_STOP: #ifdef TEST3 printk("MCD_S_STOP\n"); #endif #ifdef WORK_AROUND_MITSUMI_BUG_93 if (!mitsumi_bug_93_wait) goto do_not_work_around_mitsumi_bug_93_1; McdTimeout = mitsumi_bug_93_wait; mcd_state = 9+3+1; break; case 9+3+1: if (McdTimeout) break; do_not_work_around_mitsumi_bug_93_1: #endif /* WORK_AROUND_MITSUMI_BUG_93 */ outb(MCMD_STOP, MCDPORT(0)); #ifdef WORK_AROUND_MITSUMI_BUG_92 if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS) { int i = 4096; do { inb(MCDPORT(0)); } while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS && --i); outb(MCMD_STOP, MCDPORT(0)); if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS) { i = 4096; do { inb(MCDPORT(0)); } while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS && --i); outb(MCMD_STOP, MCDPORT(0)); } } #endif /* WORK_AROUND_MITSUMI_BUG_92 */ mcd_state = MCD_S_STOPPING; McdTimeout = 1000; break; case MCD_S_STOPPING: #ifdef TEST3 printk("MCD_S_STOPPING\n"); #endif if ((st = mcdStatus()) == -1 && McdTimeout) break; if ((st != -1) && (st & MST_DSK_CHG)) { mcdDiskChanged = 1; tocUpToDate = 0; mcd_invalidate_buffers(); } #ifdef WORK_AROUND_MITSUMI_BUG_93 if (!mitsumi_bug_93_wait) goto do_not_work_around_mitsumi_bug_93_2; McdTimeout = mitsumi_bug_93_wait; mcd_state = 9+3+2; break; case 9+3+2: if (McdTimeout) break; st = -1; do_not_work_around_mitsumi_bug_93_2: #endif /* WORK_AROUND_MITSUMI_BUG_93 */ #ifdef TEST3 printk("CURRENT_VALID %d mcd_mode %d\n", CURRENT_VALID, mcd_mode); #endif if (CURRENT_VALID) { if (st != -1) { if (mcd_mode == 1) goto read_immediately; else goto set_mode_immediately; } else { mcd_state = MCD_S_START; McdTimeout = 1; } } else { mcd_state = MCD_S_IDLE; return; } break; default: printk("mcd: invalid state %d\n", mcd_state); return; } ret: if (!McdTimeout--) { printk("mcd: timeout in state %d\n", mcd_state); mcd_state = MCD_S_STOP; } SET_TIMER(mcd_poll, 1); }
__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; }
/* * On close, we flush all mcd blocks from the buffer cache. */ static void mcd_release(struct cdrom_device_info * cdi) { MOD_DEC_USE_COUNT; if (!--mcd_open_count) { mcd_invalidate_buffers(); } }
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; }