Browse Source

Plan 9 from Bell Labs 2008-03-11

David du Colombier 13 years ago
parent
commit
5353d592a4

+ 10 - 10
dist/replica/_plan9.db

@@ -181,7 +181,7 @@
 386/bin/cleanname - 775 sys sys 1168402295 58541
 386/bin/clock - 775 sys sys 1197732691 157356
 386/bin/cmp - 775 sys sys 1157597609 40658
-386/bin/col - 775 sys sys 1172029864 64995
+386/bin/col - 775 sys sys 1205206380 63487
 386/bin/colors - 775 sys sys 1197732695 151031
 386/bin/comm - 775 sys sys 1168402296 61586
 386/bin/compress - 775 sys sys 1184529900 167036
@@ -5633,7 +5633,7 @@ rc/bin/stop - 775 sys sys 945617209 110
 rc/bin/tel - 775 sys sys 1161209756 128
 rc/bin/termrc - 775 sys sys 1179769653 2479
 rc/bin/termrc.local - 775 sys sys 1176500067 425
-rc/bin/thesaurus - 775 sys sys 1068054167 246
+rc/bin/thesaurus - 775 sys sys 1205183987 422
 rc/bin/tlsclienttunnel - 775 sys sys 1024375633 153
 rc/bin/tlssrvtunnel - 775 sys sys 1024375634 175
 rc/bin/troff2gif - 775 sys sys 1127410278 164
@@ -7721,7 +7721,7 @@ sys/man/4/INDEX - 664 sys sys 1196638942 1026
 sys/man/4/INDEX.html - 664 sys sys 1196638942 5147
 sys/man/4/acme - 664 sys sys 1196638943 10435
 sys/man/4/archfs - 664 sys sys 1196638943 533
-sys/man/4/cdfs - 664 sys sys 1196638943 3638
+sys/man/4/cdfs - 664 sys sys 1205203382 4352
 sys/man/4/cfs - 664 sys sys 1196638943 2136
 sys/man/4/consolefs - 664 sys sys 1196638943 4389
 sys/man/4/cwfs - 664 sys sys 1196638943 6553
@@ -8187,7 +8187,7 @@ sys/src/9/pc/uarti8250.c - 664 sys sys 1177676872 13957
 sys/src/9/pc/uartisa.c - 664 sys sys 1127126907 1777
 sys/src/9/pc/uartpci.c - 664 sys sys 1190235592 4685
 sys/src/9/pc/usb.h - 664 sys sys 1202865355 4630
-sys/src/9/pc/usbohci.c - 664 sys sys 1203981402 49005
+sys/src/9/pc/usbohci.c - 664 sys sys 1205184193 49042
 sys/src/9/pc/usbuhci.c - 664 sys sys 1202252076 31839
 sys/src/9/pc/vga.c - 664 sys sys 1131290595 5148
 sys/src/9/pc/vga3dfx.c - 664 sys sys 1133218367 3833
@@ -10015,12 +10015,12 @@ sys/src/cmd/cc/scon.c - 664 sys sys 1138463621 8788
 sys/src/cmd/cc/sub.c - 664 sys sys 1143759345 34268
 sys/src/cmd/cc/y.tab.h - 664 sys sys 1098501521 1680
 sys/src/cmd/cdfs - 20000000775 sys sys 1039727558 0
-sys/src/cmd/cdfs/buf.c - 664 sys sys 964456822 1848
-sys/src/cmd/cdfs/dat.h - 664 sys sys 1204937945 2834
+sys/src/cmd/cdfs/buf.c - 664 sys sys 1205203460 1851
+sys/src/cmd/cdfs/dat.h - 664 sys sys 1205203455 3753
 sys/src/cmd/cdfs/fns.h - 664 sys sys 969542122 297
-sys/src/cmd/cdfs/main.c - 664 sys sys 1204937969 11147
+sys/src/cmd/cdfs/main.c - 664 sys sys 1205203482 11360
 sys/src/cmd/cdfs/mkfile - 664 sys sys 1204937991 153
-sys/src/cmd/cdfs/mmc.c - 664 sys sys 1204938193 20926
+sys/src/cmd/cdfs/mmc.c - 664 sys sys 1205203566 26493
 sys/src/cmd/cec - 20000000775 sys sys 1193683647 0
 sys/src/cmd/cec/LICENSE - 664 sys sys 1186248056 1554
 sys/src/cmd/cec/Protocol - 664 sys sys 1186248056 2881
@@ -10051,7 +10051,7 @@ sys/src/cmd/chmod.c - 664 sys sys 1079372923 1904
 sys/src/cmd/cleanname.c - 664 sys sys 944960760 715
 sys/src/cmd/clock.c - 664 sys sys 1014925410 1881
 sys/src/cmd/cmp.c - 664 sys sys 1157581072 2491
-sys/src/cmd/col.c - 664 sys sys 1172005084 3850
+sys/src/cmd/col.c - 664 sys sys 1205188047 3850
 sys/src/cmd/colors.c - 664 sys sys 951763912 3186
 sys/src/cmd/comm.c - 664 sys sys 1093979717 2140
 sys/src/cmd/compress - 20000000775 sys sys 1157679448 0
@@ -13614,7 +13614,7 @@ sys/src/cmd/troff/ext.h - 664 sys sys 1116904533 3491
 sys/src/cmd/troff/find - 775 sys sys 944961293 15
 sys/src/cmd/troff/fns.h - 664 sys sys 944961293 7329
 sys/src/cmd/troff/hytab.c - 664 sys sys 944961293 7232
-sys/src/cmd/troff/mkfile - 664 sys sys 1019509075 1034
+sys/src/cmd/troff/mkfile - 664 sys sys 1205186908 1034
 sys/src/cmd/troff/n1.c - 664 sys sys 960145286 20246
 sys/src/cmd/troff/n10.c - 664 sys sys 944961293 11564
 sys/src/cmd/troff/n2.c - 664 sys sys 961261288 5031

+ 10 - 10
dist/replica/plan9.db

@@ -181,7 +181,7 @@
 386/bin/cleanname - 775 sys sys 1168402295 58541
 386/bin/clock - 775 sys sys 1197732691 157356
 386/bin/cmp - 775 sys sys 1157597609 40658
-386/bin/col - 775 sys sys 1172029864 64995
+386/bin/col - 775 sys sys 1205206380 63487
 386/bin/colors - 775 sys sys 1197732695 151031
 386/bin/comm - 775 sys sys 1168402296 61586
 386/bin/compress - 775 sys sys 1184529900 167036
@@ -5633,7 +5633,7 @@ rc/bin/stop - 775 sys sys 945617209 110
 rc/bin/tel - 775 sys sys 1161209756 128
 rc/bin/termrc - 775 sys sys 1179769653 2479
 rc/bin/termrc.local - 775 sys sys 1176500067 425
