Commit ed594d2d authored by Peter Osterlund's avatar Peter Osterlund Committed by Linus Torvalds

[PATCH] DVD+RW support

This patch adds support for using DVD+RW drives as writable block devices.

The patch is based on work from:

        Andy Polyakov <appro@fy.chalmers.se> - Wrote the 2.4 patch
        Nigel Kukard <nkukard@lbsd.net> - Initial porting to 2.6.x

It works for me using an Iomega Super DVD 8x USB drive.


  Nov 5 2001, Aug 8 2002. Modified by Andy Polyakov
  <appro@fy.chalmers.se> to support MMC-3 complaint DVD+RW units.

  Modified by Nigel Kukard <nkukard@lbsd.net> - support DVD+RW
  2.4.x patch by Andy Polyakov <appro@fy.chalmers.se>

This patch implements CDRW packet writing as a kernel block device.  Usage
instructions are in the packet-writing.txt file.

A hint: If you don't want to wait for a complete disc format, you can
format just a part of the disc.  For example:

        cdrwtool -d /dev/hdc -m 10240

This will format 10240 blocks, ie 20MB.
Signed-off-by: default avatarPeter Osterlund <petero2@telia.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent a4946826
...@@ -848,6 +848,41 @@ static int cdrom_ram_open_write(struct cdrom_device_info *cdi) ...@@ -848,6 +848,41 @@ static int cdrom_ram_open_write(struct cdrom_device_info *cdi)
return ret; return ret;
} }
static void cdrom_mmc3_profile(struct cdrom_device_info *cdi)
{
struct packet_command cgc;
char buffer[32];
int ret, mmc3_profile;
init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
cgc.cmd[0] = GPCMD_GET_CONFIGURATION;
cgc.cmd[1] = 0;
cgc.cmd[2] = cgc.cmd[3] = 0; /* Starting Feature Number */
cgc.cmd[7] = 0; cgc.cmd [8] = 8; /* Allocation Length */
cgc.quiet = 1;
if ((ret = cdi->ops->generic_packet(cdi, &cgc))) {
mmc3_profile = 0xffff;
} else {
mmc3_profile = (buffer[6] << 8) | buffer[7];
printk(KERN_INFO "cdrom: %s: mmc-3 profile capable, current profile: %Xh\n",
cdi->name, mmc3_profile);
}
cdi->mmc3_profile = mmc3_profile;
}
static int cdrom_is_dvd_rw(struct cdrom_device_info *cdi)
{
switch (cdi->mmc3_profile) {
case 0x12: /* DVD-RAM */
case 0x1A: /* DVD+RW */
return 0;
default:
return 1;
}
}
/* /*
* returns 0 for ok to open write, non-0 to disallow * returns 0 for ok to open write, non-0 to disallow
*/ */
...@@ -889,10 +924,50 @@ static int cdrom_open_write(struct cdrom_device_info *cdi) ...@@ -889,10 +924,50 @@ static int cdrom_open_write(struct cdrom_device_info *cdi)
ret = cdrom_ram_open_write(cdi); ret = cdrom_ram_open_write(cdi);
else if (CDROM_CAN(CDC_MO_DRIVE)) else if (CDROM_CAN(CDC_MO_DRIVE))
ret = mo_open_write(cdi); ret = mo_open_write(cdi);
else if (!cdrom_is_dvd_rw(cdi))
ret = 0;
return ret; return ret;
} }
static void cdrom_dvd_rw_close_write(struct cdrom_device_info *cdi)
{
struct packet_command cgc;
if (cdi->mmc3_profile != 0x1a) {
cdinfo(CD_CLOSE, "%s: No DVD+RW\n", cdi->name);
return;
}
if (!cdi->media_written) {
cdinfo(CD_CLOSE, "%s: DVD+RW media clean\n", cdi->name);
return;
}
printk(KERN_INFO "cdrom: %s: dirty DVD+RW media, \"finalizing\"\n",
cdi->name);
init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
cgc.cmd[0] = GPCMD_FLUSH_CACHE;
cgc.timeout = 30*HZ;
cdi->ops->generic_packet(cdi, &cgc);
init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
cgc.cmd[0] = GPCMD_CLOSE_TRACK;
cgc.timeout = 3000*HZ;
cgc.quiet = 1;
cdi->ops->generic_packet(cdi, &cgc);
init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
cgc.cmd[0] = GPCMD_CLOSE_TRACK;
cgc.cmd[2] = 2; /* Close session */
cgc.quiet = 1;
cgc.timeout = 3000*HZ;
cdi->ops->generic_packet(cdi, &cgc);
cdi->media_written = 0;
}
static int cdrom_close_write(struct cdrom_device_info *cdi) static int cdrom_close_write(struct cdrom_device_info *cdi)
{ {
#if 0 #if 0
...@@ -925,6 +1000,7 @@ int cdrom_open(struct cdrom_device_info *cdi, struct inode *ip, struct file *fp) ...@@ -925,6 +1000,7 @@ int cdrom_open(struct cdrom_device_info *cdi, struct inode *ip, struct file *fp)
ret = open_for_data(cdi); ret = open_for_data(cdi);
if (ret) if (ret)
goto err; goto err;
cdrom_mmc3_profile(cdi);
if (fp->f_mode & FMODE_WRITE) { if (fp->f_mode & FMODE_WRITE) {
ret = -EROFS; ret = -EROFS;
if (cdrom_open_write(cdi)) if (cdrom_open_write(cdi))
...@@ -932,6 +1008,7 @@ int cdrom_open(struct cdrom_device_info *cdi, struct inode *ip, struct file *fp) ...@@ -932,6 +1008,7 @@ int cdrom_open(struct cdrom_device_info *cdi, struct inode *ip, struct file *fp)
if (!CDROM_CAN(CDC_RAM)) if (!CDROM_CAN(CDC_RAM))
goto err; goto err;
ret = 0; ret = 0;
cdi->media_written = 0;
} }
} }
...@@ -1123,6 +1200,8 @@ int cdrom_release(struct cdrom_device_info *cdi, struct file *fp) ...@@ -1123,6 +1200,8 @@ int cdrom_release(struct cdrom_device_info *cdi, struct file *fp)
cdi->use_count--; cdi->use_count--;
if (cdi->use_count == 0) if (cdi->use_count == 0)
cdinfo(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n", cdi->name); cdinfo(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n", cdi->name);
if (cdi->use_count == 0)
cdrom_dvd_rw_close_write(cdi);
if (cdi->use_count == 0 && if (cdi->use_count == 0 &&
(cdo->capability & CDC_LOCK) && !keeplocked) { (cdo->capability & CDC_LOCK) && !keeplocked) {
cdinfo(CD_CLOSE, "Unlocking door!\n"); cdinfo(CD_CLOSE, "Unlocking door!\n");
...@@ -1329,6 +1408,7 @@ int media_changed(struct cdrom_device_info *cdi, int queue) ...@@ -1329,6 +1408,7 @@ int media_changed(struct cdrom_device_info *cdi, int queue)
if (cdi->ops->media_changed(cdi, CDSL_CURRENT)) { if (cdi->ops->media_changed(cdi, CDSL_CURRENT)) {
cdi->mc_flags = 0x3; /* set bit on both queues */ cdi->mc_flags = 0x3; /* set bit on both queues */
ret |= 1; ret |= 1;
cdi->media_written = 0;
} }
cdi->mc_flags &= ~mask; /* clear bit */ cdi->mc_flags &= ~mask; /* clear bit */
return ret; return ret;
......
...@@ -1932,6 +1932,8 @@ static ide_startstop_t cdrom_start_write(ide_drive_t *drive, struct request *rq) ...@@ -1932,6 +1932,8 @@ static ide_startstop_t cdrom_start_write(ide_drive_t *drive, struct request *rq)
info->dma = drive->using_dma ? 1 : 0; info->dma = drive->using_dma ? 1 : 0;
info->cmd = WRITE; info->cmd = WRITE;
info->devinfo.media_written = 1;
/* Start sending the write request to the drive. */ /* Start sending the write request to the drive. */
return cdrom_start_packet_command(drive, 32768, cdrom_start_write_cont); return cdrom_start_packet_command(drive, 32768, cdrom_start_write_cont);
} }
......
...@@ -377,6 +377,7 @@ static int sr_init_command(struct scsi_cmnd * SCpnt) ...@@ -377,6 +377,7 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
return 0; return 0;
SCpnt->cmnd[0] = WRITE_10; SCpnt->cmnd[0] = WRITE_10;
SCpnt->sc_data_direction = DMA_TO_DEVICE; SCpnt->sc_data_direction = DMA_TO_DEVICE;
cd->cdi.media_written = 1;
} else if (rq_data_dir(SCpnt->request) == READ) { } else if (rq_data_dir(SCpnt->request) == READ) {
SCpnt->cmnd[0] = READ_10; SCpnt->cmnd[0] = READ_10;
SCpnt->sc_data_direction = DMA_FROM_DEVICE; SCpnt->sc_data_direction = DMA_FROM_DEVICE;
......
...@@ -947,6 +947,8 @@ struct cdrom_device_info { ...@@ -947,6 +947,8 @@ struct cdrom_device_info {
__u8 reserved : 6; /* not used yet */ __u8 reserved : 6; /* not used yet */
int cdda_method; /* see flags */ int cdda_method; /* see flags */
__u8 last_sense; __u8 last_sense;
__u8 media_written; /* dirty flag, DVD+RW bookkeeping */
unsigned short mmc3_profile; /* current MMC3 profile */
int for_data; int for_data;
int (*exit)(struct cdrom_device_info *); int (*exit)(struct cdrom_device_info *);
int mrw_mode_page; int mrw_mode_page;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment