[PATCH] DVD+-RW for 2.6.4

From: Nigel Kukard
Date: Tue Mar 23 2004 - 02:47:40 EST


Hi Guys,

I've done some work based on what Any Polakov had in 2.4.x in regards to
DVD+-RW.

Attached are patches I've created to support DVD+-RW in 2.6.4, just beware
on my LG GSA-4040B drive I get a vendor specific error code when I try
finalize the media. I have however not noticed any dataloss in 10
multisession dvd's i burnt last night.

Please test and let me know what the results are. BTW the DVD-RW patch
requires the packet writing patch to be applied first.

http://w1.894.telia.com/~u89404340/patches/packet/2.6/packet-2.6.4-rc2.patch.bz2



Thanks
Nigel Kukard

diff -c --new-file --recursive linux-2.6.4_vanilla/drivers/cdrom/cdrom.c linux-2.6.4_dvd+rw/drivers/cdrom/cdrom.c
*** linux-2.6.4_vanilla/drivers/cdrom/cdrom.c Thu Mar 11 04:55:22 2004
--- linux-2.6.4_dvd+rw/drivers/cdrom/cdrom.c Mon Mar 22 14:12:28 2004
***************
*** 766,771 ****
--- 766,774 ----

/* if this was a O_NONBLOCK open and we should honor the flags,
* do a quick open without drive/disc integrity checks. */
+ /* But do it earlier so that media_change can (re)sense MMC3
+ profile and tune mask accordingly. <appro@xxxxxxxxxxxxxx> */
+ check_disk_change(ip->i_bdev);
cdi->use_count++;
if ((fp->f_flags & O_NONBLOCK) && (cdi->options & CDO_USE_FFLAGS)) {
ret = cdi->ops->open(cdi, 1);
***************
*** 787,793 ****
cdi->name, cdi->use_count);
/* Do this on open. Don't wait for mount, because they might
not be mounting, but opening with O_NONBLOCK */
- check_disk_change(ip->i_bdev);
return 0;
err:
cdi->use_count--;
--- 790,795 ----
diff -c --new-file --recursive linux-2.6.4_vanilla/drivers/scsi/sr.c linux-2.6.4_dvd+rw/drivers/scsi/sr.c
*** linux-2.6.4_vanilla/drivers/scsi/sr.c Thu Mar 11 04:55:24 2004
--- linux-2.6.4_dvd+rw/drivers/scsi/sr.c Mon Mar 22 16:13:19 2004
***************
*** 30,35 ****
--- 30,39 ----
*
* Modified by Arnaldo Carvalho de Melo <acme@xxxxxxxxxxxxxxxx>
* check resource allocation in sr_init and some cleanups
+ *
+ * Modified by Nigel Kukard <nkukard@xxxxxxxx> - support DVD+RW
+ * 2.4.x patch by Andy Polyakov <appro@xxxxxxxxxxxxxx>
+ *
*/

#include <linux/module.h>
***************
*** 149,157 ****
/* If the disk changed, the capacity will now be different,
* so we force a re-read of this information */
if (retval) {
- /* check multisession offset etc */
- sr_cd_check(cdi);
-
/*
* If the disk changed, the capacity will now be different,
* so we force a re-read of this information
--- 153,158 ----
***************
*** 161,170 ****
--- 162,191 ----
*/
cd->needs_sector_size = 1;
cd->device->sector_size = 2048;
+ /* DVD+RW bookkeeping, mark clean */
+ cd->media_written = 0;
+
+ /* check multisession offset etc */
+ sr_cd_check(cdi);
}
return retval;
}