-rc/bin/thesaurus - 775 sys sys 1068054167 246
+rc/bin/thesaurus - 775 sys sys 1205183987 422
 rc/bin/tlsclienttunnel - 775 sys sys 1024375633 153
 rc/bin/tlssrvtunnel - 775 sys sys 1024375634 175
 rc/bin/troff2gif - 775 sys sys 1127410278 164
@@ -7721,7 +7721,7 @@ sys/man/4/INDEX - 664 sys sys 1196638942 1026
 sys/man/4/INDEX.html - 664 sys sys 1196638942 5147
 sys/man/4/acme - 664 sys sys 1196638943 10435
 sys/man/4/archfs - 664 sys sys 1196638943 533
-sys/man/4/cdfs - 664 sys sys 1196638943 3638
+sys/man/4/cdfs - 664 sys sys 1205203382 4352
 sys/man/4/cfs - 664 sys sys 1196638943 2136
 sys/man/4/consolefs - 664 sys sys 1196638943 4389
 sys/man/4/cwfs - 664 sys sys 1196638943 6553
@@ -8187,7 +8187,7 @@ sys/src/9/pc/uarti8250.c - 664 sys sys 1177676872 13957
 sys/src/9/pc/uartisa.c - 664 sys sys 1127126907 1777
 sys/src/9/pc/uartpci.c - 664 sys sys 1190235592 4685
 sys/src/9/pc/usb.h - 664 sys sys 1202865355 4630
-sys/src/9/pc/usbohci.c - 664 sys sys 1203981402 49005
+sys/src/9/pc/usbohci.c - 664 sys sys 1205184193 49042
 sys/src/9/pc/usbuhci.c - 664 sys sys 1202252076 31839
 sys/src/9/pc/vga.c - 664 sys sys 1131290595 5148
 sys/src/9/pc/vga3dfx.c - 664 sys sys 1133218367 3833
@@ -10015,12 +10015,12 @@ sys/src/cmd/cc/scon.c - 664 sys sys 1138463621 8788
 sys/src/cmd/cc/sub.c - 664 sys sys 1143759345 34268
 sys/src/cmd/cc/y.tab.h - 664 sys sys 1098501521 1680
 sys/src/cmd/cdfs - 20000000775 sys sys 1039727558 0
-sys/src/cmd/cdfs/buf.c - 664 sys sys 964456822 1848
-sys/src/cmd/cdfs/dat.h - 664 sys sys 1204937945 2834
+sys/src/cmd/cdfs/buf.c - 664 sys sys 1205203460 1851
+sys/src/cmd/cdfs/dat.h - 664 sys sys 1205203455 3753
 sys/src/cmd/cdfs/fns.h - 664 sys sys 969542122 297
-sys/src/cmd/cdfs/main.c - 664 sys sys 1204937969 11147
+sys/src/cmd/cdfs/main.c - 664 sys sys 1205203482 11360
 sys/src/cmd/cdfs/mkfile - 664 sys sys 1204937991 153
-sys/src/cmd/cdfs/mmc.c - 664 sys sys 1204938193 20926
+sys/src/cmd/cdfs/mmc.c - 664 sys sys 1205203566 26493
 sys/src/cmd/cec - 20000000775 sys sys 1193683647 0
 sys/src/cmd/cec/LICENSE - 664 sys sys 1186248056 1554
 sys/src/cmd/cec/Protocol - 664 sys sys 1186248056 2881
@@ -10051,7 +10051,7 @@ sys/src/cmd/chmod.c - 664 sys sys 1079372923 1904
 sys/src/cmd/cleanname.c - 664 sys sys 944960760 715
 sys/src/cmd/clock.c - 664 sys sys 1014925410 1881
 sys/src/cmd/cmp.c - 664 sys sys 1157581072 2491
-sys/src/cmd/col.c - 664 sys sys 1172005084 3850
+sys/src/cmd/col.c - 664 sys sys 1205188047 3850
 sys/src/cmd/colors.c - 664 sys sys 951763912 3186
 sys/src/cmd/comm.c - 664 sys sys 1093979717 2140
 sys/src/cmd/compress - 20000000775 sys sys 1157679448 0
@@ -13614,7 +13614,7 @@ sys/src/cmd/troff/ext.h - 664 sys sys 1116904533 3491
 sys/src/cmd/troff/find - 775 sys sys 944961293 15
 sys/src/cmd/troff/fns.h - 664 sys sys 944961293 7329
 sys/src/cmd/troff/hytab.c - 664 sys sys 944961293 7232
-sys/src/cmd/troff/mkfile - 664 sys sys 1019509075 1034
+sys/src/cmd/troff/mkfile - 664 sys sys 1205186908 1034
 sys/src/cmd/troff/n1.c - 664 sys sys 960145286 20246
 sys/src/cmd/troff/n10.c - 664 sys sys 944961293 11564
 sys/src/cmd/troff/n2.c - 664 sys sys 961261288 5031

+ 10 - 0
dist/replica/plan9.log

@@ -18728,3 +18728,13 @@
 1205010004 2 c sys/src/9/port/master - 664 sys sys 1205009260 507
 1205010004 3 c sys/src/9/port/master.local - 664 sys sys 1205009250 117
 1205037004 0 c 386/bin/auth/cron - 775 sys sys 1205035791 141213
+1205184604 0 c rc/bin/thesaurus - 775 sys sys 1205183987 422
+1205184604 1 c sys/src/9/pc/usbohci.c - 664 sys sys 1205184193 49042
+1205188204 0 c sys/src/cmd/col.c - 664 sys sys 1205188047 3850
+1205188204 1 c sys/src/cmd/troff/mkfile - 664 sys sys 1205186908 1034
+1205204404 0 c sys/man/4/cdfs - 664 sys sys 1205203382 4352
+1205204404 1 c sys/src/cmd/cdfs/buf.c - 664 sys sys 1205203460 1851
+1205204404 2 c sys/src/cmd/cdfs/dat.h - 664 sys sys 1205203455 3753
+1205204404 3 c sys/src/cmd/cdfs/main.c - 664 sys sys 1205203482 11360
+1205204404 4 c sys/src/cmd/cdfs/mmc.c - 664 sys sys 1205203566 26493
+1205208004 0 c 386/bin/col - 775 sys sys 1205206380 63487

+ 22 - 13
rc/bin/thesaurus

@@ -2,19 +2,28 @@
 
 hget 'http://thesaurus.reference.com/search?q='^$1 |
 	htmlfmt -l 1000 |
