From p@i609.hadiko.de  Tue Apr 17 05:41:49 2001
Return-Path: <p@i609.hadiko.de>
Received: from mailgate.rz.uni-karlsruhe.de (mailgate.rz.uni-karlsruhe.de [129.13.64.97])
	by hub.freebsd.org (Postfix) with ESMTP id 691F537B43E
	for <FreeBSD-gnats-submit@freebsd.org>; Tue, 17 Apr 2001 05:41:44 -0700 (PDT)
	(envelope-from p@i609.hadiko.de)
Received: from nce2.hadiko.de (hadince2.hadiko.uni-karlsruhe.de [172.20.32.2])
	by mailgate.rz.uni-karlsruhe.de with esmtp (Exim 3.16 #1)
	id 14pUne-0004US-00; Tue, 17 Apr 2001 14:41:42 +0200
Received: from i609.hadiko.de (hadii609.hadiko.uni-karlsruhe.de [172.20.44.159])
	by nce2.hadiko.de (8.9.3/8.9.3) with ESMTP id OAA13295
	for <FreeBSD-gnats-submit@freebsd.org>; Tue, 17 Apr 2001 14:41:38 +0200 (MET DST)
Received: (from p@localhost)
	by i609.hadiko.de (8.11.3/8.11.3) id f3HCfbd01363;
	Tue, 17 Apr 2001 14:41:37 +0200 (CEST)
	(envelope-from p)
Message-Id: <200104171241.f3HCfbd01363@i609.hadiko.de>
Date: Tue, 17 Apr 2001 14:41:37 +0200 (CEST)
From: un1i@rz.uni-karlsruhe.de
Reply-To: un1i@rz.uni-karlsruhe.de
To: FreeBSD-gnats-submit@freebsd.org
Cc:
Subject: [PATCH] ATA/ATAPI driver doesn't implement CDIOCREADSUBCHANNEL correctly
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         26644
>Category:       kern
>Synopsis:       [PATCH] ATA/ATAPI driver doesn't implement CDIOCREADSUBCHANNEL correctly
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    sos
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Apr 17 05:50:01 PDT 2001
>Closed-Date:    Sat Mar 16 09:03:05 PST 2002
>Last-Modified:  Sat Mar 16 09:03:05 PST 2002
>Originator:     Philipp Mergenthaler
>Release:        FreeBSD 5.0-CURRENT i386
>Organization:
Univeristy of Karlsruhe
>Environment:
System: FreeBSD i609.hadiko.de 5.0-CURRENT FreeBSD 5.0-CURRENT #368: Tue Apr 17 12:35:00 CEST 2001 p@i609.hadiko.de:/usr/obj/usr/src/sys/I609 i386


>Description:
1) The ioctl CDIOCREADSUBCHANNEL can be used to request position information,
   the media catalogue or track info. However, atapi-cd.c:acdioctl()
   always returns the position information.

2) At the same place, the function lba2msf() is used to compute the track
   relative address. However, this function adds an offset of 150 frames
   to convert from LBA (logical block address) to MSF (minute, second, frame).
   This is correct for absolute adresses, but not in this case.

>How-To-Repeat:

1) Execute "cdcontrol -f /dev/acd0 status". Note that the media catalog
   number is bogus or contains control characters.

2) Execute "cdcontrol -f /dev/acd0 play 1 && cdcontrol -f /dev/acd0 status"
   and note that the "current position" starts at 0:02.00, not 0:00.00 as
   expected.

   
>Fix:

The following two patches are alternative. The first one tries to stay
with the current style: copy all data from cdp->subchan to struct data
and do the lba-msf conversion with lba2msf().

The second patch isn't so lengthy, it copies data directly from
cdp->subchan to the userland and leaves the lba-msf conversion to
the drive.

I could imagine that reasons for the original style would be to isolate
struct cd_sub_channel_info and struct subchan in case one of them changes,
and to work around broken drives that can't do the lba-msf conversion.

I'm not sure how relevant these are. The code in /sys/cam/scsi/scsi_cd.c
looks more like my second patch.

You'll notice that I always ask the drive for position information first.
This is because the drive will return an error if the media catalog
or track information is requested while an audio play operation is
in progress. Therefore I only request that if the audio status is ok.