+ static void flush_intr(struct scsi_cmnd *SCpnt)
+ {
+ /* this is a temporary hack which suspends i/o if unexpected happens */
+ if (driver_byte(SCpnt->result) != 0 && SCpnt->sense_buffer[0] & 0xF0) {
+ printk("sr%d: unable to \"SYNCHRONIZE CACHE\" [%02x/%02x]? "
+ "Suspending I/O...\n",
+ SCpnt->sense_buffer[2],
+ SCpnt->sense_buffer[12],
+ SCpnt->sense_buffer[13]);
+ SCpnt->device->changed = 1;
+ }
+
+ scsi_release_request(SCpnt->sc_request);
+ }
+
static inline struct scsi_cd *scsi_cd(struct gendisk *disk)
{
return container_of(disk->private_data, struct scsi_cd, driver);
***************
*** 251,256 ****
--- 272,357 ----
}
}

+ if (cd->mmc3_profile == 0x1A &&
+ driver_byte(result) != 0 &&
+ SCpnt->sense_buffer[0] & 0xF0) /* permit for vendor codes */ {
+ if (SCpnt->sense_buffer[2] == MEDIUM_ERROR &&
+ SCpnt->sense_buffer[12] == 0x15 &&
+ rq_data_dir(SCpnt->request) == WRITE) {
+ printk("%s: This one beats me! Suspending I/O...\n",
+ cd->cdi.name);
+ SCpnt->device->changed = 1;
+ }
+ else if (SCpnt->sense_buffer[2] == ILLEGAL_REQUEST &&
+ SCpnt->sense_buffer[12] == 0x2c) do {
+ Scsi_Request *SRpnt;
+
+ printk("%s: injecting \"SYNCHRONIZE CACHE\"\n",
+ cd->cdi.name);
+
+ SRpnt = scsi_allocate_request(SCpnt->device,GFP_KERNEL);
+ if (SRpnt == NULL) {
+ printk ("%s: out of kernel memory :-(\n",
+ cd->cdi.name);
+ SCpnt->device->changed = 1;
+ break; /* mind do{}while(0) around */
+ }
+
+ SRpnt->sr_cmnd[0] = 0x35;
+ SRpnt->sr_cmd_len = 10;
+ SRpnt->sr_data_direction = SCSI_DATA_NONE;
+ SRpnt->sr_timeout_per_command = 30*HZ;
+ SRpnt->sr_done = flush_intr;
+
+ #if 0 /* scsi_insert_special_req isn't exported :-( */
+ scsi_insert_special_req(SRpnt,1);
+ #elseif 0
+ /*
+ * As scsi_insert_special_req is not exported, I
+ * just copy corresponding code from scsi_lib.c.
+ * This is a TEMPORARY solution and the ONLY
+ * reason for doing this is that I don't want to
+ * patch scsi_syms.c just yet! Below is inlined
+ * call to __scsi_insert_special(q,rq,SRpnt,1)
+ * from 2.4.18.
+ */
+ {
+ request_queue_t *q = &SRpnt->sr_device->request_queue;
+ struct request *rq = &SRpnt->sr_request;
+ unsigned long flags;
+
+ rq->cmd = SPECIAL;
+ rq->special = SRpnt;
+ rq->q = NULL;
+ rq->nr_segments = 0;
+ rq->elevator_sequence = 0;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+
+ list_add(&rq->queue, &q->queue_head);
+
+ q->request_fn(q);
+
+ spin_unlock_irqrestore(&io_request_lock, flags);
+ }
+ #else
+ SRpnt->sr_request->flags &= ~REQ_DONTPREP;
+ blk_insert_request(SRpnt->sr_device->request_queue, SRpnt->sr_request,
+ 1, SRpnt, 0);
+ #endif
+ /*
+ * fake "LOGICAL UNIT IS IN PROCESS OF BECOMING READY"
+ * for current command to fool scsi_io_completion().
+ */
+ SCpnt->sense_buffer[0] = 0xF0;
+ SCpnt->sense_buffer[2] &= 0xF0;
+ SCpnt->sense_buffer[2] |= NOT_READY;
+ SCpnt->sense_buffer[12] = 4;
+ SCpnt->sense_buffer[13] = 1;
+ good_bytes = 0;
+ } while (0);
+ }
+
/*
* This calls the generic completion function, now that we know
* how many actual sectors finished, and how many sectors we need
***************
*** 295,301 ****
--- 396,405 ----
if (!rq->data_len)
SCpnt->sc_data_direction = SCSI_DATA_NONE;
else if (rq_data_dir(rq) == WRITE)
+ {
SCpnt->sc_data_direction = SCSI_DATA_WRITE;
+ cd->media_written = 1;
+ }
else
SCpnt->sc_data_direction = SCSI_DATA_READ;

***************
*** 550,555 ****
--- 654,661 ----
cd->use = 1;
cd->readcd_known = 0;
cd->readcd_cdda = 0;
+ cd->media_written = 0;
+ cd->close_track_sniffed = 0;

cd->cdi.ops = &sr_dops;
cd->cdi.handle = cd;
diff -c --new-file --recursive linux-2.6.4_vanilla/drivers/scsi/sr.h linux-2.6.4_dvd+rw/drivers/scsi/sr.h
*** linux-2.6.4_vanilla/drivers/scsi/sr.h Thu Mar 11 04:55:25 2004
--- linux-2.6.4_dvd+rw/drivers/scsi/sr.h Mon Mar 22 14:12:28 2004
***************
*** 12,17 ****
--- 12,21 ----
* Modified by Eric Youngdale eric@xxxxxxxxxxx to
* add scatter-gather, multiple outstanding request, and other
* enhancements.
+ *
+ * Modified by Nigel Kukard <nkukard@xxxxxxxx> - support DVD+RW
+ * 2.4.x patch by Andy Polyakov <appro@xxxxxxxxxxxxxx>
+ *
*/