-	sed -n '
-		1,/^[0-9]+ entries found for/d
-		/ADVERTISEMENT/,$d
-		1,/^$/d
-		s/^Entry://p
-		/^Source:/{
+	sed -n '/^Main Entry:/,/^Source/ {
+		/^Source/ q
+		/^[A-Z].*:/ {
 			N
-			d
+			s/\n/	/g
 		}
-		/^[A-Z][a-z]*:/{
-			N
-			s/\n/	/gp
+		p
+	}' | awk -F', ' '{
+		if(length($0)<=70){
+			print
+			next
 		}
-	'
-
-
+		l = 0
+		for(i = 1; i < NF; i++){
+			printf "%s ", $i
+			l += length($i)+1
+			if(l > 70){
+				printf "\n\t\t"
+				l = 2*ENVIRON["tabstop"]
+			}
+		}
+		if(l>0)
+			printf "\n"
+		next
+	}'

+ 72 - 38
sys/man/4/cdfs

@@ -1,13 +1,12 @@
 .TH CDFS 4
 .SH NAME
-cdfs, cddb \- CD reader and writer file system
+cdfs, cddb \- optical disc (CD, DVD, BD) reader and writer file system
 .SH SYNOPSIS
 .B cdfs
 [
 .B -d
 .I sddev
-]
-[
+] [
 .B -m
 .I mtpt
 ]
@@ -17,8 +16,7 @@ cdfs, cddb \- CD reader and writer file system
 .B aux/cddb
 [
 .B -DTt
-]
-[
+] [
 .B -s
 .I server
 ]
@@ -30,21 +28,24 @@ cdfs, cddb \- CD reader and writer file system
 .SH DESCRIPTION
 .I Cdfs
 serves a one and a half level directory
-mounted at 
+mounted at
 .I mtpt
 (default
 .BR /mnt/cd )
 that provides access to the tracks
-on CDs placed in the CD reader or writer
+on discs placed in the disc reader or writer
 named by
 .I sddev
 (default
 .BR /dev/sdD0 ,
 see
 .IR sd (3)).
+Any MMC-compliant compact disc (CD), DVD,
+or Blu-ray (BD) drive should work.
+On DVD and BD discs, access to data tracks only is implemented.
 .PP
 The top level directory contains one file
-per CD track.
+per disc track.
 The files are named
 .IR cNNN ,
 where
@@ -59,10 +60,9 @@ and
 .I NNN
 is the track number.
 .PP
-If the device is capable of writing CDs
-and contains a writable CD, the top level
-directory also contains two empty
-directories
+If the device is capable of writing discs
+and contains a writable disc, the top level
+directory also contains two empty directories
 .B wa
 and
 .BR wd .
@@ -73,44 +73,53 @@ as new audio or data tracks, regardless of name.
 At any time, any number of tracks
 may be open for reading or a single track
 may be open for writing.
-Writing a CD track is a real-time operation:
-the CD writer must be kept saturated with
+Writing a disc track is a real-time operation:
+the disc writer must be kept saturated with
 new data to avoid buffer underruns.
 To ensure this, copying from a file system
-stored on local disk is recommended.
+stored on local disk or memory is recommended.
 .PP
-To fixate a CD (close a writable CD by writing
+To fixate a disc (close a recordable disc by writing
 its permanent table of contents), simply
-remove the 
+remove the
 .B wa
 or
 .B wd
 directory.
 The directory removed selects whether
-the CD is fixated as an audio or data CD;
+the disc is fixated as an audio or data disc;
 since each track carries its own type information,
 very few readers care which fixation type was used.
+Rewritable discs do not require fixation.
 .PP
 The top level directory
-also contains a 
+also contains a
 .B ctl
 file, into which control messages
 may be echoed.
 The current control messages are:
-.TF "\fLquickblank "
+.TF "\fLquickblan"
+.TP
+.B format
+Format the rewritable disc (\c
+.B -RW
+or
+.BR -RE )
+in the drive
+before initial use.
 .TP
 .B blank
-Blank the entire rewritable CD in the drive.
+Blank the entire rewritable disc in the drive.
 .TP
 .B quickblank
 Blank only the table of contents on the rewritable
-CD in the drive.
+disc in the drive.
 .TP
 .B eject
-Eject the CD in the drive.
+Eject the disc in the drive.
 .TP
 .B ingest
-Ingest a CD into the drive.
+Ingest a disc into the drive.
 .TP
 .B speed \fIkpbs\fR
 Set the reading and writing speed to use.
@@ -131,10 +140,10 @@ or
 .B write
 .BR 8192.
 Note that most drives reset the reading and writing speed
-each time a new CD is inserted.
+each time a new disc is inserted.
 .PD
 .PP
-Reading the 
+Reading the
 .B ctl
 file yields information about the drive.
 If the drive contains an audio CD, the first line
@@ -147,31 +156,40 @@ Subsequent lines contain the current and maximum
 reading and writing speeds.
 .PD
 .PP
-.I Aux/cddb takes 4 optional arguments.
+.I Aux/cddb
+takes 4 optional arguments.
 The
-.B -s server
+.B -s
 option causes
 .I aux/cddb
-to use a different server for the query
+to use a different
+.I server
+for the query
 (default is
-.IR freedb.freedb.org ).
+.LR freedb.freedb.org ).
 The
 .B -D
 option causes the raw database response from the server to be dumped
 to standard output.
 The
-.I -t
+.B -t
 option causes the time of each track to be appended to the normal output.
-.I -T
+.B -T
 is like
-.I -t
+.B -t
 but prints a line with the total time at the end.
 .PD
-.PP
-Only MMC-compliant CD readers and writers
-are supported, but it would be easy to add
-support for early CD writers if desired.
 .SH EXAMPLE
+Backup to a BD-RW disc:
+.IP
+.EX
+9fs boot
+cdfs
+tar cbf /mnt/cd/wd/x /n/boot
+.EE
+.br
+.ne 3
+.PP
 Copy the audio tracks from a CD:
 .IP
 .EX
@@ -190,10 +208,26 @@ rm /mnt/cd/wa
 .SH SOURCE
 .B /sys/src/cmd/cdfs
 .SH SEE ALSO
+.TF "\fLhttp://www.t10.org\fP"
+.TP
+.B http://www.t10.org
+optical disc interface standards
+.PP
+.PD
 .IR sd (3),
 .I 9660srv
 (in
 .IR dossrv (4)),
 .IR mk9660 (8)
 .SH BUGS
-There should be support for DVDs.
+There are too many combinations of optical media, approximately
+the cross-product of these tuples:
+(CD DVD- DVD+ BD),
+(single-layer dual-layer),
+(ROM -R -RW).
+.PP
+Packet (incremental) writing is not yet implemented.
+.PP
+Only MMC-compliant disc readers and writers
+are supported, but it would be easy to add
+support for early CD writers if desired.

+ 4 - 2
sys/src/9/pc/usbohci.c

@@ -1869,6 +1869,9 @@ interrupt(Ureg *, void *arg)
 		case 2:			/* Bitstuff */
 			ep->dir[dirin].err = "Bitstuff error";
 			goto error;
+		case 3:
+			ep->dir[dirin].err = "data toggle mismatch";
+			goto error;
 		case 4:			/* Stall */
 			ep->dir[dirin].err = Estalled;
 			goto error;
@@ -1888,8 +1891,7 @@ interrupt(Ureg *, void *arg)
 			wakeup(&ep->dir[dirin].rend);
 			break;
 		default:
-			panic("cc %lud unimplemented\n",
-				(ctrl >> TD_CC_SHIFT) & TD_CC_MASK);
+			panic("cc %lud unimplemented\n", cc);
 		}
 		ep->dir[dirin].queued--;
 		/* Clean up blocks used for transfers */

+ 1 - 1
sys/src/cmd/cdfs/buf.c

@@ -41,7 +41,7 @@ bread(Buf *b, void *v, long n, long off)
 		noff = off - off % b->bs;
 		if(vflag)
 			fprint(2, "try refill at %ld\n", noff);
-		if((m = b->fn(b, b->data, Nblock, noff/b->bs)) <= 0)
+		if((m = b->fn(b, b->data, b->nblock, noff/b->bs)) <= 0)
 			return m;
 		b->ndata = b->bs * m;
 		b->off = noff;

+ 44 - 7
sys/src/cmd/cdfs/dat.h

@@ -1,12 +1,10 @@
 enum {
 	Maxtrack	= 200,
 	Ntrack		= Maxtrack+1,
-	BScdrom		= 2048,
+	BScdrom		= 2048,		/* mmc data block size */
 	BScdda		= 2352,
 	BScdxa		= 2336,
 	BSmax		= 2352,
-	Nalloc		= 12*BScdda,
-	DictBlock	= 1,
 
 	/* scsi peripheral device types */
 	TypeDA		= 0,		/* Direct Access (SBC) */
@@ -16,6 +14,13 @@ enum {
 	TypeMO		= 7,		/* rewriteable Magneto-Optical (SBC) */
 	TypeMC		= 8,		/* Medium Changer (SMC-2) */
 
+	/* MMC-3 device types */
+	Subtypenone	= 0,
+	Subtypecd,
+	Subtypedvd,
+	Subtypebd,
+
+	/* disc or track types */
 	TypeNone	= 0,
 	TypeAudio,
 	TypeAwritable,
@@ -24,7 +29,29 @@ enum {
 	TypeDisk,
 	TypeBlank,
 
-	/* Cache control bits in page 8 byte 2 */
+	/* offsets in Pagcapmechsts mode page; see MMC-3 §5.5.10 */
+	Capread		= 2,
+	Capwrite	= 3,
+	Capmisc		= 5,
+
+	/* device capabilities in Pagcapmechsts mode page */
+	Capcdr		= 1<<0,		/* bytes 2 & 3 */
+	Capcdrw		= 1<<1,
+	Captestwr	= 1<<2,
+	Capdvdrom	= 1<<3,
+	Capdvdr		= 1<<4,
+	Capdvdram	= 1<<5,
+	Capcdda		= 1<<0,		/* Capmisc bits */
+	Caprw		= 1<<2,
+
+	/* write types, MMC-6 §7.5.4.9 */
+	Wtpkt	= 0,
+	Wttrackonce,
+	Wtsessonce,
+	Wtraw,
+	Wtlayerjump,
+
+	/* Cache control bits in mode page 8 byte 2 */
 	Ccrcd	= 1<<0,		/* read cache disabled */
 	Ccmf	= 1<<1,		/* multiplication factor */
 	Ccwce	= 1<<2,		/* writeback cache enabled */
@@ -34,10 +61,13 @@ enum {
 	Ccabpf	= 1<<6,		/* abort pre-fetch */
 	Ccic	= 1<<7,		/* initiator control */
 
+	/* drive->cap bits */
 	Cwrite	= 1<<0,
 	Ccdda	= 1<<1,
 
-	Nblock = 12,
+	CDNblock = 12,		/* chosen for CD */
+	DVDNblock = 16,		/* DVD ECC block is 16 sectors */
+	BDNblock = 32,		/* BD ECC block (`cluster') is 32 sectors */
 };
 
 typedef struct Buf Buf;
@@ -64,7 +94,6 @@ struct Track
 	Msf	mbeg;
 	Msf	mend;
 
-
 	/* initialized by fs */
 	char	name[32];
 	int	mode;
@@ -109,7 +138,9 @@ struct Drive
 	QLock;
 	Scsi;
 
+	/* disc characteristics */
 	int	type;
+	int	subtype;
 	int	nopen;
 	int	firsttrack;
 	int	ntrack;
@@ -117,9 +148,15 @@ struct Drive
 	int	changetime;
 	int	nameok;
 	int	writeok;
+	int	blank;
+	int	blankset;
+	int	recordable;		/* writable by burning? */
+	int	recordableset;
+	int	erasable;		/* rewritable? */
+	int	erasableset;
 
 	Track	track[Ntrack];
-	ulong	cap;
+	ulong	cap;			/* drive capabilities */
 	uchar	blkbuf[BScdda];
 
 	int	maxreadspeed;

+ 25 - 20
sys/src/cmd/cdfs/main.c

@@ -381,10 +381,10 @@ fsread(Req *r)
 		r->ofcall.count = count;
 		respond(r, nil);
 	}
-	return;
 }
 
 static char *Ebadmsg = "bad cdfs control message";
+
 static char*
 writectl(void *v, long count)
 {
@@ -516,7 +516,12 @@ fsopen(Req *r)
 			return;
 		}
 
-		if(omode != OREAD || (o = drive->openrd(drive, fid->qid.path-Qtrack)) == nil) {
+		/*
+		 * allow the open with OWRITE or ORDWR if the
+		 * drive and disc are both capable?
+		 */
+		if(omode != OREAD ||
+		    (o = drive->openrd(drive, fid->qid.path-Qtrack)) == nil) {
 			respond(r, "permission denied");
 			return;
 		}
@@ -524,11 +529,10 @@ fsopen(Req *r)
 		o->nref = 1;
 		((Aux*)fid->aux)->o = o;
 		respond(r, nil);
+		break;
 	}
 }
 
-static uchar zero[BScdda];
-
 static void
 fsdestroyfid(Fid *fid)
 {
@@ -546,6 +550,10 @@ fsdestroyfid(Fid *fid)
 	}
 }
 