Index: atapi-cd.c
===================================================================
RCS file: /ncvs/src/sys/dev/ata/atapi-cd.c,v
retrieving revision 1.88
diff -u -r1.88 atapi-cd.c
--- atapi-cd.c	2001/04/05 11:17:33	1.88
+++ atapi-cd.c	2001/04/17 10:31:09
@@ -726,6 +726,8 @@
 	    struct ioc_read_subchannel *args =
 		(struct ioc_read_subchannel *)addr;
 	    struct cd_sub_channel_info data;
+	    u_int8_t format;
+	    int i;
 	    int len = args->data_len;
 	    int32_t abslba, rellba;
 	    int8_t ccb[16] = { ATAPI_READ_SUBCHANNEL, 0, 0x40, 1, 0, 0, 0,
@@ -738,31 +740,108 @@
 		break;
 	    }
 
+	    format=args->data_format;
+	    if ((format != CD_CURRENT_POSITION) &&
+		(format != CD_MEDIA_CATALOG) && (format != CD_TRACK_INFO)) {
+		error = EINVAL;
+		break;
+	    }
+
 	    if ((error = atapi_queue_cmd(cdp->atp, ccb, (caddr_t)&cdp->subchan, 
 					 sizeof(cdp->subchan), ATPR_F_READ, 10,
 					 NULL, NULL))) {
 		break;
 	    }
-	    abslba = cdp->subchan.abslba;
-	    rellba = cdp->subchan.rellba;
-	    if (args->address_format == CD_MSF_FORMAT) {
-		lba2msf(ntohl(abslba),
-		    &data.what.position.absaddr.msf.minute,
-		    &data.what.position.absaddr.msf.second,
-		    &data.what.position.absaddr.msf.frame);
-		lba2msf(ntohl(rellba),
-		    &data.what.position.reladdr.msf.minute,
-		    &data.what.position.reladdr.msf.second,
-		    &data.what.position.reladdr.msf.frame);
-	    } else {
-		data.what.position.absaddr.lba = abslba;
-		data.what.position.reladdr.lba = rellba;
+
+	    /*
+	     * Ask for media catalogue or track info only if no audio play
+	     * operation is in progress or the drive will return an error.
+	     */
+
+	    if ((format == CD_MEDIA_CATALOG) || (format == CD_TRACK_INFO)) {
+		if (cdp->subchan.header.audio_status == 0x11) {
+		    error = EINVAL;
+		    break;
+		}
+
+		ccb[3] = format;
+		if (format == CD_TRACK_INFO)
+		    ccb[6] = args->track;
+
+		if ((error = atapi_queue_cmd(cdp->atp, ccb,
+					     (caddr_t)&cdp->subchan, 
+					     sizeof(cdp->subchan), ATPR_F_READ,
+					     10, NULL, NULL))) {
+		    break;
+		}
+	    }
+
+	    data.header.audio_status = cdp->subchan.header.audio_status;
+	    data.header.data_len[0] = cdp->subchan.header.data_length >> 8;
+	    data.header.data_len[1] = cdp->subchan.header.data_length & 255;
+
+	    switch (format) {
+	    case CD_CURRENT_POSITION:
+		{
+		    abslba = cdp->subchan.what.position.abslba;
+		    rellba = cdp->subchan.what.position.rellba;
+		    if (args->address_format == CD_MSF_FORMAT) {
+			lba2msf(ntohl(abslba),
+			    &data.what.position.absaddr.msf.minute,
+			    &data.what.position.absaddr.msf.second,
+			    &data.what.position.absaddr.msf.frame);
+			lba2msf(ntohl(rellba - 150),
+			    &data.what.position.reladdr.msf.minute,
+			    &data.what.position.reladdr.msf.second,
+			    &data.what.position.reladdr.msf.frame);
+		    } else {
+			data.what.position.absaddr.lba = abslba;
+			data.what.position.reladdr.lba = rellba;
+		    }
+		    data.what.position.data_format =
+			cdp->subchan.what.position.data_format;
+		    data.what.position.control =
+			cdp->subchan.what.position.control & 0xf;
+		    data.what.position.addr_type =
+			cdp->subchan.what.position.control >> 4;
+		    data.what.position.track_number =
+			cdp->subchan.what.position.track;
+		    data.what.position.index_number =
+			cdp->subchan.what.position.indx;
+		    break;
+		}
+
+	    case CD_MEDIA_CATALOG:
+		{
+		    data.what.media_catalog.data_format =
+			cdp->subchan.what.media_catalog.data_format;
+		    data.what.media_catalog.mc_valid =
+			cdp->subchan.what.media_catalog.mc_valid;
+		    for(i = 0; i < 15; i++)
+			    data.what.media_catalog.mc_number[i] =
+				cdp->subchan.what.media_catalog.mc_number[i];
+		    break;
+		}
+		
+	    case CD_TRACK_INFO:
+		{
+		    data.what.track_info.data_format =
+			cdp->subchan.what.track_info.data_format;
+		    data.what.track_info.control =
+			cdp->subchan.what.track_info.control & 0xf;
+		    data.what.track_info.addr_type =
+			cdp->subchan.what.track_info.control >> 4;
+		    data.what.track_info.track_number =
+			cdp->subchan.what.track_info.track;
+		    data.what.track_info.ti_valid =
+			cdp->subchan.what.track_info.ti_valid;
+		    for(i = 0; i < 15; i++)
+			    data.what.track_info.ti_number[i] =
+				cdp->subchan.what.track_info.ti_number[i];
+		    break;
+
+		}
 	    }
-	    data.header.audio_status = cdp->subchan.audio_status;
-	    data.what.position.control = cdp->subchan.control & 0xf;
-	    data.what.position.addr_type = cdp->subchan.control >> 4;
-	    data.what.position.track_number = cdp->subchan.track;
-	    data.what.position.index_number = cdp->subchan.indx;
 	    error = copyout(&data, args->data, len);
 	    break;
 	}