#ifndef _SR_H
***************
*** 24,29 ****
--- 28,37 ----
/* In fact, it is very slow if it has to spin up first */
#define IOCTL_TIMEOUT 30*HZ

+ /* primitive to determine whether we need to have GFP_DMA set based on
+ * the status of the unchecked_isa_dma flag in the host structure */
+ #define SR_GFP_DMA(cd) (((cd)->device->host->unchecked_isa_dma) ? GFP_DMA : 0)
+
typedef struct scsi_cd {
struct scsi_driver *driver;
unsigned capacity; /* size in blocks */
***************
*** 35,40 ****
--- 43,51 ----
unsigned xa_flag:1; /* CD has XA sectors ? */
unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */
unsigned readcd_cdda:1; /* reading audio data using READ_CD */
+ unsigned media_written:1; /* dirty flag, DVD+RW bookkeeping */
+ unsigned close_track_sniffed:1; /* dirty flag, DVD+RW bookkeeping */
+ unsigned short mmc3_profile; /* current MMC3 profile, see sr_vendor.c */
struct cdrom_device_info cdi;
struct gendisk *disk;
} Scsi_CD;
***************
*** 58,62 ****
--- 69,75 ----
void sr_vendor_init(Scsi_CD *);
int sr_cd_check(struct cdrom_device_info *);
int sr_set_blocklength(Scsi_CD *, int blocklength);
+ /* anchor for DVD+RW "finalization" at unlock */
+ void sr_vendor_lock_door (Scsi_CD *,int lock);

#endif
diff -c --new-file --recursive linux-2.6.4_vanilla/drivers/scsi/sr_ioctl.c linux-2.6.4_dvd+rw/drivers/scsi/sr_ioctl.c
*** linux-2.6.4_vanilla/drivers/scsi/sr_ioctl.c Thu Mar 11 04:55:35 2004
--- linux-2.6.4_dvd+rw/drivers/scsi/sr_ioctl.c Mon Mar 22 14:12:28 2004
***************
*** 160,165 ****
--- 160,172 ----
err = -EIO;
}
}
+ else if (cgc->cmd[0] == 0x5B) {
+ /* Even though this flag is commented as DVD+RW specific
+ * in sr.h, no check if currently mounted media is DVD+RW
+ * is performed. That's because the flag does good in
+ * in either case. */
+ cd->close_track_sniffed = 1;
+ }

if (cgc->sense)
memcpy(cgc->sense, SRpnt->sr_sense_buffer, sizeof(*cgc->sense));
***************
*** 205,210 ****
--- 212,218 ----
{
Scsi_CD *cd = cdi->handle;

+ sr_vendor_lock_door(cd,lock);
return scsi_set_medium_removal(cd->device, lock ?
SCSI_REMOVAL_PREVENT : SCSI_REMOVAL_ALLOW);
}
***************
*** 262,271 ****
return 0;
}

- /* primitive to determine whether we need to have GFP_DMA set based on
- * the status of the unchecked_isa_dma flag in the host structure */
- #define SR_GFP_DMA(cd) (((cd)->device->host->unchecked_isa_dma) ? GFP_DMA : 0)
-
int sr_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
{
Scsi_CD *cd = cdi->handle;
--- 270,275 ----
diff -c --new-file --recursive linux-2.6.4_vanilla/drivers/scsi/sr_vendor.c linux-2.6.4_dvd+rw/drivers/scsi/sr_vendor.c
*** linux-2.6.4_vanilla/drivers/scsi/sr_vendor.c Thu Mar 11 04:55:27 2004
--- linux-2.6.4_dvd+rw/drivers/scsi/sr_vendor.c Mon Mar 22 19:04:12 2004
***************
*** 32,37 ****
--- 32,41 ----
* - HP: Much like SONY, but a little different... (Thomas)
* HP-Writers only ??? Maybe other CD-Writers work with this too ?
* HP 6020 writers now supported.
+ * --------------------------------------------------------------------------
+ *
+ * Modified by Nigel Kukard <nkukard@xxxxxxxx> - support DVD+RW
+ * 2.4.x patch by Andy Polyakov <appro@xxxxxxxxxxxxxx>
*/

#include <linux/config.h>
***************
*** 61,79 ****

#define VENDOR_TIMEOUT 30*HZ

void sr_vendor_init(Scsi_CD *cd)
{
#ifndef CONFIG_BLK_DEV_SR_VENDOR
cd->vendor = VENDOR_SCSI3;
#else
char *vendor = cd->device->vendor;
char *model = cd->device->model;

/* default */
cd->vendor = VENDOR_SCSI3;
! if (cd->readcd_known)
/* this is true for scsi3/mmc drives - no more checks */
return;

if (cd->device->type == TYPE_WORM) {
cd->vendor = VENDOR_WRITER;
--- 65,203 ----

#define VENDOR_TIMEOUT 30*HZ

+ static unsigned short sr_mmc3_profile(Scsi_CD *cd)
+ {
+ char *buffer = kmalloc(32, GFP_KERNEL | SR_GFP_DMA(cd));
+ int rc, mmc3_profile;
+ struct cdrom_generic_command cgc;
+
+ /* Read MMC-3 profile */
+ memset(&cgc, 0, sizeof(struct cdrom_generic_command));
+ cgc.cmd[0] = GPCMD_GET_CONFIGURATION;
+ cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
+ (cd->device->lun << 5) : 0;
+ cgc.cmd[2] = cgc.cmd[3] = 0; /* Starting Feature Number */
+ cgc.cmd[4] = cgc.cmd[5] = cgc.cmd [6] = 0; /* Reserved */
+ cgc.cmd[7] = 0; cgc.cmd [8] = 8; /* Allocation Length */
+ cgc.cmd[9] = 0; /* Control */
+ cgc.buffer = buffer;
+ cgc.buflen = 8;
+ cgc.timeout = IOCTL_TIMEOUT;
+ cgc.data_direction = SCSI_DATA_READ;
+
+ rc = sr_do_ioctl(cd, &cgc);
+ if (rc) { /* doesn't seem to support MMC3 profiles!!! */
+ mmc3_profile = 0xFFFF;
+ } else {
+ mmc3_profile = (buffer[6] << 8) | buffer[7];
+ switch (mmc3_profile) {
+ case 0x0A: /* CD-RW */
+ cd->cdi.mask &= ~CDC_CD_RW;
+ cd->device->writeable = 1;
+ break;
+ case 0x12: /* DVD-RAM */
+ case 0x1A: /* DVD+RW */
+ cd->cdi.mask &= ~CDC_DVD_RAM;
+ cd->device->writeable = 1;
+ break;
+ case 0x1B: /* DVD+R */
+ /* Needed for accessing of opened media */
+ cgc.cmd[0] = GPCMD_READ_FORMAT_CAPACITIES;
+ cgc.cmd[8] = 12;
+ cgc.timeout = VENDOR_TIMEOUT;
+
+ rc = sr_do_ioctl(cd, &cgc);
+ if (!rc) {
+ cd->capacity = ((buffer[4] << 24) |
+ (buffer[5] << 16) |
+ (buffer[6] << 8) |
+ buffer[7]) * 4;
+ cd->device->sector_size = 2048;
+ cd->disk->capacity = cd->disk->capacity >> (BLOCK_SIZE_BITS - 9);
+ cd->needs_sector_size = 0;
+ }
+ /* no break; */
+ default:
+ cd->cdi.mask |= CDC_DVD_RAM;
+ cd->device->writeable = 0;
+ break;
+ }
+ }
+ cd->mmc3_profile = mmc3_profile;
+
+ kfree(buffer);
+ return mmc3_profile;
+ }
+
+ void sr_vendor_lock_door(Scsi_CD *cd, int lock)
+ {
+ struct cdrom_generic_command cgc;
+
+ if (lock != 0) return;
+
+ if ( (cd->media_written) &&
+ (cd->mmc3_profile == 0x1A) ) {
+ printk ("%s: dirty DVD+RW media, \"finalizing\"\n",
+ cd->cdi.name);
+
+ memset(&cgc, 0, sizeof(struct cdrom_generic_command));
+ cgc.cmd[0] = GPCMD_FLUSH_CACHE;
+ cgc.timeout = IOCTL_TIMEOUT;
+ cgc.data_direction = SCSI_DATA_NONE;
+ sr_do_ioctl(cd, &cgc);
+
+ memset(&cgc, 0, sizeof(struct cdrom_generic_command));
+ cgc.cmd[0] = GPCMD_CLOSE_TRACK;
+ cgc.timeout = 3000*HZ;
+ cgc.data_direction = SCSI_DATA_NONE;
+ sr_do_ioctl(cd, &cgc);
+
+ memset(&cgc, 0, sizeof(struct cdrom_generic_command));
+ cgc.cmd[0] = GPCMD_CLOSE_TRACK;
+ cgc.cmd[2] = 2; /* Close session */
+ cgc.timeout = 3000*HZ;
+ cgc.data_direction = SCSI_DATA_NONE;
+ sr_do_ioctl(cd, &cgc);
+
+ /* bookkeeping, mark clean and changed */
+ cd->media_written = 0;
+ cd->close_track_sniffed = 0;
+ cd->device->changed = 1;
+ }
+ else if (cd->close_track_sniffed) {
+ cd->close_track_sniffed = 0;
+ cd->device->changed = 1;
+ }
+ }
+
void sr_vendor_init(Scsi_CD *cd)
{
+ int rc;
#ifndef CONFIG_BLK_DEV_SR_VENDOR
cd->vendor = VENDOR_SCSI3;
+
+ /* check for MMC-3 Profile capability */
+ rc = sr_mmc3_profile(cd);
+ if (rc != 0xFFFF)
+ printk ("%s: mmc-3 profile capable,"
+ " current profile: %Xh\n", cd->cdi.name, rc);
+ return;
#else
char *vendor = cd->device->vendor;
char *model = cd->device->model;

/* default */
cd->vendor = VENDOR_SCSI3;
! if (cd->readcd_known) {
! /* this is true for scsi3/mmc drives */
! /* check for MMC-3 Profile capability */
! rc = sr_mmc3_profile(cd);
! if (rc != 0xFFFF)
! printk ("%s: mmc-3 profile capable,"
! " current profile: %Xh\n", cd->cdi.name, rc);
/* this is true for scsi3/mmc drives - no more checks */
return;
+ }

if (cd->device->type == TYPE_WORM) {
cd->vendor = VENDOR_WRITER;
***************
*** 160,165 ****
--- 284,300 ----
struct cdrom_generic_command cgc;
int rc, no_multi;

+
+ if ((cd->vendor == VENDOR_SCSI3) &&
+ (cd->mmc3_profile != 0xFFFF)) {
+ rc = sr_mmc3_profile(cd);
+ if (rc != 0xFFFF)
+ printk ("%s: mmc-3 profile: %Xh\n", cd->cdi.name, rc);
+ else
+ printk ("%s: Failed to sense mmc-3 profile\n",
+ cd->cdi.name);
+ }
+
if (cd->cdi.mask & CDC_MULTI_SESSION)
return 0;

***************
*** 177,184 ****

case VENDOR_SCSI3:
cgc.cmd[0] = READ_TOC;
cgc.cmd[8] = 12;
- cgc.cmd[9] = 0x40;
cgc.buffer = buffer;
cgc.buflen = 12;
cgc.quiet = 1;
--- 312,319 ----

case VENDOR_SCSI3:
cgc.cmd[0] = READ_TOC;
+ cgc.cmd[2] = 1;
cgc.cmd[8] = 12;
cgc.buffer = buffer;
cgc.buflen = 12;
cgc.quiet = 1;
***************
*** 187,193 ****
rc = sr_do_ioctl(cd, &cgc);
if (rc != 0)
break;
! if ((buffer[0] << 8) + buffer[1] < 0x0a) {
printk(KERN_INFO "%s: Hmm, seems the drive "
"doesn't support multisession CD's\n", cd->cdi.name);
no_multi = 1;
--- 322,328 ----
rc = sr_do_ioctl(cd, &cgc);
if (rc != 0)
break;
! if ((buffer[0] << 8) + buffer[1] < 8) {
printk(KERN_INFO "%s: Hmm, seems the drive "
"doesn't support multisession CD's\n", cd->cdi.name);
no_multi = 1;
diff -c --recursive linux-2.6.4_packet/drivers/block/Kconfig linux-2.6.4_dvd-rw/drivers/block/Kconfig
*** linux-2.6.4_packet/drivers/block/Kconfig Mon Mar 22 14:44:56 2004
--- linux-2.6.4_dvd-rw/drivers/block/Kconfig Mon Mar 22 15:03:56 2004
***************
*** 345,351 ****
compliant ATAPI or SCSI drive, which is just about any newer CD
writer.

! Currently only writing to CD-RW discs is possible.

To compile this driver as a module, choose M here: the
module will be called pktcdvd.
--- 345,353 ----
compliant ATAPI or SCSI drive, which is just about any newer CD
writer.

! Currently only writing to CD-RW, DVD-RW and DVD+RW discs is possible.
!
! DVD-RW disks must be in restricted overwrite mode.

To compile this driver as a module, choose M here: the
module will be called pktcdvd.
diff -c --recursive linux-2.6.4_packet/drivers/block/pktcdvd.c linux-2.6.4_dvd-rw/drivers/block/pktcdvd.c
*** linux-2.6.4_packet/drivers/block/pktcdvd.c Mon Mar 22 14:44:56 2004
--- linux-2.6.4_dvd-rw/drivers/block/pktcdvd.c Mon Mar 22 15:21:43 2004
***************
*** 1346,1351 ****
--- 1346,1357 ----
char buffer[128];
int ret, size;

+ /* doesn't apply to DVD+RW (?) */
+ if (pd->mmc3_profile == 0x1a)
+ return 0;
+ /* if (pd->mmc3_profile == 0x13) */
+ /* return 0; */
+
memset(buffer, 0, sizeof(buffer));
init_cdrom_command(&cgc, buffer, sizeof(*wp), CGC_DATA_READ);
cgc.sense = &sense;
***************
*** 1451,1456 ****
--- 1457,1475 ----
*/
static int pkt_good_disc(struct pktcdvd_device *pd, disc_information *di)
{
+ switch (pd->mmc3_profile) {
+ case 0x0a: /* CD-RW */
+ case 0xffff: /* MMC3 not supported ? */
+ break;
+ case 0x1a: /* DVD+RW */
+ return 0;
+ case 0x13: /* DVD-RW Experimental */
+ return 0;
+ default:
+ printk("pktcdvd: Wrong disc profile (%x)\n", pd->mmc3_profile);
+ return 1;
+ }
+
/*
* for disc type 0xff we should probably reserve a new track.
* but i'm not sure, should we leave this to user apps? probably.
***************
*** 1480,1489 ****
--- 1499,1516 ----

static int pkt_probe_settings(struct pktcdvd_device *pd)
{
+ struct cdrom_generic_command cgc;
+ unsigned char buf[12];
disc_information di;
track_information ti;
int ret, track;

+ init_cdrom_command(&cgc, buf, 8, 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));

***************
*** 1818,1831 ****

if ((ret = pkt_get_max_speed(pd, &write_speed)))
write_speed = 16;
! if ((ret = pkt_media_speed(pd, &media_write_speed)))
! media_write_speed = 16;
! write_speed = min_t(unsigned, write_speed, media_write_speed);
! read_speed = (write_speed * 3) / 2;

if ((ret = pkt_set_speed(pd, write_speed, read_speed))) {
DPRINTK("pktcdvd: %s couldn't set write speed\n", pd->name);
return -EIO;
}
DPRINTK("pktcdvd: speed (R/W) %u/%u\n", read_speed, write_speed);
pd->write_speed = write_speed;
--- 1845,1868 ----

if ((ret = pkt_get_max_speed(pd, &write_speed)))
write_speed = 16;
! switch (pd->mmc3_profile) {
! case 0x13: /* DVD-RW Experimental */
! case 0x1a: /* DVD+RW */
! read_speed = write_speed;
! break;
! default:
! if ((ret = pkt_media_speed(pd, &media_write_speed)))
! media_write_speed = 16;
! write_speed = min_t(unsigned, write_speed, media_write_speed);
! read_speed = (write_speed * 3) / 2;
! break;
! }

if ((ret = pkt_set_speed(pd, write_speed, read_speed))) {
DPRINTK("pktcdvd: %s couldn't set write speed\n", pd->name);
+ /*
return -EIO;
+ */
}
DPRINTK("pktcdvd: speed (R/W) %u/%u\n", read_speed, write_speed);
pd->write_speed = write_speed;
diff -c --recursive linux-2.6.4_packet/drivers/scsi/sr_vendor.c linux-2.6.4_dvd-rw/drivers/scsi/sr_vendor.c
*** linux-2.6.4_packet/drivers/scsi/sr_vendor.c Mon Mar 22 14:51:24 2004
--- linux-2.6.4_dvd-rw/drivers/scsi/sr_vendor.c Mon Mar 22 15:03:56 2004
***************
*** 117,122 ****
--- 117,125 ----
cd->needs_sector_size = 0;
}
/* no break; */
+ case 0x13: /* DVD-RW Restricted Overwrite */
+ cd->device->writeable = 1;
+ break;
default:
cd->cdi.mask |= CDC_DVD_RAM;
cd->device->writeable = 0;
diff -c --recursive linux-2.6.4_packet/include/linux/pktcdvd.h linux-2.6.4_dvd-rw/include/linux/pktcdvd.h
*** linux-2.6.4_packet/include/linux/pktcdvd.h Mon Mar 22 14:44:56 2004
--- linux-2.6.4_dvd-rw/include/linux/pktcdvd.h Mon Mar 22 15:03:56 2004
***************
*** 244,249 ****
--- 244,250 ----
__u8 mode_offset; /* 0 / 8 */
__u8 type;
unsigned long flags;
+ __u16 mmc3_profile;
__u8 disc_status;
__u8 track_status; /* last one */
__u32 nwa; /* next writable address */

Attachment: pgp00000.pgp
Description: PGP signature