+/*
+ * should it be possible on -r or -rw disc to have a mode of 0666,
+ * or do we have to use the wd/x interface?
+ */
 static void
 checktoc(Drive *drive)
 {
@@ -562,6 +570,9 @@ checktoc(Drive *drive)
 			t->mode = 0;
 		else
 			t->mode = 0444;
+		/*
+		 * set mode to 0666 if the drive and disc are both capable?
+		 */
 		sprint(t->name, "?%.3d", i);
 		switch(t->type){
 		case TypeNone:
@@ -601,14 +612,14 @@ bufwrite(Otrack *t, void *v, long n)
 Srv fs = {
 .attach=	fsattach,
 .destroyfid=	fsdestroyfid,
-.clone=	fsclone,
-.walk1=	fswalk1,
-.open=	fsopen,
-.read=	fsread,
-.write=	fswrite,
+.clone=		fsclone,
+.walk1=		fswalk1,
+.open=		fsopen,
+.read=		fsread,
+.write=		fswrite,
 .create=	fscreate,
 .remove=	fsremove,
-.stat=	fsstat,
+.stat=		fsstat,
 };
 
 void
@@ -655,16 +666,10 @@ main(int argc, char **argv)
 	if(dev == nil || mtpt == nil || argc > 0)
 		usage();
 
-	if((s = openscsi(dev)) == nil) {
-		fprint(2, "openscsi '%s': %r\n", dev);
-		exits("openscsi");
-	}
-
-	if((drive = mmcprobe(s)) == nil) {
-		fprint(2, "mmcprobe '%s': %r\n", dev);
-		exits("mmcprobe");
-	}
-
+	if((s = openscsi(dev)) == nil)
+		sysfatal("openscsi '%s': %r", dev);
+	if((drive = mmcprobe(s)) == nil)
+		sysfatal("mmcprobe '%s': %r", dev);
 	checktoc(drive);
 
 	postmountsrv(&fs, nil, mtpt, MREPL|MCREATE);

+ 274 - 60
sys/src/cmd/cdfs/mmc.c

@@ -37,6 +37,25 @@ struct Mmcaux {
 	long	ntotbk;
 };
 
+static char *dvdtype[] = {
+	"dvd-rom",
+	"dvd-ram",
+	"dvd-r",
+	"dvd-rw",
+	"hd dvd-rom",
+	"hd dvd-ram",
+	"hd dvd-r",
+	"type 7 (unknown)",
+	"type 8 (unknown)",
+	"dvd+rw",
+	"dvd+r",
+	"type 11 (unknown)",
+	"type 12 (unknown)",
+	"dvd+rw dl",
+	"dvd+r dl",
+	"type 15 (unknown)",
+};
+
 static ulong
 bige(void *p)
 {
@@ -71,8 +90,25 @@ hexdump(void *v, int n)
 		print("\n");
 }
 
+static void
+initcdb(uchar *cdb, int len, int cmd)
+{
+	memset(cdb, 0, len);
+	cdb[0] = cmd;
+}
+
+static uchar *
+newcdb(int len, int cmd)
+{
+	uchar *cdb;
+
+	cdb = emalloc(len);
+	cdb[0] = cmd;
+	return cdb;
+}
+
 /*
- * SCSI CCBs (cmd arrays) are 6, 10, 12, 16 or 32 bytes long.
+ * SCSI CDBs (cmd arrays) are 6, 10, 12, 16 or 32 bytes long.
  * The mode sense/select commands implicitly refer to
  * a mode parameter list, which consists of an 8-byte
  * mode parameter header, followed by zero or more block
@@ -184,7 +220,7 @@ mmcsetpage10(Drive *drive, int page, void *v)
 	p[0] = 0;
 	p[1] = len - 2;
 
-	/* set up CCB */
+	/* set up CDB */
 	memset(cmd, 0, sizeof(cmd));
 	cmd[0] = ScmdMselect10;
 	cmd[1] = 0x10;			/* format not vendor-specific */
@@ -273,8 +309,7 @@ mmcstatus(Drive *drive)
 {
 	uchar cmd[12];
 
-	memset(cmd, 0, sizeof(cmd));
-	cmd[0] = ScmdCDstatus;			/* mechanism status */
+	initcdb(cmd, sizeof cmd, ScmdCDstatus);		/* mechanism status */
 	return scsi(drive, cmd, sizeof(cmd), nil, 0, Sread);
 }
 
@@ -284,7 +319,7 @@ mmcgetspeed(Drive *drive)
 	int n, maxread, curread, maxwrite, curwrite;
 	uchar buf[Pagesz];
 
-	n = mmcgetpage(drive, Pagcapmechsts, buf);
+	n = mmcgetpage(drive, Pagcapmechsts, buf);	/* legacy page */
 	maxread = (buf[8]<<8)|buf[9];
 	curread = (buf[14]<<8)|buf[15];
 	maxwrite = (buf[18]<<8)|buf[19];
@@ -307,7 +342,6 @@ mmcprobe(Scsi *scsi)
 	uchar buf[Pagesz];
 	int cap, n;
 
-	/* BUG: confirm mmc better! */
 	if (vflag)
 		print("mmcprobe: inquiry: %s\n", scsi->inquire);
 	drive = emalloc(sizeof(Drive));
@@ -316,6 +350,7 @@ mmcprobe(Scsi *scsi)
 	aux = emalloc(sizeof(Mmcaux));
 	drive->aux = aux;
 
+	/* BUG: confirm mmc better! */
 	/* attempt to read CD capabilities page, but it's now legacy */
 	if(mmcgetpage10(drive, Pagcapmechsts, buf) >= 0)
 		aux->pagecmdsz = 10;
@@ -326,20 +361,24 @@ mmcprobe(Scsi *scsi)
 		free(drive);
 		return nil;
 	}
-
 	cap = 0;
-	if(buf[3] & 3)		/* 2=cdrw, 1=cdr */
+	if(buf[Capwrite] & (Capcdr|Capcdrw|Capdvdr|Capdvdram) ||
+	    buf[Capmisc] & Caprw)
 		cap |= Cwrite;
-	if(buf[5] & 1)
-		cap |= Ccdda;
+	if(buf[Capmisc] & Capcdda)	/* CD-DA commands supported? */
+		cap |= Ccdda;		/* not used anywhere else */
 
 //	print("read %d max %d\n", biges(buf+14), biges(buf+8));
 //	print("write %d max %d\n", biges(buf+20), biges(buf+18));
 
 	/* cache optional page 05 (write parameter page) */
-	if((cap & Cwrite) && mmcgetpage(drive, Pagwrparams, aux->page05) >= 0)
+	if(/* (cap & Cwrite) && */
+	    mmcgetpage(drive, Pagwrparams, aux->page05) >= 0) {
 		aux->page05ok = 1;
-	else
+		cap |= Cwrite;
+		if (vflag)
+			fprint(2, "mmcprobe: got page 5, assuming writable\n");
+	} else
 		cap &= ~Cwrite;
 
 	drive->cap = cap;
@@ -375,7 +414,7 @@ mmctrackinfo(Drive *drive, int t, int i)
 	aux = drive->aux;
 	memset(cmd, 0, sizeof(cmd));
 	cmd[0] = ScmdRtrackinfo;
-	cmd[1] = 1;
+	cmd[1] = 1;			/* address below is logical track # */
 	cmd[2] = t>>24;
 	cmd[3] = t>>16;
 	cmd[4] = t>>8;
@@ -385,7 +424,7 @@ mmctrackinfo(Drive *drive, int t, int i)
 	n = scsi(drive, cmd, sizeof(cmd), resp, sizeof(resp), Sread);
 	if(n < 28) {
 		if(vflag)
-			print("trackinfo %d fails n=%d %r\n", t, n);
+			print("trackinfo %d fails n=%d: %r\n", t, n);
 		return -1;
 	}
 
@@ -410,11 +449,8 @@ mmctrackinfo(Drive *drive, int t, int i)
 		type = TypeNone;
 		break;
 	case 4:		/* data track, recorded uninterrupted */
-		type = TypeData;
-		bs = BScdrom;
-		break;
 	case 5:		/* data track, recorded interrupted */
-		/* treat it as cdrom; probably dvd or bd */
+		/* treat 5 as cdrom; it's probably dvd or bd */
 		type = TypeData;
 		bs = BScdrom;
 		break;
@@ -429,7 +465,7 @@ mmctrackinfo(Drive *drive, int t, int i)
 	drive->track[i].end = beg+size;
 	drive->track[i].type = type;
 	drive->track[i].bs = bs;
-	drive->track[i].size = (vlong)(size-2)*bs;	/* -2: skip lead out */
+	drive->track[i].size = (vlong)(size-2) * bs;	/* -2: skip lead out */
 
 	if(resp[6] & (1<<6)) {
 		drive->track[i].type = TypeBlank;
@@ -438,10 +474,10 @@ mmctrackinfo(Drive *drive, int t, int i)
 
 	if(t == 0xFF)
 		aux->mmcnwa = bige(&resp[12]);
-
 	return 0;
 }
 
+/* this may fail for blank media */
 static int
 mmcreadtoc(Drive *drive, int type, int track, void *data, int nbytes)
 {
@@ -488,6 +524,108 @@ rdmsf(uchar *p)
 	return msf;
 }
 
+static int
+getdiscinfo(Drive *drive, uchar resp[], int resplen)
+{
+	int n;
+
+	n = mmcreaddiscinfo(drive, resp, resplen);
+	if(n < 3)
+		return n;
+	if (vflag)
+		fprint(2, "read disc info succeeded\n");
+	assert((resp[2] & 0340) == 0);			/* data type 0 */
+	drive->erasable = ((resp[2] & 0x10) != 0);	/* -RW? */
+	drive->erasableset = 1;
+	return n;
+}
+
+static int
+getdvdstruct(Drive *drive)
+{
+	int n;
+	uchar cmd[12], resp[Pagesz];
+
+	initcdb(cmd, sizeof cmd, ScmdReadDVD); /* actually, read disc structure */
+	cmd[1] = 0;			/* media type: dvd */
+	cmd[7] = 0;			/* format code: physical format */
+	cmd[8] = sizeof resp >> 8;	/* allocation length */
+	cmd[9] = sizeof resp;
+	n = scsi(drive, cmd, sizeof(cmd), resp, sizeof resp, Sread);
+	if (n < 7)
+		return -1;
+	/*
+	 * resp[0..1] is resp length
+	 * (resp[4] & 0xf0) >> 4 is dvd type (disk category), MMC-6 §6.22.3.2.1
+	 */
+	if (vflag)
+		fprint(2, "dvd type is %s\n", dvdtype[(resp[4] & 0xf0) >> 4]);
+	/* write parameters mode page may suffice to compute writeok for dvd */
+	drive->erasable = drive->recordable = 0;
+	switch (resp[6] & 0xf) {		/* layer type */
+	case 0:					/* embossed data */
+		drive->blank = 0;
+		drive->blankset = 1;
+		break;
+	case 1:					/* recordable */
+		drive->recordable = 1;
+		break;
+	case 2:					/* rewritable */
+		drive->erasable = 1;
+		break;
+	default:
+		fprint(2, "%s: unknown dvd layer type %d\n",
+			argv0, resp[6] & 0xf);
+		return -1;
+	}
+	drive->erasableset = drive->recordableset = 1;
+	drive->subtype = Subtypedvd;
+	return 0;
+}
+
+static int
+getbdstruct(Drive *drive)
+{
+	int n;
+	uchar cmd[12], resp[4100];
+
+	initcdb(cmd, sizeof cmd, ScmdReadDVD); /* actually, read disc structure */
+	cmd[1] = 1;			/* media type: bd */
+	cmd[7] = 0;			/* format code: disc info */
+	cmd[8] = sizeof resp >> 8;	/* allocation length */
+	cmd[9] = sizeof resp;
+	n = scsi(drive, cmd, sizeof(cmd), resp, sizeof resp, Sread);
+	if (n < 4+8+3)
+		return -1;
+	if (vflag)
+		fprint(2, "read disc structure (bd) succeeded\n");
+	/*
+	 * resp[0..1] is resp length
+	 * resp[4+8..4+8+2] is bd type (disc type identifier):
+	 * BDO|BDW|BDR, MMC-6 §6.22.3.3.1
+	 */
+	assert(resp[4+8] == 'B' && resp[4+8+1] == 'D');
+	drive->erasable = drive->recordable = 0;
+	switch (resp[4+8+2]) {
+	case 'O':
+		drive->blank = 0;
+		drive->blankset = 1;
+		break;
+	case 'W':				/* recordable */
+		drive->recordable = 1;
+		break;
+	case 'R':				/* rewritable */
+		drive->erasable = 1;
+		break;
+	default:
+		fprint(2, "%s: unknown bd type BD%c\n", argv0, resp[4+8+2]);
+		return -1;
+	}
+	drive->erasableset = drive->recordableset = 1;
+	drive->subtype = Subtypebd;
+	return 0;
+}
+
 static int
 mmcgettoc(Drive *drive)
 {
@@ -515,13 +653,18 @@ mmcgettoc(Drive *drive)
 	drive->nameok = 0;
 	drive->nchange = drive->Scsi.nchange;
 	drive->changetime = drive->Scsi.changetime;
-	drive->writeok = 0;
+	drive->writeok = drive->erasable = drive->recordable = drive->blank = 0;
+	drive->erasableset = drive->recordableset = drive->blankset = 0;
 
 	for(i=0; i<nelem(drive->track); i++){
 		memset(&drive->track[i].mbeg, 0, sizeof(Msf));
 		memset(&drive->track[i].mend, 0, sizeof(Msf));
 	}
 
+	/*
+	 * TODO: set read ahead, MMC-6 §6.37, seems to control caching.
+	 */
+
 	/*
 	 * find number of tracks
 	 */
@@ -530,29 +673,52 @@ mmcgettoc(Drive *drive)
 		 * on a blank disc in a cd-rw, use readdiscinfo
 		 * to find the track info.
 		 */
-		if(mmcreaddiscinfo(drive, resp, sizeof(resp)) < 0)
+		if(getdiscinfo(drive, resp, sizeof(resp)) < 7)
 			return -1;
+		assert((resp[2] & 0340) == 0);	/* data type 0 */
+		drive->erasable = ((resp[2] & 0x10) != 0);
+		drive->erasableset = 1;
 		if(resp[4] != 1)
 			print("multi-session disc %d\n", resp[4]);
 		first = resp[3];
 		last = resp[6];
 		if(vflag)
 			print("blank disc %d %d\n", first, last);
-		drive->writeok = 1;
+		drive->writeok = drive->blank = drive->blankset = 1;
 	} else {
 		first = resp[2];
 		last = resp[3];
 
 		if(n >= 4+8*(last-first+2)) {
-			for(i=0; i<=last-first+1; i++)	/* <=: track[last-first+1] = end */
+			/* <=: track[last-first+1] = end */
+			for(i=0; i<=last-first+1; i++)
 				drive->track[i].mbeg = rdmsf(resp+4+i*8+5);
 			for(i=0; i<last-first+1; i++)
 				drive->track[i].mend = drive->track[i+1].mbeg;
 		}
 	}
 
-	if(vflag)
+	getdvdstruct(drive);
+	getbdstruct(drive);
+
+	if (drive->subtype == Subtypenone)
+		drive->subtype = Subtypecd;	/* by default */
+	if (drive->recordable || drive->erasable)
+		drive->writeok = 1;
+//	if (drive->subtype == Subtypecd && otrack->buf->ndata == 0)
+//		otrack->buf->nblock = CDNblock;
+
+	if (vflag) {
+		fprint(2, "writeok %d", drive->writeok);
+		if (drive->blankset)
+			fprint(2, " blank %d", drive->blank);
+		if (drive->recordableset)
+			fprint(2, " recordable %d", drive->recordable);
+		if (drive->erasableset)
+			fprint(2, " erasable %d", drive->erasable);
+		fprint(2, "\n");
 		print("first %d last %d\n", first, last);
+	}
 
 	if(first == 0 && last == 0)
 		first = 1;
@@ -589,7 +755,7 @@ mmcgettoc(Drive *drive)
 			}
 		}
 
-		if((long)drive->track[0].beg < 0)	/* i've seen negative track 0's */
+		if((long)drive->track[0].beg < 0) /* i've seen negative track 0's */
 			drive->track[0].beg = 0;
 
 		tot = 0;
@@ -607,7 +773,8 @@ mmcgettoc(Drive *drive)
 				t->beg = 0;
 				t->end = 0;
 			}
-			t->size = (t->end - t->beg - 2) * (vlong)t->bs;	/* -2: skip lead out */
+			/* -2: skip lead out */
+			t->size = (t->end - t->beg - 2) * (vlong)t->bs;
 		}
 	}
 
@@ -630,35 +797,53 @@ mmcsetbs(Drive *drive, int bs)
 		return 0;			/* harmless; assume 2k */
 
 	p = aux->page05;
-	p[2] = 0x01;				/* track-at-once */
+	/*
+	 * establish defaults.
+	 * p[2] & 0xf is write type.
+	 * p[3] & 0xf is track mode.
+	 * p[4] & 0xf is data-block type.
+	 * p[8] is session format.
+	 */
+	p[2] = Wttrackonce;
 //	if(xflag)
-//		p[2] |= 0x10;			/* test-write */
-
-	switch(bs){
-	case BScdrom:
-		p[3] = (p[3] & ~0x07)|0x04;	/* data track, uninterrupted */
-		p[4] = 0x08;			/* mode 1 CD-ROM */
-		p[8] = 0;			/* session format CD-DA or CD-ROM */
-		break;
-
-	case BScdda:
-		p[3] = (p[3] & ~0x07)|0x00;	/* 2 audio channels without pre-emphasis */
-		p[4] = 0x00;			/* raw data */
-		p[8] = 0;			/* session format CD-DA or CD-ROM */
+//		p[2] |= 0x10;		/* test-write */
+	p[3] &= ~0xf;
+	p[3] |= 5;			/* dvd default track mode */
+	p[4] = 0x08;			/* mode 1 CD-ROM: 2K user data */
+	p[8] = 0;			/* session format, CD-DA or -ROM (data) */
+	switch(drive->subtype) {
+	case Subtypecd:
+		p[3] = (p[3] & ~0x07)|0x04; /* data track, uninterrupted */
+		switch(bs){
+		case BScdrom:
+			break;
+		case BScdda:
+			/* 2 audio channels without pre-emphasis */
+			p[3] = (p[3] & ~0x07)|0x00;
+			p[4] = 0x00;	/* raw data */
+			break;
+		case BScdxa:
+			p[4] = 0x09;	/* mode 2: 2336 bytes user data */
+			p[8] = 0x20;	/* session format CD-ROM XA */
+			break;
+		default:
+			fprint(2, "%s: unknown CD type; bs %d\n", argv0, bs);
+			assert(0);
+		}
 		break;
-
-	case BScdxa:
-		p[3] = (p[3] & ~0x07)|0x04;	/* data track, uninterrupted */
-		p[4] = 0x09;			/* mode 2 */
-		p[8] = 0x20;			/* session format CD-ROM XA */
+	case Subtypedvd:
+	case Subtypebd:
 		break;
-
 	default:
-		assert(0);
+		fprint(2, "%s: unknown disc sub-type %d\n",
+			argv0, drive->subtype);
+		break;
 	}
-
-	if(mmcsetpage(drive, Pagwrparams, p) < 0)
+	if(mmcsetpage(drive, Pagwrparams, p) < 0) {
+		if (vflag)
+			fprint(2, "mmcsetbs: could NOT set write parameters page\n");
 		return -1;
+	}
 	return 0;
 }
 
