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

📄 pktcdvd.c

📁 Linux块设备驱动源码
💻 C
📖 第 1 页 / 共 5 页
字号:
		printk("pktcdvd: Can't write to last track (reserved)\n");		return 1;	}	return 0;}static int pkt_probe_settings(struct pktcdvd_device *pd){	struct packet_command cgc;	unsigned char buf[12];	disc_information di;	track_information ti;	int ret, track;	init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ);	cgc.cmd[0] = GPCMD_GET_CONFIGURATION;	cgc.cmd[8] = 8;	ret = pkt_generic_packet(pd, &cgc);	pd->mmc3_profile = ret ? 0xffff : buf[6] << 8 | buf[7];	memset(&di, 0, sizeof(disc_information));	memset(&ti, 0, sizeof(track_information));	if ((ret = pkt_get_disc_info(pd, &di))) {		printk("failed get_disc\n");		return ret;	}	if (pkt_good_disc(pd, &di))		return -ENXIO;	switch (pd->mmc3_profile) {		case 0x1a: /* DVD+RW */			printk("pktcdvd: inserted media is DVD+RW\n");			break;		case 0x13: /* DVD-RW */			printk("pktcdvd: inserted media is DVD-RW\n");			break;		case 0x12: /* DVD-RAM */			printk("pktcdvd: inserted media is DVD-RAM\n");			break;		default:			printk("pktcdvd: inserted media is CD-R%s\n", di.erasable ? "W" : "");			break;	}	pd->type = di.erasable ? PACKET_CDRW : PACKET_CDR;	track = 1; /* (di.last_track_msb << 8) | di.last_track_lsb; */	if ((ret = pkt_get_track_info(pd, track, 1, &ti))) {		printk("pktcdvd: failed get_track\n");		return ret;	}	if (pkt_good_track(&ti)) {		printk("pktcdvd: can't write to this track\n");		return -ENXIO;	}	/*	 * we keep packet size in 512 byte units, makes it easier to	 * deal with request calculations.	 */	pd->settings.size = be32_to_cpu(ti.fixed_packet_size) << 2;	if (pd->settings.size == 0) {		printk("pktcdvd: detected zero packet size!\n");		pd->settings.size = 128;	}	if (pd->settings.size > PACKET_MAX_SECTORS) {		printk("pktcdvd: packet size is too big\n");		return -ENXIO;	}	pd->settings.fp = ti.fp;	pd->offset = (be32_to_cpu(ti.track_start) << 2) & (pd->settings.size - 1);	if (ti.nwa_v) {		pd->nwa = be32_to_cpu(ti.next_writable);		set_bit(PACKET_NWA_VALID, &pd->flags);	}	/*	 * in theory we could use lra on -RW media as well and just zero	 * blocks that haven't been written yet, but in practice that	 * is just a no-go. we'll use that for -R, naturally.	 */	if (ti.lra_v) {		pd->lra = be32_to_cpu(ti.last_rec_address);		set_bit(PACKET_LRA_VALID, &pd->flags);	} else {		pd->lra = 0xffffffff;		set_bit(PACKET_LRA_VALID, &pd->flags);	}	/*	 * fine for now	 */	pd->settings.link_loss = 7;	pd->settings.write_type = 0;	/* packet */	pd->settings.track_mode = ti.track_mode;	/*	 * mode1 or mode2 disc	 */	switch (ti.data_mode) {		case PACKET_MODE1:			pd->settings.block_mode = PACKET_BLOCK_MODE1;			break;		case PACKET_MODE2:			pd->settings.block_mode = PACKET_BLOCK_MODE2;			break;		default:			printk("pktcdvd: unknown data mode\n");			return 1;	}	return 0;}/* * enable/disable write caching on drive */static int pkt_write_caching(struct pktcdvd_device *pd, int set){	struct packet_command cgc;	struct request_sense sense;	unsigned char buf[64];	int ret;	memset(buf, 0, sizeof(buf));	init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ);	cgc.sense = &sense;	cgc.buflen = pd->mode_offset + 12;	/*	 * caching mode page might not be there, so quiet this command	 */	cgc.quiet = 1;	if ((ret = pkt_mode_sense(pd, &cgc, GPMODE_WCACHING_PAGE, 0)))		return ret;	buf[pd->mode_offset + 10] |= (!!set << 2);	cgc.buflen = cgc.cmd[8] = 2 + ((buf[0] << 8) | (buf[1] & 0xff));	ret = pkt_mode_select(pd, &cgc);	if (ret) {		printk("pktcdvd: write caching control failed\n");		pkt_dump_sense(&cgc);	} else if (!ret && set)		printk("pktcdvd: enabled write caching on %s\n", pd->name);	return ret;}static int pkt_lock_door(struct pktcdvd_device *pd, int lockflag){	struct packet_command cgc;	init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);	cgc.cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;	cgc.cmd[4] = lockflag ? 1 : 0;	return pkt_generic_packet(pd, &cgc);}/* * Returns drive maximum write speed */static int pkt_get_max_speed(struct pktcdvd_device *pd, unsigned *write_speed){	struct packet_command cgc;	struct request_sense sense;	unsigned char buf[256+18];	unsigned char *cap_buf;	int ret, offset;	memset(buf, 0, sizeof(buf));	cap_buf = &buf[sizeof(struct mode_page_header) + pd->mode_offset];	init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_UNKNOWN);	cgc.sense = &sense;	ret = pkt_mode_sense(pd, &cgc, GPMODE_CAPABILITIES_PAGE, 0);	if (ret) {		cgc.buflen = pd->mode_offset + cap_buf[1] + 2 +			     sizeof(struct mode_page_header);		ret = pkt_mode_sense(pd, &cgc, GPMODE_CAPABILITIES_PAGE, 0);		if (ret) {			pkt_dump_sense(&cgc);			return ret;		}	}	offset = 20;			    /* Obsoleted field, used by older drives */	if (cap_buf[1] >= 28)		offset = 28;		    /* Current write speed selected */	if (cap_buf[1] >= 30) {		/* If the drive reports at least one "Logical Unit Write		 * Speed Performance Descriptor Block", use the information		 * in the first block. (contains the highest speed)		 */		int num_spdb = (cap_buf[30] << 8) + cap_buf[31];		if (num_spdb > 0)			offset = 34;	}	*write_speed = (cap_buf[offset] << 8) | cap_buf[offset + 1];	return 0;}/* These tables from cdrecord - I don't have orange book *//* standard speed CD-RW (1-4x) */static char clv_to_speed[16] = {	/* 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 */	   0, 2, 4, 6, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};/* high speed CD-RW (-10x) */static char hs_clv_to_speed[16] = {	/* 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 */	   0, 2, 4, 6, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};/* ultra high speed CD-RW */static char us_clv_to_speed[16] = {	/* 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 */	   0, 2, 4, 8, 0, 0,16, 0,24,32,40,48, 0, 0, 0, 0};/* * reads the maximum media speed from ATIP */static int pkt_media_speed(struct pktcdvd_device *pd, unsigned *speed){	struct packet_command cgc;	struct request_sense sense;	unsigned char buf[64];	unsigned int size, st, sp;	int ret;	init_cdrom_command(&cgc, buf, 2, CGC_DATA_READ);	cgc.sense = &sense;	cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP;	cgc.cmd[1] = 2;	cgc.cmd[2] = 4; /* READ ATIP */	cgc.cmd[8] = 2;	ret = pkt_generic_packet(pd, &cgc);	if (ret) {		pkt_dump_sense(&cgc);		return ret;	}	size = ((unsigned int) buf[0]<<8) + buf[1] + 2;	if (size > sizeof(buf))		size = sizeof(buf);	init_cdrom_command(&cgc, buf, size, CGC_DATA_READ);	cgc.sense = &sense;	cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP;	cgc.cmd[1] = 2;	cgc.cmd[2] = 4;	cgc.cmd[8] = size;	ret = pkt_generic_packet(pd, &cgc);	if (ret) {		pkt_dump_sense(&cgc);		return ret;	}	if (!buf[6] & 0x40) {		printk("pktcdvd: Disc type is not CD-RW\n");		return 1;	}	if (!buf[6] & 0x4) {		printk("pktcdvd: A1 values on media are not valid, maybe not CDRW?\n");		return 1;	}	st = (buf[6] >> 3) & 0x7; /* disc sub-type */	sp = buf[16] & 0xf; /* max speed from ATIP A1 field */	/* Info from cdrecord */	switch (st) {		case 0: /* standard speed */			*speed = clv_to_speed[sp];			break;		case 1: /* high speed */			*speed = hs_clv_to_speed[sp];			break;		case 2: /* ultra high speed */			*speed = us_clv_to_speed[sp];			break;		default:			printk("pktcdvd: Unknown disc sub-type %d\n",st);			return 1;	}	if (*speed) {		printk("pktcdvd: Max. media speed: %d\n",*speed);		return 0;	} else {		printk("pktcdvd: Unknown speed %d for sub-type %d\n",sp,st);		return 1;	}}static int pkt_perform_opc(struct pktcdvd_device *pd){	struct packet_command cgc;	struct request_sense sense;	int ret;	VPRINTK("pktcdvd: Performing OPC\n");	init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);	cgc.sense = &sense;	cgc.timeout = 60*HZ;	cgc.cmd[0] = GPCMD_SEND_OPC;	cgc.cmd[1] = 1;	if ((ret = pkt_generic_packet(pd, &cgc)))		pkt_dump_sense(&cgc);	return ret;}static int pkt_open_write(struct pktcdvd_device *pd){	int ret;	unsigned int write_speed, media_write_speed, read_speed;	if ((ret = pkt_probe_settings(pd))) {		DPRINTK("pktcdvd: %s failed probe\n", pd->name);		return -EIO;	}	if ((ret = pkt_set_write_settings(pd))) {		DPRINTK("pktcdvd: %s failed saving write settings\n", pd->name);		return -EIO;	}	pkt_write_caching(pd, USE_WCACHING);	if ((ret = pkt_get_max_speed(pd, &write_speed)))		write_speed = 16 * 177;	switch (pd->mmc3_profile) {		case 0x13: /* DVD-RW */		case 0x1a: /* DVD+RW */		case 0x12: /* DVD-RAM */			DPRINTK("pktcdvd: write speed %ukB/s\n", write_speed);			break;		default:			if ((ret = pkt_media_speed(pd, &media_write_speed)))				media_write_speed = 16;			write_speed = min(write_speed, media_write_speed * 177);			DPRINTK("pktcdvd: write speed %ux\n", write_speed / 176);			break;	}	read_speed = write_speed;	if ((ret = pkt_set_speed(pd, write_speed, read_speed))) {		DPRINTK("pktcdvd: %s couldn't set write speed\n", pd->name);		return -EIO;	}	pd->write_speed = write_speed;	pd->read_speed = read_speed;	if ((ret = pkt_perform_opc(pd))) {		DPRINTK("pktcdvd: %s Optimum Power Calibration failed\n", pd->name);	}	return 0;}/* * called at open time. */static int pkt_open_dev(struct pktcdvd_device *pd, int write){	int ret;	long lba;	request_queue_t *q;	/*	 * We need to re-open the cdrom device without O_NONBLOCK to be able	 * to read/write from/to it. It is already opened in O_NONBLOCK mode	 * so bdget() can't fail.	 */	bdget(pd->bdev->bd_dev);	if ((ret = blkdev_get(pd->bdev, FMODE_READ, O_RDONLY)))		goto out;	if ((ret = pkt_get_last_written(pd, &lba))) {		printk("pktcdvd: pkt_get_last_written failed\n");		goto out_putdev;	}	set_capacity(pd->disk, lba << 2);	set_capacity(pd->bdev->bd_disk, lba << 2);	bd_set_size(pd->bdev, (loff_t)lba << 11);	q = bdev_get_queue(pd->bdev);	if (write) {		if ((ret = pkt_open_write(pd)))			goto out_putdev;		/*		 * Some CDRW drives can not handle writes larger than one packet,		 * even if the size is a multiple of the packet size.		 */		spin_lock_irq(q->queue_lock);		blk_queue_max_sectors(q, pd->settings.size);		spin_unlock_irq(q->queue_lock);		set_bit(PACKET_WRITABLE, &pd->flags);	} else {		pkt_set_speed(pd, MAX_SPEED, MAX_SPEED);		clear_bit(PACKET_WRITABLE, &pd->flags);	}	if ((ret = pkt_set_segment_merging(pd, q)))		goto out_putdev;	if (write)		printk("pktcdvd: %lukB available on disc\n", lba << 1);	return 0;out_putdev:	blkdev_put(pd->bdev);out:	return ret;}/* * called when the device is closed. makes sure that the device flushes * the internal cache before we close. */static void pkt_release_dev(struct pktcdvd_device *pd, int flush){	if (flush && pkt_flush_cache(pd))		DPRINTK("pktcdvd: %s not flushing cache\n", pd->name);	pkt_lock_door(pd, 0);	pkt_set_speed(pd, MAX_SPEED, MAX_SPEED);	blkdev_put(pd->bdev);}static struct pktcdvd_device *pkt_find_dev_from_minor(int dev_minor){	if (dev_minor >= MAX_WRITERS)		return NULL;	return pkt_devs[dev_minor];}static int pkt_open(struct inode *inode, struct file *file){	struct pktcdvd_device *pd = NULL;	int ret;	VPRINTK("pktcdvd: entering open\n");	down(&ctl_mutex);	pd = pkt_find_dev_from_minor(iminor(inode));	if (!pd) {		ret = -ENODEV;		goto out;	}	BUG_ON(pd->refcnt < 0);	pd->refcnt++;	if (pd->refcnt > 1) {		if ((file->f_mode & FMODE_WRITE) &&		    !test_bit(PACKET_WRITABLE, &pd->flags)) {			ret = -EBUSY;			goto out_dec;		}	} else {		if (pkt_open_dev(pd, file->f_mode & FMODE_WRITE)) {			ret = -EIO;			goto out_dec;		}		/*		 * needed here as well, since ext2 (among others) may change		 * the blocksize at mount time		 */		set_blocksize(inode->i_bdev, CD_FRAMESIZE);	}	up(&ctl_mutex);	return 0;out_dec:	pd->refcnt--;out:	VPRINTK("pktcdvd: failed open (%d)\n", ret);	up(&ctl_mutex);	return ret;}static int pkt_close(struct inode *inode, struct file *file){	struct pktcdvd_device *pd = inode->i_bdev->bd_disk->private_data;	int ret = 0;	down(&ctl_mutex);	pd->refcnt--;	BUG_ON(pd->refcnt < 0);	if (pd->refcnt == 0) {		int flush = test_bit(PACKET_WRITABLE, &pd->flags);		pkt_release_dev(pd, flush);	}	up(&ctl_mutex);	return ret;}static void *psd_pool_alloc(gfp_t gfp_mask, void *data){	return kmalloc(sizeof(struct packet_stacked_data), gfp_mask);}static void psd_pool_free(void *ptr, void *data){	kfree(ptr);}static int pkt_end_io_read_cloned(struct bio *bio, unsigned int bytes_done, int err){	struct packet_stacked_data *psd = bio->bi_private;	struct pktcdvd_device *pd = psd->pd;	if (bio->bi_size)		return 1;	bio_put(bio);	bio_endio(psd->bio, psd->bio->bi_size, err);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -