From: Peter Osterlund This patch adds support for using DVD+RW drives as writable block devices. The patch is based on work from: Andy Polyakov - Wrote the 2.4 patch Nigel Kukard - Initial porting to 2.6.x It works for me using an Iomega Super DVD 8x USB drive. Signed-off-by: Peter Osterlund Signed-off-by: Andrew Morton --- 25-akpm/drivers/cdrom/cdrom.c | 80 ++++++++++++++++++++++++++++++++++++++++++ 25-akpm/drivers/ide/ide-cd.c | 2 + 25-akpm/drivers/scsi/sr.c | 1 25-akpm/include/linux/cdrom.h | 2 + 4 files changed, 85 insertions(+) diff -puN drivers/cdrom/cdrom.c~dvdrw-support-for-267-bk13 drivers/cdrom/cdrom.c --- 25/drivers/cdrom/cdrom.c~dvdrw-support-for-267-bk13 Thu Jul 1 14:50:59 2004 +++ 25-akpm/drivers/cdrom/cdrom.c Thu Jul 1 14:51:34 2004 @@ -821,6 +821,41 @@ static int cdrom_ram_open_write(struct c 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 */ @@ -859,10 +894,50 @@ static int cdrom_open_write(struct cdrom ret = cdrom_ram_open_write(cdi); else if (CDROM_CAN(CDC_MO_DRIVE)) ret = mo_open_write(cdi); + else if (!cdrom_is_dvd_rw(cdi)) + ret = 0; 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) { #if 0 @@ -895,6 +970,7 @@ int cdrom_open(struct cdrom_device_info ret = open_for_data(cdi); if (ret) goto err; + cdrom_mmc3_profile(cdi); if (fp->f_mode & FMODE_WRITE) { ret = -EROFS; if (!CDROM_CAN(CDC_RAM)) @@ -902,6 +978,7 @@ int cdrom_open(struct cdrom_device_info if (cdrom_open_write(cdi)) goto err; ret = 0; + cdi->media_written = 0; } } @@ -1093,6 +1170,8 @@ int cdrom_release(struct cdrom_device_in cdi->use_count--; if (cdi->use_count == 0) 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 && (cdo->capability & CDC_LOCK) && !keeplocked) { cdinfo(CD_CLOSE, "Unlocking door!\n"); @@ -1299,6 +1378,7 @@ int media_changed(struct cdrom_device_in if (cdi->ops->media_changed(cdi, CDSL_CURRENT)) { cdi->mc_flags = 0x3; /* set bit on both queues */ ret |= 1; + cdi->media_written = 0; } cdi->mc_flags &= ~mask; /* clear bit */ return ret; diff -puN drivers/ide/ide-cd.c~dvdrw-support-for-267-bk13 drivers/ide/ide-cd.c --- 25/drivers/ide/ide-cd.c~dvdrw-support-for-267-bk13 Thu Jul 1 14:50:59 2004 +++ 25-akpm/drivers/ide/ide-cd.c Thu Jul 1 14:50:59 2004 @@ -1940,6 +1940,8 @@ static ide_startstop_t cdrom_start_write info->dma = drive->using_dma ? 1 : 0; info->cmd = WRITE; + info->devinfo.media_written = 1; + /* Start sending the write request to the drive. */ return cdrom_start_packet_command(drive, 32768, cdrom_start_write_cont); } diff -puN drivers/scsi/sr.c~dvdrw-support-for-267-bk13 drivers/scsi/sr.c --- 25/drivers/scsi/sr.c~dvdrw-support-for-267-bk13 Thu Jul 1 14:50:59 2004 +++ 25-akpm/drivers/scsi/sr.c Thu Jul 1 14:50:59 2004 @@ -379,6 +379,7 @@ static int sr_init_command(struct scsi_c return 0; SCpnt->cmnd[0] = WRITE_10; SCpnt->sc_data_direction = DMA_TO_DEVICE; + cd->cdi.media_written = 1; } else if (rq_data_dir(SCpnt->request) == READ) { SCpnt->cmnd[0] = READ_10; SCpnt->sc_data_direction = DMA_FROM_DEVICE; diff -puN include/linux/cdrom.h~dvdrw-support-for-267-bk13 include/linux/cdrom.h --- 25/include/linux/cdrom.h~dvdrw-support-for-267-bk13 Thu Jul 1 14:50:59 2004 +++ 25-akpm/include/linux/cdrom.h Thu Jul 1 14:50:59 2004 @@ -946,6 +946,8 @@ struct cdrom_device_info { __u8 reserved : 6; /* not used yet */ int cdda_method; /* see flags */ __u8 last_sense; + __u8 media_written; /* dirty flag, DVD+RW bookkeeping */ + unsigned short mmc3_profile; /* current MMC3 profile */ int for_data; int (*exit)(struct cdrom_device_info *); int mrw_mode_page; _