@@ -774,7 +959,7 @@ mmcopenrd(Drive *drive, int trackno)
 	o->track = &drive->track[trackno];
 	o->nchange = drive->nchange;
 	o->omode = OREAD;
-	o->buf = bopen(mmcread, OREAD, o->track->bs, Nblock);
+	o->buf = bopen(mmcread, OREAD, o->track->bs, BDNblock);
 	o->buf->otrack = o;
 
 	aux->nropen++;
@@ -782,6 +967,29 @@ mmcopenrd(Drive *drive, int trackno)
 	return o;
 }
 
+static int
+format(Drive *drive)
+{
+	uchar *fmtdesc;
+	uchar cmd[6], parms[4+8];
+
+	initcdb(cmd, sizeof cmd, ScmdFormat);	/* format unit */
+	cmd[1] = 0x10 | 1;		/* format data, mmc format code */
+
+	memset(parms, 0, sizeof parms);
+	parms[1] = 2;			/* immediate return; don't wait */
+	parms[3] = 8;			/* format descriptor length */
+
+	fmtdesc = parms + 4;
+	PUTBELONG(fmtdesc, ~0ul);
+	fmtdesc[4] = 0;			/* full format */
+	PUTBE24(fmtdesc + 5, BScdrom);
+
+	if(vflag)
+		print("%lld ns: format\n", nsec());
+	return scsi(drive, cmd, sizeof(cmd), parms, sizeof parms, Swrite);
+}
+
 static long
 mmcxwrite(Otrack *o, void *v, long nblk)
 {
@@ -793,6 +1001,7 @@ mmcxwrite(Otrack *o, void *v, long nblk)
 	aux = o->drive->aux;
 	aux->ntotby += nblk*o->track->bs;
 	aux->ntotbk += nblk;
+
 	memset(cmd, 0, sizeof(cmd));
 	cmd[0] = ScmdExtwrite;		/* write (10) */
 	cmd[2] = aux->mmcnwa>>24;
@@ -802,7 +1011,7 @@ mmcxwrite(Otrack *o, void *v, long nblk)
 	cmd[7] = nblk>>8;
 	cmd[8] = nblk>>0;
 	if(vflag)
-		print("%lld: write %ld at 0x%lux\n", nsec(), nblk, aux->mmcnwa);
+		print("%lld ns: write %ld at 0x%lux\n", nsec(), nblk, aux->mmcnwa);
 	aux->mmcnwa += nblk;
 	return scsi(o->drive, cmd, sizeof(cmd), v, nblk*o->track->bs, Swrite);
 }
