📄 sjcd.c
字号:
#endif
sjcd_transfer_state =
SJCD_S_STOP;
goto ReSwitch;
}
if (sjcd_mode != SCMD_MODE_COOKED) {
#if defined( SJCD_TRACE )
printk
("SJCD_S_READ: mode failed: goto to SJCD_S_STOP mode\n");
#endif
sjcd_transfer_state =
SJCD_S_STOP;
goto ReSwitch;
}
}
if (CURRENT_IS_VALID) {
struct sjcd_play_msf msf;
sjcd_next_bn = CURRENT->sector / 4;
hsg2msf(sjcd_next_bn, &msf.start);
msf.end.min = 0;
msf.end.sec = 0;
msf.end.frame = sjcd_read_count =
SJCD_BUF_SIZ;
#if defined( SJCD_TRACE )
printk
("SJCD: ---reading msf-address %x:%x:%x %x:%x:%x\n",
msf.start.min, msf.start.sec,
msf.start.frame, msf.end.min,
msf.end.sec, msf.end.frame);
printk
("sjcd_next_bn:%x buf_in:%x buf_out:%x buf_bn:%x\n",
sjcd_next_bn, sjcd_buf_in,
sjcd_buf_out,
sjcd_buf_bn[sjcd_buf_in]);
#endif
sjcd_send_6_cmd(SCMD_DATA_READ,
&msf);
sjcd_transfer_state = SJCD_S_DATA;
sjcd_transfer_timeout = 500;
#if defined( SJCD_TRACE )
printk
("SJCD_S_READ: go to SJCD_S_DATA mode\n");
#endif
} else {
#if defined( SJCD_TRACE )
printk
("SJCD_S_READ: nothing to read: go to SJCD_S_STOP mode\n");
#endif
sjcd_transfer_state = SJCD_S_STOP;
goto ReSwitch;
}
}
#if defined( SJCD_GATHER_STAT )
else
statistic.read_ticks++;
#endif
break;
}
case SJCD_S_DATA:{
unsigned char stat;
sjcd_s_data:stat =
inb(SJCDPORT
(1));
#if defined( SJCD_TRACE )
printk("SJCD_S_DATA: status = 0x%02x\n", stat);
#endif
if (SJCD_STATUS_AVAILABLE(stat)) {
/*
* No data is waiting for us in the drive buffer. Status of operation
* completion is available. Read and parse it.
*/
sjcd_load_status();
if (!sjcd_status_valid
|| sjcd_command_failed) {
#if defined( SJCD_TRACE )
printk
("SJCD: read block %d failed, maybe audio disk? Giving up\n",
sjcd_next_bn);
#endif
if (CURRENT_IS_VALID)
end_request(0);
#if defined( SJCD_TRACE )
printk
("SJCD_S_DATA: pre-cmd failed: go to SJCD_S_STOP mode\n");
#endif
sjcd_transfer_state = SJCD_S_STOP;
goto ReSwitch;
}
if (!sjcd_media_is_available) {
printk
("SJCD_S_DATA: no disk: go to SJCD_S_STOP mode\n");
sjcd_transfer_state = SJCD_S_STOP;
goto ReSwitch;
}
sjcd_transfer_state = SJCD_S_READ;
goto ReSwitch;
} else if (SJCD_DATA_AVAILABLE(stat)) {
/*
* One frame is read into device buffer. We must copy it to our memory.
* Otherwise cdrom hangs up. Check to see if we have something to copy
* to.
*/
if (!CURRENT_IS_VALID
&& sjcd_buf_in == sjcd_buf_out) {
#if defined( SJCD_TRACE )
printk
("SJCD_S_DATA: nothing to read: go to SJCD_S_STOP mode\n");
printk
(" ... all the date would be discarded\n");
#endif
sjcd_transfer_state = SJCD_S_STOP;
goto ReSwitch;
}
/*
* Everything seems to be OK. Just read the frame and recalculate
* indices.
*/
sjcd_buf_bn[sjcd_buf_in] = -1; /* ??? */
insb(SJCDPORT(2),
sjcd_buf + 2048 * sjcd_buf_in, 2048);
#if defined( SJCD_TRACE )
printk
("SJCD_S_DATA: next_bn=%d, buf_in=%d, buf_out=%d, buf_bn=%d\n",
sjcd_next_bn, sjcd_buf_in,
sjcd_buf_out,
sjcd_buf_bn[sjcd_buf_in]);
#endif
sjcd_buf_bn[sjcd_buf_in] = sjcd_next_bn++;
if (sjcd_buf_out == -1)
sjcd_buf_out = sjcd_buf_in;
if (++sjcd_buf_in == SJCD_BUF_SIZ)
sjcd_buf_in = 0;
/*
* Only one frame is ready at time. So we should turn over to wait for
* another frame. If we need that, of course.
*/
if (--sjcd_read_count == 0) {
/*
* OK, request seems to be precessed. Continue transferring...
*/
if (!sjcd_transfer_is_active) {
while (CURRENT_IS_VALID) {
/*
* Continue transferring.
*/
sjcd_transfer();
if (CURRENT->
nr_sectors ==
0)
end_request
(1);
else
break;
}
}
if (CURRENT_IS_VALID &&
(CURRENT->sector / 4 <
sjcd_next_bn
|| CURRENT->sector / 4 >
sjcd_next_bn +
SJCD_BUF_SIZ)) {
#if defined( SJCD_TRACE )
printk
("SJCD_S_DATA: can't read: go to SJCD_S_STOP mode\n");
#endif
sjcd_transfer_state =
SJCD_S_STOP;
goto ReSwitch;
}
}
/*
* Now we should turn around rather than wait for while.
*/
goto sjcd_s_data;
}
#if defined( SJCD_GATHER_STAT )
else
statistic.data_ticks++;
#endif
break;
}
case SJCD_S_STOP:{
sjcd_read_count = 0;
sjcd_send_cmd(SCMD_STOP);
sjcd_transfer_state = SJCD_S_STOPPING;
sjcd_transfer_timeout = 500;
#if defined( SJCD_GATHER_STAT )
statistic.stop_ticks++;
#endif
break;
}
case SJCD_S_STOPPING:{
unsigned char stat;
stat = inb(SJCDPORT(1));
#if defined( SJCD_TRACE )
printk("SJCD_S_STOP: status = 0x%02x\n", stat);
#endif
if (SJCD_DATA_AVAILABLE(stat)) {
int i;
#if defined( SJCD_TRACE )
printk("SJCD_S_STOP: discard data\n");
#endif
/*
* Discard all the data from the pipe. Foolish method.
*/
for (i = 2048; i--;
(void) inb(SJCDPORT(2)));
sjcd_transfer_timeout = 500;
} else if (SJCD_STATUS_AVAILABLE(stat)) {
sjcd_load_status();
if (sjcd_status_valid
&& sjcd_media_is_changed) {
sjcd_toc_uptodate = 0;
sjcd_invalidate_buffers();
}
if (CURRENT_IS_VALID) {
if (sjcd_status_valid)
sjcd_transfer_state =
SJCD_S_READ;
else
sjcd_transfer_state =
SJCD_S_START;
} else
sjcd_transfer_state = SJCD_S_IDLE;
goto ReSwitch;
}
#if defined( SJCD_GATHER_STAT )
else
statistic.stopping_ticks++;
#endif
break;
}
default:
printk("SJCD: poll: invalid state %d\n",
sjcd_transfer_state);
return;
}
if (--sjcd_transfer_timeout == 0) {
printk("SJCD: timeout in state %d\n", sjcd_transfer_state);
while (CURRENT_IS_VALID)
end_request(0);
sjcd_send_cmd(SCMD_STOP);
sjcd_transfer_state = SJCD_S_IDLE;
goto ReSwitch;
}
/*
* Get back in some time. 1 should be replaced with count variable to
* avoid unnecessary testings.
*/
SJCD_SET_TIMER(sjcd_poll, 1);
}
static void do_sjcd_request(request_queue_t * q)
{
#if defined( SJCD_TRACE )
printk("SJCD: do_sjcd_request(%ld+%ld)\n",
CURRENT->sector, CURRENT->nr_sectors);
#endif
sjcd_transfer_is_active = 1;
while (CURRENT_IS_VALID) {
/*
* Who of us are paranoiac?
*/
if (CURRENT->bh && !buffer_locked(CURRENT->bh))
panic(DEVICE_NAME ": block not locked");
sjcd_transfer();
if (CURRENT->nr_sectors == 0)
end_request(1);
else {
sjcd_buf_out = -1; /* Want to read a block not in buffer */
if (sjcd_transfer_state == SJCD_S_IDLE) {
if (!sjcd_toc_uptodate) {
if (sjcd_update_toc() < 0) {
printk
("SJCD: transfer: discard\n");
while (CURRENT_IS_VALID)
end_request(0);
break;
}
}
sjcd_transfer_state = SJCD_S_START;
SJCD_SET_TIMER(sjcd_poll, HZ / 100);
}
break;
}
}
sjcd_transfer_is_active = 0;
#if defined( SJCD_TRACE )
printk
("sjcd_next_bn:%x sjcd_buf_in:%x sjcd_buf_out:%x sjcd_buf_bn:%x\n",
sjcd_next_bn, sjcd_buf_in, sjcd_buf_out,
sjcd_buf_bn[sjcd_buf_in]);
printk("do_sjcd_request ends\n");
#endif
}
/*
* Open the device special file. Check disk is in.
*/
int sjcd_open(struct inode *ip, struct file *fp)
{
/*
* Check the presence of device.
*/
if (!sjcd_present)
return (-ENXIO);
/*
* Only read operations are allowed. Really? (:-)
*/
if (fp->f_mode & 2)
return (-EROFS);
if (sjcd_open_count == 0) {
int s, sjcd_open_tries;
/* We don't know that, do we? */
/*
sjcd_audio_status = CDROM_AUDIO_NO_STATUS;
*/
sjcd_mode = 0;
sjcd_door_was_open = 0;
sjcd_transfer_state = SJCD_S_IDLE;
sjcd_invalidate_buffers();
sjcd_status_valid = 0;
/*
* Strict status checking.
*/
for (sjcd_open_tries = 4; --sjcd_open_tries;) {
if (!sjcd_status_valid)
sjcd_get_status();
if (!sjcd_status_valid) {
#if defined( SJCD_DIAGNOSTIC )
printk
("SJCD: open: timed out when check status.\n");
#endif
goto err_out;
} else if (!sjcd_media_is_available) {
#if defined( SJCD_DIAGNOSTIC )
printk("SJCD: open: no disk in drive\n");
#endif
if (!sjcd_door_closed) {
sjcd_door_was_open = 1;
#if defined( SJCD_TRACE )
printk
("SJCD: open: close the tray\n");
#endif
s = sjcd_tray_close();
if (s < 0 || !sjcd_status_valid
|| sjcd_command_failed) {
#if defined( SJCD_DIAGNOSTIC )
printk
("SJCD: open: tray close attempt failed\n");
#endif
goto err_out;
}
continue;
} else
goto err_out;
}
break;
}
s = sjcd_tray_lock();
if (s < 0 || !sjcd_status_valid || sjcd_command_failed) {
#if defined( SJCD_DIAGNOSTIC )
printk("SJCD: open: tray lock attempt failed\n");
#endif
goto err_out;
}
#if defined( SJCD_TRACE )
printk("SJCD: open: done\n");
#endif
}
++sjcd_open_count;
return (0);
err_out:
return (-EIO);
}
/*
* On close, we flush all sjcd blocks from the buffer cache.
*/
static int sjcd_release(struct inode *inode, struct file *file)
{
int s;
#if defined( SJCD_TRACE )
printk("SJCD: release\n");
#endif
if (--sjcd_open_count == 0) {
sjcd_invalidate_buffers();
s = sjcd_tray_unlock();
if (s < 0 || !sjcd_status_valid || sjcd_command_failed) {
#if defined( SJCD_DIAGNOSTIC )
printk
("SJCD: release: tray unlock attempt failed.\n");
#endif
}
if (sjcd_door_was_open) {
s = sjcd_tray_open();
if (s < 0 || !sjcd_status_valid
|| sjcd_command_failed) {
#if defined( SJCD_DIAGNOSTIC )
printk
("SJCD: release: tray unload attempt failed.\n");
#endif
}
}
}
return 0;
}
/*
* A list of file operations allowed for this cdrom.
*/
static struct block_device_operations sjcd_fops = {
owner:THIS_MODULE,
open:sjcd_open,
release:sjcd_release,
ioctl:sjcd_ioctl,
check_media_change:sjcd_disk_change,
};
static int blksize = 2048;
static int secsize = 2048;
/*
* Following stuff is intended for initialization of the cdrom. It
* first looks for presence of device. If the device is present, it
* will be reset. Then read the version of the drive and load status.
* The version is two BCD-coded bytes.
*/
static struct {
unsigned char major, minor;
} sjcd_version;
/*
* Test for presence of drive and initialize it. Called at boot time.
* Probe cdrom, find out version and status.
*/
int __init sjcd_init(void)
{
int i;
printk(KERN_INFO
"SJCD: Sanyo CDR-H94A cdrom driver version %d.%d.\n",
SJCD_VERSION_MAJOR, SJCD_VERSION_MINOR);
#if defined( SJCD_TRACE )
printk("SJCD: sjcd=0x%x: ", sjcd_base);
#endif
hardsect_size[MAJOR_NR] = &secsize;
blksize_size[MAJOR_NR] = &blksize;
if (devfs_register_blkdev(MAJOR_NR, "sjcd", &sjcd_fops) != 0) {
printk("SJCD: Unable to get major %d for Sanyo CD-ROM\n",
MAJOR_NR);
return (-EIO);
}
blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
read_ahead[MAJOR_NR] = 4;
register_disk(NULL, MKDEV(MAJOR_NR, 0), 1, &sjcd_fops, 0);
if (check_region(sjcd_base, 4)) {
printk
("SJCD: Init failed, I/O port (%X) is already in use\n",
sjcd_base);
sjcd_cleanup();
return (-EIO);
}
/*
* Check for card. Since we are booting now, we can't use standard
* wait algorithm.
*/
printk(KERN_INFO "SJCD: Resetting: ");
sjcd_send_cmd(SCMD_RESET);
for (i = 1000; i > 0 && !sjcd_status_valid; --i) {
unsigned long timer;
/*
* Wait 10ms approx.
*/
for (timer = jiffies; time_before_eq(jiffies, timer););
if ((i % 100) == 0)
printk(".");
(void) sjcd_check_status();
}
if (i == 0 || sjcd_command_failed) {
printk(" reset failed, no drive found.\n");
sjcd_cleanup();
return (-EIO);
} else
printk("\n");
/*
* Get and print out cdrom version.
*/
printk(KERN_INFO "SJCD: Getting version: ");
sjcd_send_cmd(SCMD_GET_VERSION);
for (i = 1000; i > 0 && !sjcd_status_valid; --i) {
unsigned long timer;
/*
* Wait 10ms approx.
*/
for (timer = jiffies; time_before_eq(jiffies, timer););
if ((i % 100) == 0)
printk(".");
(void) sjcd_check_status();
}
if (i == 0 || sjcd_command_failed) {
printk(" get version failed, no drive found.\n");
sjcd_cleanup();
return (-EIO);
}
if (sjcd_load_response(&sjcd_version, sizeof(sjcd_version)) == 0) {
printk(" %1x.%02x\n", (int) sjcd_version.major,
(int) sjcd_version.minor);
} else {
printk(" read version failed, no drive found.\n");
sjcd_cleanup();
return (-EIO);
}
/*
* Check and print out the tray state. (if it is needed?).
*/
if (!sjcd_status_valid) {
printk(KERN_INFO "SJCD: Getting status: ");
sjcd_send_cmd(SCMD_GET_STATUS);
for (i = 1000; i > 0 && !sjcd_status_valid; --i) {
unsigned long timer;
/*
* Wait 10ms approx.
*/
for (timer = jiffies;
time_before_eq(jiffies, timer););
if ((i % 100) == 0)
printk(".");
(void) sjcd_check_status();
}
if (i == 0 || sjcd_command_failed) {
printk(" get status failed, no drive found.\n");
sjcd_cleanup();
return (-EIO);
} else
printk("\n");
}
printk(KERN_INFO "SJCD: Status: port=0x%x.\n", sjcd_base);
devfs_register(NULL, "sjcd", DEVFS_FL_DEFAULT, MAJOR_NR, 0,
S_IFBLK | S_IRUGO | S_IWUGO, &sjcd_fops, NULL);
sjcd_present++;
return (0);
}
static int sjcd_cleanup(void)
{
if ((devfs_unregister_blkdev(MAJOR_NR, "sjcd") == -EINVAL))
printk("SJCD: cannot unregister device.\n");
else {
release_region(sjcd_base, 4);
blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
}
return (0);
}
void __exit sjcd_exit(void)
{
devfs_unregister(devfs_find_handle
(NULL, "sjcd", 0, 0, DEVFS_SPECIAL_BLK, 0));
if (sjcd_cleanup())
printk("SJCD: module: cannot be removed.\n");
else
printk(KERN_INFO "SJCD: module: removed.\n");
}
#ifdef MODULE
module_init(sjcd_init);
#endif
module_exit(sjcd_exit);
MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -