⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sjcd.c

📁 cdrom device drive for linux.
💻 C
📖 第 1 页 / 共 3 页
字号:
#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 + -