@@ -840,17 +1049,18 @@ mmccreate(Drive *drive, int type)
 		return nil;
 	}
 
+/* comment out the returns for now; it should be no big deal - geoff */
 	if(mmctrackinfo(drive, 0xFF, Maxtrack)) {	/* the invisible track */
 		werrstr("CD not writable");
-		return nil;
+//		return nil;
 	}
 	if(mmcsetbs(drive, bs) < 0) {
 		werrstr("cannot set bs mode");
-		return nil;
+//		return nil;
 	}
 	if(mmctrackinfo(drive, 0xFF, Maxtrack)) {	/* the invisible track */
 		werrstr("CD not writable 2");
-		return nil;
+//		return nil;
 	}
 
 	aux->ntotby = 0;
@@ -869,7 +1079,7 @@ mmccreate(Drive *drive, int type)
 	o->nchange = drive->nchange;
 	o->omode = OWRITE;
 	o->track = t;
-	o->buf = bopen(mmcwrite, OWRITE, bs, Nblock);
+	o->buf = bopen(mmcwrite, OWRITE, bs, BDNblock);
 	o->buf->otrack = o;
 
 	aux->nwopen++;
@@ -924,8 +1134,8 @@ mmcxclose(Drive *drive, int ts, int trackno)
 	 * ts: 1 == track, 2 == session
 	 */
 	memset(cmd, 0, sizeof(cmd));
-	cmd[0] = ScmdClosetracksess;
-	cmd[2] = ts;
+	cmd[0] = ScmdClosetracksess;		/* fixate */
+	cmd[2] = ts;				/* close function */
 	if(ts == 1)
 		cmd[5] = trackno;
 	return scsi(drive, cmd, sizeof(cmd), cmd, 0, Snone);
@@ -944,9 +1154,10 @@ mmcfixate(Drive *drive)
 
 	drive->nchange = -1;		/* force reread toc */
 
-	/* TODO: page 5 is legacy and now read-only */
+	/* page 5 is legacy and now read-only */
 	aux = drive->aux;
 	p = aux->page05;
+	/* zero multi-session field: next session not allowed */
 	p[3] &= ~0xC0;
 	if(mmcsetpage(drive, Pagwrparams, p) < 0)
 		return -1;
@@ -963,9 +1174,10 @@ mmcsession(Drive *drive)
 
 	drive->nchange = -1;	/* force reread toc */
 
-	/* TODO: page 5 is legacy and now read-only */
+	/* page 5 is legacy and now read-only */
 	aux = drive->aux;
 	p = aux->page05;
+	/* zero multi-session field: next session not allowed */
 	p[3] &= ~0xC0;
 	if(mmcsetpage(drive, Pagwrparams, p) < 0)
 		return -1;
@@ -1014,6 +1226,8 @@ mmcctl(Drive *drive, int argc, char **argv)
 	if(argc < 1)
 		return nil;
 
+	if(strcmp(argv[0], "format") == 0)
+		return e(format(drive));
 	if(strcmp(argv[0], "blank") == 0)
 		return e(mmcblank(drive, 0));
 	if(strcmp(argv[0], "quickblank") == 0)

+ 8 - 8
sys/src/cmd/col.c

@@ -177,7 +177,7 @@ outc(Rune c)
 	while (*line == '\b')
 		line += 2;
 	if (bflag || *line == '\0' || *line == ' ')
-		*line = c;
+		cp += runetochar(line, &c) - 1;
 	else {
 		char c1, c2, c3;
 
@@ -232,17 +232,17 @@ emit(char *s, int lineno)
 
 	if (*s) {
 		while (cline < lineno - 1) {
-			Bputrune(&bout, '\n');
+			Bputc(&bout, '\n');
 			pcp = 0;
 			cline += 2;
 		}
 		if (cline != lineno) {
-			Bputrune(&bout, ESC);
-			Bputrune(&bout, '9');
+			Bputc(&bout, ESC);
+			Bputc(&bout, '9');
 			cline++;
 		}
 		if (pcp)
-			Bputrune(&bout, '\r');
+			Bputc(&bout, '\r');
 		pcp = 0;
 		p = s;
 		while (*p) {
@@ -250,15 +250,15 @@ emit(char *s, int lineno)
 			while (*p++ == ' ')
 				if ((++ncp & 7) == 0 && !xflag) {
 					pcp = ncp;
-					Bputrune(&bout, '\t');
+					Bputc(&bout, '\t');
 				}
 			if (!*--p)
 				break;
 			while (pcp < ncp) {
-				Bputrune(&bout, ' ');
+				Bputc(&bout, ' ');
 				pcp++;
 			}
-			Bputrune(&bout, *p);
+			Bputc(&bout, *p);
 			if (*p++ == '\b')
 				pcp--;
 			else

+ 1 - 1
sys/src/cmd/troff/mkfile

@@ -51,7 +51,7 @@ n1.$O:	n1.c $HFILES
 	$CC $CFLAGS -DFONTDIR'='$FONTDIR -DNTERMDIR'='$NTERMDIR -DTEXHYPHENS'='$TEXHYPHENS -DALTHYPHENS'='$TEXHYPHENS -DDWBHOME'='$DWBHOME n1.c
 
 n10.$O:	n10.c $HFILES
-	$CC $CFLAGS -DTDEVNAME'='$NDEVNAME n10.c
+	$CC $CFLAGS -DNDEVNAME'='$NDEVNAME n10.c
 
 n8.$O:	n8.c $HFILES
 	$CC $CFLAGS -DTEXHYPHENS'='$TEXHYPHENS n8.c