Index: atapi-cd.h
===================================================================
RCS file: /ncvs/src/sys/dev/ata/atapi-cd.h,v
retrieving revision 1.25
diff -u -r1.25 atapi-cd.h
--- atapi-cd.h	2001/03/21 14:59:38	1.25
+++ atapi-cd.h	2001/04/17 10:19:46
@@ -311,16 +311,40 @@
     struct audiopage		au;		/* audio page info */
     struct audiopage		aumask;		/* audio page mask */
     struct cappage		cap;		/* capabilities page info */
-    struct {					/* subchannel info */
-	u_int8_t	void0;
-	u_int8_t	audio_status;
-	u_int16_t	data_length;
-	u_int8_t	data_format;
-	u_int8_t	control;
-	u_int8_t	track;
-	u_int8_t	indx;
-	u_int32_t	abslba;
-	u_int32_t	rellba;
+    struct {
+	struct {
+		u_int8_t	void0;
+		u_int8_t	audio_status;
+		u_int16_t	data_length;
+	} header;
+	union {					/* subchannel info */
+	    struct {
+		u_int8_t	data_format;
+		u_int8_t	control;
+		u_int8_t	track;
+		u_int8_t	indx;
+		u_int32_t	abslba;
+		u_int32_t	rellba;
+	    } position;
+	    struct {
+		u_int8_t	data_format;
+		u_int8_t	:8;
+		u_int8_t	:8;
+		u_int8_t	:8;
+		u_int8_t	:7;
+		u_int8_t	mc_valid:1;
+		u_int8_t	mc_number[15];
+	    } media_catalog;
+	    struct {
+		u_int8_t	data_format;
+		u_int8_t	control;
+		u_int8_t	track;
+		u_int8_t	:8;
+		u_int8_t	:7;
+		u_int8_t	ti_valid:1;
+		u_int8_t	ti_number[15];
+	    } track_info;
+	} what;
     } subchan;
     struct changer		*changer_info;	/* changer info */
     struct acd_softc		**driver;	/* softc's of changer slots */





Index: atapi-cd.c
===================================================================
RCS file: /ncvs/src/sys/dev/ata/atapi-cd.c,v
retrieving revision 1.88
diff -u -r1.88 atapi-cd.c
--- atapi-cd.c	2001/04/05 11:17:33	1.88
+++ atapi-cd.c	2001/04/17 12:25:23
@@ -725,45 +725,57 @@
 	{
 	    struct ioc_read_subchannel *args =
 		(struct ioc_read_subchannel *)addr;
-	    struct cd_sub_channel_info data;
+	    u_int8_t format;
 	    int len = args->data_len;
-	    int32_t abslba, rellba;
 	    int8_t ccb[16] = { ATAPI_READ_SUBCHANNEL, 0, 0x40, 1, 0, 0, 0,
 			       sizeof(cdp->subchan)>>8, sizeof(cdp->subchan),
 			       0, 0, 0, 0, 0, 0, 0 };
 
-	    if (len > sizeof(data) ||
+	    if (len > sizeof(struct cd_sub_channel_info) ||
 		len < sizeof(struct cd_sub_channel_header)) {
 		error = EINVAL;
 		break;
 	    }
 
+	    format=args->data_format;
+	    if ((format != CD_CURRENT_POSITION) &&
+		(format != CD_MEDIA_CATALOG) && (format != CD_TRACK_INFO)) {
+		error = EINVAL;
+		break;
+	    }
+
+	    ccb[1] = args->address_format & CD_MSF_FORMAT;
+
 	    if ((error = atapi_queue_cmd(cdp->atp, ccb, (caddr_t)&cdp->subchan, 
 					 sizeof(cdp->subchan), ATPR_F_READ, 10,
 					 NULL, NULL))) {
 		break;
 	    }
-	    abslba = cdp->subchan.abslba;
-	    rellba = cdp->subchan.rellba;
-	    if (args->address_format == CD_MSF_FORMAT) {
-		lba2msf(ntohl(abslba),
-		    &data.what.position.absaddr.msf.minute,
-		    &data.what.position.absaddr.msf.second,
-		    &data.what.position.absaddr.msf.frame);
-		lba2msf(ntohl(rellba),
-		    &data.what.position.reladdr.msf.minute,
-		    &data.what.position.reladdr.msf.second,
-		    &data.what.position.reladdr.msf.frame);
-	    } else {
-		data.what.position.absaddr.lba = abslba;
-		data.what.position.reladdr.lba = rellba;
+
+	    /*
+	     * Ask for media catalogue or track info only if no audio play
+	     * operation is in progress or the drive will return an error.
+	     */
+
+	    if ((format == CD_MEDIA_CATALOG) || (format == CD_TRACK_INFO)) {
+		if (cdp->subchan.header.audio_status == 0x11) {
+		    error = EINVAL;
+		    break;
+		}
+
+		ccb[3] = format;
+		if (format == CD_TRACK_INFO)
+		    ccb[6] = args->track;
+
+		if ((error = atapi_queue_cmd(cdp->atp, ccb,
+					     (caddr_t)&cdp->subchan, 
+					     sizeof(cdp->subchan), ATPR_F_READ,
+					     10, NULL, NULL))) {
+		    break;
+		}
 	    }
-	    data.header.audio_status = cdp->subchan.audio_status;
-	    data.what.position.control = cdp->subchan.control & 0xf;
-	    data.what.position.addr_type = cdp->subchan.control >> 4;
-	    data.what.position.track_number = cdp->subchan.track;
-	    data.what.position.index_number = cdp->subchan.indx;
-	    error = copyout(&data, args->data, len);
+
+	    error = copyout(&cdp->subchan, args->data, len);
 	    break;
 	}
 
Index: atapi-cd.h
===================================================================
RCS file: /ncvs/src/sys/dev/ata/atapi-cd.h,v
retrieving revision 1.25
diff -u -r1.25 atapi-cd.h
--- atapi-cd.h	2001/03/21 14:59:38	1.25
+++ atapi-cd.h	2001/04/17 10:19:46
@@ -311,16 +311,40 @@
     struct audiopage		au;		/* audio page info */
     struct audiopage		aumask;		/* audio page mask */
     struct cappage		cap;		/* capabilities page info */
-    struct {					/* subchannel info */
-	u_int8_t	void0;
-	u_int8_t	audio_status;
-	u_int16_t	data_length;
-	u_int8_t	data_format;
-	u_int8_t	control;
-	u_int8_t	track;
-	u_int8_t	indx;
-	u_int32_t	abslba;
-	u_int32_t	rellba;
+    struct {
+	struct {
+		u_int8_t	void0;
+		u_int8_t	audio_status;
+		u_int16_t	data_length;
+	} header;
+	union {					/* subchannel info */
+	    struct {
+		u_int8_t	data_format;
+		u_int8_t	control;
+		u_int8_t	track;
+		u_int8_t	indx;
+		u_int32_t	abslba;
+		u_int32_t	rellba;
+	    } position;
+	    struct {
+		u_int8_t	data_format;
+		u_int8_t	:8;
+		u_int8_t	:8;
+		u_int8_t	:8;
+		u_int8_t	:7;
+		u_int8_t	mc_valid:1;
+		u_int8_t	mc_number[15];
+	    } media_catalog;
+	    struct {
+		u_int8_t	data_format;
+		u_int8_t	control;
+		u_int8_t	track;
+		u_int8_t	:8;
+		u_int8_t	:7;
+		u_int8_t	ti_valid:1;
+		u_int8_t	ti_number[15];
+	    } track_info;
+	} what;
     } subchan;
     struct changer		*changer_info;	/* changer info */
     struct acd_softc		**driver;	/* softc's of changer slots */
>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->sos 
Responsible-Changed-By: roam 
Responsible-Changed-When: Tue Apr 17 06:38:55 PDT 2001 
Responsible-Changed-Why:  
Over to Mr. ATA :) 

http://www.freebsd.org/cgi/query-pr.cgi?pr=26644 

From: Philipp Mergenthaler <philipp.mergenthaler@stud.uni-karlsruhe.de>
To: freebsd-gnats-submit@FreeBSD.org
Cc:  
Subject: Re: kern/26644: [PATCH] ATA/ATAPI driver doesn't implement CDIOCREADSUBCHANNEL correctly
Date: Sun, 29 Apr 2001 18:49:10 +0200

 Oops, the first patch should also include the following change. Sorry.
 
 Bye, Philipp
 
 
 Index: cdio.h
 ===================================================================
 RCS file: /ncvs/src/sys/sys/cdio.h,v
 retrieving revision 1.21
 diff -r1.21 cdio.h
 88c88,89
 <         u_int   :8;
 ---
 > 	u_int	control:4;
 > 	u_int	addr_type:4;

From: Philipp Mergenthaler <philipp.mergenthaler@stud.uni-karlsruhe.de>
To: freebsd-gnats-submit@FreeBSD.org
Cc:  
Subject: Re: kern/26644 [PATCH] ATA/ATAPI driver doesn't implement CDIOCREADSUBCHANNEL correctly
Date: Wed, 27 Feb 2002 20:21:50 +0100

 These are updates of the original patches in the PR, since those don't
 apply cleanly anymore.  Also, the second issue in that PR (wrong time
 computation) is mood; it was probably a bug in my old CD-ROM drive.
 
 The two patch sets are alternative: The first one tries to stay with the
 current style, it copies all structure members separately.
 The second patch set copies the data directly from cdp->subchan to the
 userland (similiar to what the SCSI-driver does).
 
 The patches to atapi-cd.h should be orthogonal to those to atapi-cd.c,
 though I haven't tested that.
 
 
 
 Index: sys/dev/ata/atapi-cd.c
 ===================================================================
 RCS file: /ncvs/src/sys/dev/ata/atapi-cd.c,v
 retrieving revision 1.109
 diff -u -r1.109 atapi-cd.c
 --- sys/dev/ata/atapi-cd.c	15 Feb 2002 07:08:44 -0000	1.109
 +++ sys/dev/ata/atapi-cd.c	27 Feb 2002 18:57:23 -0000
 @@ -711,6 +711,8 @@
  	    struct ioc_read_subchannel *args =
  		(struct ioc_read_subchannel *)addr;
  	    struct cd_sub_channel_info *data;
 +	    u_int8_t format;
 +	    int i;
  	    int8_t ccb[16] = { ATAPI_READ_SUBCHANNEL, 0, 0x40, 1, 0, 0, 0,
  			       sizeof(cdp->subchan)>>8, sizeof(cdp->subchan),
  			       0, 0, 0, 0, 0, 0, 0 };
 @@ -718,6 +720,13 @@
  	    if (args->data_len > sizeof(struct cd_sub_channel_info) ||
  		args->data_len < sizeof(struct cd_sub_channel_header)) {
  		error = EINVAL;
 + 		break;
 + 	    }
 +
 +	    format=args->data_format;
 +	    if ((format != CD_CURRENT_POSITION) &&
 +		(format != CD_MEDIA_CATALOG) && (format != CD_TRACK_INFO)) {
 +		error = EINVAL;
  		break;
  	    }
  
 @@ -726,27 +735,100 @@
  					 NULL, NULL))) {
  		break;
  	    }
 +
 +	    /*
 +	     * Ask for media catalogue or track info only if no audio play
 +	     * operation is in progress or the drive will return an error.
 +	     */
 +
 +	    if ((format == CD_MEDIA_CATALOG) || (format == CD_TRACK_INFO)) {
 +		if (cdp->subchan.header.audio_status == 0x11) {
 +		    error = EINVAL;
 +		    break;
 +		}
 +
 +		ccb[3] = format;
 +		if (format == CD_TRACK_INFO)
 +		    ccb[6] = args->track;
 +
 +		if ((error = atapi_queue_cmd(cdp->device, ccb,
 +					     (caddr_t)&cdp->subchan, 
 +					     sizeof(cdp->subchan), ATPR_F_READ,
 +					     10, NULL, NULL))) {
 +		    break;
 +		}
 +	    }
 +
  	    data = malloc(sizeof(struct cd_sub_channel_info),
  			  M_ACD, M_NOWAIT | M_ZERO);
  
 -	    if (args->address_format == CD_MSF_FORMAT) {
 -		lba2msf(ntohl(cdp->subchan.abslba),
 -		    &data->what.position.absaddr.msf.minute,
 -		    &data->what.position.absaddr.msf.second,
 -		    &data->what.position.absaddr.msf.frame);
 -		lba2msf(ntohl(cdp->subchan.rellba),
 -		    &data->what.position.reladdr.msf.minute,
 -		    &data->what.position.reladdr.msf.second,
 -		    &data->what.position.reladdr.msf.frame);
 -	    } else {
 -		data->what.position.absaddr.lba = cdp->subchan.abslba;
 -		data->what.position.reladdr.lba = cdp->subchan.rellba;
 -	    }
 -	    data->header.audio_status = cdp->subchan.audio_status;
 -	    data->what.position.control = cdp->subchan.control & 0xf;
 -	    data->what.position.addr_type = cdp->subchan.control >> 4;
 -	    data->what.position.track_number = cdp->subchan.track;
 -	    data->what.position.index_number = cdp->subchan.indx;
 +	    data->header.audio_status = cdp->subchan.header.audio_status;
 +	    data->header.data_len[0] = cdp->subchan.header.data_length >> 8;
 +	    data->header.data_len[1] = cdp->subchan.header.data_length & 255;
 +
 +	    switch (format) {
 +	    case CD_CURRENT_POSITION:
 +		{
 +		    if (args->address_format == CD_MSF_FORMAT) {
 +			lba2msf(ntohl(cdp->subchan.what.position.abslba),
 +			    &data->what.position.absaddr.msf.minute,
 +			    &data->what.position.absaddr.msf.second,
 +			    &data->what.position.absaddr.msf.frame);
 +			lba2msf(ntohl(cdp->subchan.what.position.rellba),
 +			    &data->what.position.reladdr.msf.minute,
 +			    &data->what.position.reladdr.msf.second,
 +			    &data->what.position.reladdr.msf.frame);
 +		    } else {
 +			data->what.position.absaddr.lba =
 +			    cdp->subchan.what.position.abslba;
 +			data->what.position.reladdr.lba =
 +				cdp->subchan.what.position.rellba;
 +		    }
 +		    data->what.position.data_format =
 +			cdp->subchan.what.position.data_format;
 +		    data->what.position.control =
 +			cdp->subchan.what.position.control & 0xf;
 +		    data->what.position.addr_type =
 +			cdp->subchan.what.position.control >> 4;
 +		    data->what.position.track_number =
 +			cdp->subchan.what.position.track;
 +		    data->what.position.index_number =
 +			cdp->subchan.what.position.indx;
 +		    break;
 +		}
 +
 +	    case CD_MEDIA_CATALOG:
 +		{
 +		    data->what.media_catalog.data_format =
 +			cdp->subchan.what.media_catalog.data_format;
 +		    data->what.media_catalog.mc_valid =
 +			cdp->subchan.what.media_catalog.mc_valid;
 +		    for(i = 0; i < 15; i++)
 +			    data->what.media_catalog.mc_number[i] =
 +				cdp->subchan.what.media_catalog.mc_number[i];
 +		    break;
 +		}
 +
 +	    case CD_TRACK_INFO:
 +		{
 +		    data->what.track_info.data_format =
 +			cdp->subchan.what.track_info.data_format;
 +		    data->what.track_info.control =
 +			cdp->subchan.what.track_info.control & 0xf;
 +		    data->what.track_info.addr_type =
 +			cdp->subchan.what.track_info.control >> 4;
 +		    data->what.track_info.track_number =
 +			cdp->subchan.what.track_info.track;
 +		    data->what.track_info.ti_valid =
 +			cdp->subchan.what.track_info.ti_valid;
 +		    for(i = 0; i < 15; i++)
 +			    data->what.track_info.ti_number[i] =
 +				cdp->subchan.what.track_info.ti_number[i];
 +		    break;
 +
 +		}
 + 	    }
 +
  	    error = copyout(data, args->data, args->data_len);
  	    free(data, M_ACD);
  	    break;
 Index: sys/dev/ata/atapi-cd.h
 ===================================================================
 RCS file: /ncvs/src/sys/dev/ata/atapi-cd.h,v
 retrieving revision 1.29
 diff -u -r1.29 atapi-cd.h
 --- sys/dev/ata/atapi-cd.h	4 Feb 2002 19:23:40 -0000	1.29
 +++ sys/dev/ata/atapi-cd.h	27 Feb 2002 18:33:11 -0000
 @@ -316,16 +316,40 @@
      struct audiopage		au;		/* audio page info */
      struct audiopage		aumask;		/* audio page mask */
      struct cappage		cap;		/* capabilities page info */
 -    struct {					/* subchannel info */
 -	u_int8_t	void0;
 -	u_int8_t	audio_status;
 -	u_int16_t	data_length;
 -	u_int8_t	data_format;
 -	u_int8_t	control;
 -	u_int8_t	track;
 -	u_int8_t	indx;
 -	u_int32_t	abslba;
 -	u_int32_t	rellba;
 +    struct {
 +	struct {
 +		u_int8_t	void0;
 +		u_int8_t	audio_status;
 +		u_int16_t	data_length;
 +	} header;
 +	union {					/* subchannel info */
 +	    struct {
 +		u_int8_t	data_format;
 +		u_int8_t	control;
 +		u_int8_t	track;
 +		u_int8_t	indx;
 +		u_int32_t	abslba;
 +		u_int32_t	rellba;
 +	    } position;
 +	    struct {
 +		u_int8_t	data_format;
 +		u_int8_t	:8;
 +		u_int8_t	:8;
 +		u_int8_t	:8;
 +		u_int8_t	:7;
 +		u_int8_t	mc_valid:1;
 +		u_int8_t	mc_number[15];
 +	    } media_catalog;
 +	    struct {
 +		u_int8_t	data_format;
 +		u_int8_t	control;
 +		u_int8_t	track;
 +		u_int8_t	:8;
 +		u_int8_t	:7;
 +		u_int8_t	ti_valid:1;
 +		u_int8_t	ti_number[15];
 +	    } track_info;
 +	} what;
      } subchan;
      struct changer		*changer_info;	/* changer info */
      struct acd_softc		**driver;	/* softc's of changer slots */
 Index: sys/sys/cdio.h
 ===================================================================
 RCS file: /ncvs/src/sys/sys/cdio.h,v
 retrieving revision 1.22
 diff -u -r1.22 cdio.h
 --- sys/sys/cdio.h	5 Sep 2001 01:22:14 -0000	1.22
 +++ sys/sys/cdio.h	21 Feb 2002 00:10:27 -0000
 @@ -85,7 +85,8 @@
  
  struct cd_sub_channel_track_info {
          u_char  data_format;
 -        u_int   :8;
 +	u_int	control:4;
 +	u_int	addr_type:4;
          u_char  track_number;
          u_int   :8;
          u_int   :7;
 
 
 
 
 
 
 ---------------- Second patch set: ------------------------
 
 
 
 
 Index: sys/dev/ata/atapi-cd.c
 ===================================================================
 RCS file: /ncvs/src/sys/dev/ata/atapi-cd.c,v
 retrieving revision 1.109
 diff -u -r1.109 atapi-cd.c
 --- sys/dev/ata/atapi-cd.c	15 Feb 2002 07:08:44 -0000	1.109
 +++ sys/dev/ata/atapi-cd.c	27 Feb 2002 18:11:09 -0000
 @@ -710,7 +710,7 @@
  	{
  	    struct ioc_read_subchannel *args =
  		(struct ioc_read_subchannel *)addr;
 -	    struct cd_sub_channel_info *data;
 +	    u_int8_t format;
  	    int8_t ccb[16] = { ATAPI_READ_SUBCHANNEL, 0, 0x40, 1, 0, 0, 0,
  			       sizeof(cdp->subchan)>>8, sizeof(cdp->subchan),
  			       0, 0, 0, 0, 0, 0, 0 };
 @@ -721,34 +721,45 @@
  		break;
  	    }
  
 +	    format=args->data_format;
 +	    if ((format != CD_CURRENT_POSITION) &&
 +		(format != CD_MEDIA_CATALOG) && (format != CD_TRACK_INFO)) {
 +		error = EINVAL;
 +		break;
 +	    }
 +
 +	    ccb[1] = args->address_format & CD_MSF_FORMAT;
 +
  	    if ((error = atapi_queue_cmd(cdp->device,ccb,(caddr_t)&cdp->subchan,
  					 sizeof(cdp->subchan), ATPR_F_READ, 10,
  					 NULL, NULL))) {
  		break;
  	    }
 -	    data = malloc(sizeof(struct cd_sub_channel_info),
 -			  M_ACD, M_NOWAIT | M_ZERO);
  
 -	    if (args->address_format == CD_MSF_FORMAT) {
 -		lba2msf(ntohl(cdp->subchan.abslba),
 -		    &data->what.position.absaddr.msf.minute,
 -		    &data->what.position.absaddr.msf.second,
 -		    &data->what.position.absaddr.msf.frame);
 -		lba2msf(ntohl(cdp->subchan.rellba),
 -		    &data->what.position.reladdr.msf.minute,
 -		    &data->what.position.reladdr.msf.second,
 -		    &data->what.position.reladdr.msf.frame);
 -	    } else {
 -		data->what.position.absaddr.lba = cdp->subchan.abslba;
 -		data->what.position.reladdr.lba = cdp->subchan.rellba;
 +	    /*
 +	     * Ask for media catalogue or track info only if no audio play
 +	     * operation is in progress or the drive will return an error.
 +	     */
 +
 +	    if ((format == CD_MEDIA_CATALOG) || (format == CD_TRACK_INFO)) {
 +		if (cdp->subchan.header.audio_status == 0x11) {
 +		    error = EINVAL;
 +		    break;
 +		}
 +
 +		ccb[3] = format;
 +		if (format == CD_TRACK_INFO)
 +		    ccb[6] = args->track;
 +
 +		if ((error = atapi_queue_cmd(cdp->device, ccb,
 +					     (caddr_t)&cdp->subchan, 
 +					     sizeof(cdp->subchan), ATPR_F_READ,
 +					     10, NULL, NULL))) {
 +		    break;
 +		}
  	    }
 -	    data->header.audio_status = cdp->subchan.audio_status;
 -	    data->what.position.control = cdp->subchan.control & 0xf;
 -	    data->what.position.addr_type = cdp->subchan.control >> 4;
 -	    data->what.position.track_number = cdp->subchan.track;
 -	    data->what.position.index_number = cdp->subchan.indx;
 -	    error = copyout(data, args->data, args->data_len);
 -	    free(data, M_ACD);
 +
 +	    error = copyout(&cdp->subchan, args->data, args->data_len);
  	    break;
  	}
  
 Index: sys/dev/ata/atapi-cd.h
 ===================================================================
 RCS file: /ncvs/src/sys/dev/ata/atapi-cd.h,v
 retrieving revision 1.29
 diff -u -r1.29 atapi-cd.h
 --- sys/dev/ata/atapi-cd.h	4 Feb 2002 19:23:40 -0000	1.29
 +++ sys/dev/ata/atapi-cd.h	27 Feb 2002 17:48:02 -0000
 @@ -316,17 +316,7 @@
      struct audiopage		au;		/* audio page info */
      struct audiopage		aumask;		/* audio page mask */
      struct cappage		cap;		/* capabilities page info */
 -    struct {					/* subchannel info */
 -	u_int8_t	void0;
 -	u_int8_t	audio_status;
 -	u_int16_t	data_length;
 -	u_int8_t	data_format;
 -	u_int8_t	control;
 -	u_int8_t	track;
 -	u_int8_t	indx;
 -	u_int32_t	abslba;
 -	u_int32_t	rellba;
 -    } subchan;
 +    struct cd_sub_channel_info	subchan;	/* from sys/cdio.h. */
      struct changer		*changer_info;	/* changer info */
      struct acd_softc		**driver;	/* softc's of changer slots */
      int				slot;		/* this instance slot number */
State-Changed-From-To: open->closed 
State-Changed-By: sos 
State-Changed-When: Sat Mar 16 09:02:30 PST 2002 
State-Changed-Why:  
Second patch committed to -current, MFC shortly. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=26644 
>Unformatted:
