?? mcd.c
字號:
SET_TIMER(mcd_status, 1);
return;
}
if (st & MST_DSK_CHG)
{
mcdDiskChanged = 1;
}
if ((st & MST_READY) == 0)
{
printk("mcd: disk removed\n");
mcdDiskChanged = 1;
end_request(0);
do_mcd_request();
return;
}
outb(0x50, MCDPORT(0)); /* set mode */
outb(0x01, MCDPORT(0)); /* mode = cooked data */
McdTimeout = 100;
SET_TIMER(mcd_read_cmd, 1);
}
/*
* Check the result of the set-mode command. On success, send the
* read-data command.
*/
static void
mcd_read_cmd()
{
int st;
long block;
struct mcd_Play_msf mcdcmd;
McdTimeout--;
st = mcdStatus();
if (st & MST_DSK_CHG)
{
mcdDiskChanged = 1;
}
if (st == -1)
{
if (McdTimeout == 0)
{
printk("mcd: set mode timed out\n");
SET_TIMER(mcd_start, 1); /* wait a bit, try again */
return;
}
SET_TIMER(mcd_read_cmd, 1);
return;
}
mcd_bn = -1; /* purge our buffer */
block = CURRENT -> sector / 4;
hsg2msf(block, &mcdcmd.start); /* cvt to msf format */
mcdcmd.end.min = 0;
mcdcmd.end.sec = 0;
mcdcmd.end.frame = 1;
sendMcdCmd(MCMD_PLAY_READ, &mcdcmd); /* read command */
McdTimeout = 200;
SET_TIMER(mcd_data, 1);
}
/*
* Check the completion of the read-data command. On success, read
* the 2048 bytes of data from the disk into our buffer.
*/
static void
mcd_data()
{
int i;
McdTimeout--;
cli();
i =inb(MCDPORT(1)) & (MFL_STATUS | MFL_DATA);
if (i == MFL_DATA)
{
printk("mcd: read failed\n");
#ifdef MCD_DEBUG
printk("got 0xB %02X\n", inb(MCDPORT(0)) & 0xFF);
#endif
SET_TIMER(mcd_start, 1);
sti();
return;
}
if (i == (MFL_STATUS | MFL_DATA))
{
if (McdTimeout == 0)
{
printk("mcd: data timeout, retrying\n");
SET_TIMER(mcd_start, 1);
}
else
SET_TIMER(mcd_data, 1);
sti();
return;
}
CLEAR_TIMER;
READ_DATA(MCDPORT(0), &mcd_buf[0], 2048);
sti();
mcd_bn = CURRENT -> sector / 4;
mcd_transfer();
end_request(1);
SET_TIMER(do_mcd_request, 1);
}
/*
* Open the device special file. Check that a disk is in.
*/
int
mcd_open(struct inode *ip, struct file *fp)
{
int st;
if (mcdPresent == 0)
return -ENXIO; /* no hardware */
st = statusCmd(); /* check drive status */
if (st == -1)
return -EIO; /* drive doesn't respond */
if ((st & MST_READY) == 0) /* no disk in drive */
{
printk("mcd: no disk in drive\n");
return -EIO;
}
if (updateToc() < 0)
return -EIO;
return 0;
}
/*
* On close, we flush all mcd blocks from the buffer cache.
*/
static void
mcd_release(struct inode * inode, struct file * file)
{
mcd_bn = -1;
sync_dev(inode->i_rdev);
invalidate_buffers(inode -> i_rdev);
}
static struct file_operations mcd_fops = {
NULL, /* lseek - default */
block_read, /* read - general block-dev read */
block_write, /* write - general block-dev write */
NULL, /* readdir - bad */
NULL, /* select */
mcd_ioctl, /* ioctl */
NULL, /* mmap */
mcd_open, /* open */
mcd_release /* release */
};
/*
* MCD interrupt descriptor
*/
static struct sigaction mcd_sigaction = {
mcd_interrupt,
0,
SA_INTERRUPT,
NULL
};
/*
* Test for presence of drive and initialize it. Called at boot time.
*/
unsigned long
mcd_init(unsigned long mem_start, unsigned long mem_end)
{
int count;
unsigned char result[3];
if (register_blkdev(MAJOR_NR, "mcd", &mcd_fops) != 0)
{
printk("mcd: Unable to get major %d for Mitsumi CD-ROM\n",
MAJOR_NR);
return mem_start;
}
if (check_region(mcd_port, 4)) {
printk("mcd: Init failed, I/O port (%X) already in use\n",
mcd_port);
return mem_start;
}
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 < 1000000; count++)
(void) inb(MCDPORT(1)); /* delay a bit */
outb(0x40, MCDPORT(0)); /* send get-stat cmd */
for (count = 0; count < 1000000; count++)
if (!(inb(MCDPORT(1)) & MFL_STATUS))
break;
if (count >= 1000000) {
printk("mcd: Init failed. No mcd device at 0x%x irq %d\n",
mcd_port, mcd_irq);
return mem_start;
}
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("mcd: mitsumi get version failed at 0x%d\n",
mcd_port);
return mem_start;
}
if (result[0] == result[1] && result[1] == result[2])
return mem_start;
printk("mcd: Mitsumi version : %02X %c %x\n",
result[0],result[1],result[2]);
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 (irqaction(MCD_INTR_NR, &mcd_sigaction))
{
printk("mcd: Unable to get IRQ%d for Mitsumi CD-ROM\n", MCD_INTR_NR);
return mem_start;
}
snarf_region(mcd_port, 4);
mcdPresent = 1;
printk("mcd: Mitsumi CD-ROM Drive present at addr %x, irq %d\n",
mcd_port, mcd_irq);
return mem_start;
}
static void
hsg2msf(long hsg, struct msf *msf)
{
hsg += 150;
msf -> min = hsg / 4500;
hsg %= 4500;
msf -> sec = hsg / 75;
msf -> frame = hsg % 75;
bin2bcd(&msf -> min); /* convert to BCD */
bin2bcd(&msf -> sec);
bin2bcd(&msf -> frame);
}
static void
bin2bcd(unsigned char *p)
{
int u, t;
u = *p % 10;
t = *p / 10;
*p = u | (t << 4);
}
static int
bcd2bin(unsigned char bcd)
{
return (bcd >> 4) * 10 + (bcd & 0xF);
}
/*
* See if a status is ready from the drive and return it
* if it is ready.
*/
static int
mcdStatus(void)
{
int i;
int st;
st = inb(MCDPORT(1)) & MFL_STATUS;
if (!st)
{
i = inb(MCDPORT(0)) & 0xFF;
return i;
}
else
return -1;
}
/*
* Send a play or read command to the drive
*/
static void
sendMcdCmd(int cmd, struct mcd_Play_msf *params)
{
outb(cmd, MCDPORT(0));
outb(params -> start.min, MCDPORT(0));
outb(params -> start.sec, MCDPORT(0));
outb(params -> start.frame, MCDPORT(0));
outb(params -> end.min, MCDPORT(0));
outb(params -> end.sec, MCDPORT(0));
outb(params -> end.frame, MCDPORT(0));
}
/*
* Timer interrupt routine to test for status ready from the drive.
* (see the next routine)
*/
static void
mcdStatTimer(void)
{
if (!(inb(MCDPORT(1)) & MFL_STATUS))
{
wake_up(&mcd_waitq);
return;
}
McdTimeout--;
if (McdTimeout <= 0)
{
wake_up(&mcd_waitq);
return;
}
SET_TIMER(mcdStatTimer, 1);
}
/*
* Wait for a status to be returned from the drive. The actual test
* (see routine above) is done by the timer interrupt to avoid
* excessive rescheduling.
*/
static int
getMcdStatus(int timeout)
{
int st;
McdTimeout = timeout;
SET_TIMER(mcdStatTimer, 1);
sleep_on(&mcd_waitq);
if (McdTimeout <= 0)
return -1;
st = inb(MCDPORT(0)) & 0xFF;
if (st == 0xFF)
return -1;
if ((st & MST_BUSY) == 0 && audioStatus == CDROM_AUDIO_PLAY)
/* XXX might be an error? look at q-channel? */
audioStatus = CDROM_AUDIO_COMPLETED;
if (st & MST_DSK_CHG)
{
mcdDiskChanged = 1;
tocUpToDate = 0;
audioStatus = CDROM_AUDIO_NO_STATUS;
}
return st;
}
/*
* Read a value from the drive. Should return quickly, so a busy wait
* is used to avoid excessive rescheduling.
*/
static int
getValue(unsigned char *result)
{
int count;
int s;
for (count = 0; count < 2000; count++)
if (!(inb(MCDPORT(1)) & MFL_STATUS))
break;
if (count >= 2000)
{
printk("mcd: getValue timeout\n");
return -1;
}
s = inb(MCDPORT(0)) & 0xFF;
*result = (unsigned char) s;
return 0;
}
/*
* Read the current Q-channel info. Also used for reading the
* table of contents.
*/
int
GetQChannelInfo(struct mcd_Toc *qp)
{
unsigned char notUsed;
int retry;
for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
{
outb(MCMD_GET_Q_CHANNEL, MCDPORT(0));
if (getMcdStatus(MCD_STATUS_DELAY) != -1)
break;
}
if (retry >= MCD_RETRY_ATTEMPTS)
return -1;
if (getValue(&qp -> ctrl_addr) < 0) return -1;
if (getValue(&qp -> track) < 0) return -1;
if (getValue(&qp -> pointIndex) < 0) return -1;
if (getValue(&qp -> trackTime.min) < 0) return -1;
if (getValue(&qp -> trackTime.sec) < 0) return -1;
if (getValue(&qp -> trackTime.frame) < 0) return -1;
if (getValue(¬Used) < 0) return -1;
if (getValue(&qp -> diskTime.min) < 0) return -1;
if (getValue(&qp -> diskTime.sec) < 0) return -1;
if (getValue(&qp -> diskTime.frame) < 0) return -1;
return 0;
}
/*
* Read the table of contents (TOC) and TOC header if neccessary
*/
static int
updateToc()
{
if (tocUpToDate)
return 0;
if (GetDiskInfo() < 0)
return -EIO;
if (GetToc() < 0)
return -EIO;
tocUpToDate = 1;
return 0;
}
/*
* Read the table of contents header
*/
static int
GetDiskInfo()
{
int retry;
for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
{
outb(MCMD_GET_DISK_INFO, MCDPORT(0));
if (getMcdStatus(MCD_STATUS_DELAY) != -1)
break;
}
if (retry >= MCD_RETRY_ATTEMPTS)
return -1;
if (getValue(&DiskInfo.first) < 0) return -1;
if (getValue(&DiskInfo.last) < 0) return -1;
DiskInfo.first = bcd2bin(DiskInfo.first);
DiskInfo.last = bcd2bin(DiskInfo.last);
if (getValue(&DiskInfo.diskLength.min) < 0) return -1;
if (getValue(&DiskInfo.diskLength.sec) < 0) return -1;
if (getValue(&DiskInfo.diskLength.frame) < 0) return -1;
if (getValue(&DiskInfo.firstTrack.min) < 0) return -1;
if (getValue(&DiskInfo.firstTrack.sec) < 0) return -1;
if (getValue(&DiskInfo.firstTrack.frame) < 0) return -1;
#ifdef MCD_DEBUG
printk("Disk Info: first %d last %d length %02x:%02x.%02x first %02x:%02x.%02x\n",
DiskInfo.first,
DiskInfo.last,
DiskInfo.diskLength.min,
DiskInfo.diskLength.sec,
DiskInfo.diskLength.frame,
DiskInfo.firstTrack.min,
DiskInfo.firstTrack.sec,
DiskInfo.firstTrack.frame);
#endif
return 0;
}
/*
* Read the table of contents (TOC)
*/
static int
GetToc()
{
int i, px;
int limit;
int retry;
struct mcd_Toc qInfo;
for (i = 0; i < MAX_TRACKS; i++)
Toc[i].pointIndex = 0;
i = DiskInfo.last + 3;
for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
{
outb(MCMD_STOP, MCDPORT(0));
if (getMcdStatus(MCD_STATUS_DELAY) != -1)
break;
}
if (retry >= MCD_RETRY_ATTEMPTS)
return -1;
for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
{
outb(MCMD_SET_MODE, MCDPORT(0));
outb(0x05, MCDPORT(0)); /* mode: toc */
if (getMcdStatus(MCD_STATUS_DELAY) != -1)
break;
}
if (retry >= MCD_RETRY_ATTEMPTS)
return -1;
for (limit = 300; limit > 0; limit--)
{
if (GetQChannelInfo(&qInfo) < 0)
break;
px = bcd2bin(qInfo.pointIndex);
if (px > 0 && px < MAX_TRACKS && qInfo.track == 0)
if (Toc[px].pointIndex == 0)
{
Toc[px] = qInfo;
i--;
}
if (i <= 0)
break;
}
Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength;
for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
{
outb(MCMD_SET_MODE, MCDPORT(0));
outb(0x01, MCDPORT(0));
if (getMcdStatus(MCD_STATUS_DELAY) != -1)
break;
}
#ifdef MCD_DEBUG
for (i = 1; i <= DiskInfo.last; i++)
printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X %02X:%02X.%02X\n",
i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame,
Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);
for (i = 100; i < 103; i++)
printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X %02X:%02X.%02X\n",
i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame,
Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);
#endif
return limit > 0 ? 0 : -1;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -