lkml.org 
[lkml]   [2004]   [Mar]   [23]   [last100]   RSS Feed
Views: [more markup]  [less markup]  [headers]  [forward] 
 
Messages in this thread
/
DateTue, 23 Mar 2004 09:44:52 +0200
FromNigel Kukard <>
Subject[PATCH] DVD+-RW for 2.6.4
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@fy.chalmers.se> */
+ 	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@conectiva.com.br>
   *	check resource allocation in sr_init and some cleanups
+  *	
+  *	Modified by Nigel Kukard <nkukard@lbsd.net> - support DVD+RW
+  *	2.4.x patch by Andy Polyakov <appro@fy.chalmers.se>
+  *
   */
  #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@andante.org to
   *       add scatter-gather, multiple outstanding request, and other
   *       enhancements.
+  *	
+  *	Modified by Nigel Kukard <nkukard@lbsd.net> - support DVD+RW
+  *	2.4.x patch by Andy Polyakov <appro@fy.chalmers.se>
+  *
   */
  #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@lbsd.net> - support DVD+RW
+  *	2.4.x patch by Andy Polyakov <appro@fy.chalmers.se>
   */
  #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 */[unhandled content-type:application/pgp-signature]
\
 
 \ /
  Last update: 2005-03-22 13:01    [from the cache]
©2003-2008