SCSI - Small Computers System Interface

CD-R writers revealed

There is no literature about low level CD-R burning. This article discloses the SCSI3 command sequence to burn a track on a CD-R using a MMC-1 device.

  • Forewords and news
  • Information for ATAPI programmers
  • CD-R writer device type
  • Objectives of this project
  • Required documentation
  • Required device
  • A word about "test mode"
  • Brief history of this project and my Plasmon D120-20 juke box
  • Theory behind this project
  • Commands you should know about
  • Preparing the Write Parameters Mode Page
  • Preparing a DLL
  • Getting info about the disc inserted into the device
  • Cloning a MODE-1 CD-ROM
  • Preparing the ISO 9660 image file
  • Burning the ISO 9660 image file in a blank CD-R disc
  • The future of this project
  • Final notes
  • Last minute news and a little bug
  • Forewords and news

    This page talks about SCSI CD recorders. Because of many requests that I had received by mail, and since some programmers reported their experiences with ATAPI CD recorders, I have added a paragraph that deals with ATAPI devices.

    Please before sending mails check whether your answer is already in this web page. Thank you.

    Information for ATAPI programmers

    Igor, a professional programmer from Russia reports the following (dec. 3rd, 2003):
    • he wrote his code in C++ for his ATAPI Sony CD Recorder. The only things that he had to change in the assembly code provided in this article (apart from being translated into C++) are the following:
      • use MODE SELECT (10) instead of MODE SELECT (6) to send the Write Parameters Mode Page to the target device
      • do not send any block descriptor together with the Write Parameters Mode Page
      Here is the code that Igor wrote to send the MODE SELECT (10) to his target:
      BYTE buffer[60];
      SRB_ExecSCSICmd srbExec;
      memset(buffer, 0, sizeof(buffer));
      memset(&srbExec, 0, sizeof(srbExec));
      srbExec.SRB_Cmd = (SRB_DIR_OUT | SC_EXEC_SCSI_CMD);
      srbExec.SRB_HaId = SCSI_HaId;
      srbExec.SRB_Target = SCSI_Id;
      srbExec.SRB_Lun = SCSI_Lun;
      srbExec.SRB_Flags = SRB_EVENT_NOTIFY;
      srbExec.SRB_PostProc = (PFNPOST)hEventSRB;
      srbExec.SRB_SenseLen = SENSE_LEN;
      srbExec.SRB_CDBLen =10;
      srbExec.SRB_BufPointer = buffer;
      srbExec.SRB_BufLen = sizeof(buffer);
      srbExec.CDBByte[0] = SCSI_MODE_SEL10;
      srbExec.CDBByte[1] = 0x10; // Set PF bit = 1
      srbExec.CDBByte[8] = sizeof(buffer); // Allocation Length
      buffer[2] = 0x20; // Set medium type, no block descriptors
      buffer[8] = 0x5; // don't save parameters; mode page #5
      buffer[9] = 0x32; // page size = 50 bytes
      buffer[10] = TrackMode | (isTest ? 0x10 : 0x0);
      buffer[11] = 0x04 | (IsMultiSession ? 0xC0 : 0x0); // data track
      buffer[12] = 0x08; // MODE-1 CDROM
      buffer[13] = 0x00; // CD-ROM disc 
      buffer[23] = 0x96; // Audio Pause Length = default value is 150
      buffer[58] = 0x08; // ? (taken from cdrecord)
      // execute
    • Igor says that he tested Adaptec's ASPI 4.60 with his ATAPI drive and it works OK
    • talking about cdrecord, Igor also says that cdrecord has 2 very good switches: "-v" and "-VV". They tell cdrecord to print all data it sends and receives to/from the target CD Recorder. It helped him solve the problem with MODE SELECT command and find out how to load/eject the medium

    XcalibEr (may 26th, 2003) and Nils from Germany (july 31th, 2003) both confirm the experience reported by Richard (see below).

    Richard, a friend programmer from Germany told me that the project described in this page works with his ATAPI CD writer as well, with no modifications. The only trick to get the result is the following:

    • install Adaptec's ASPI support on your PC as usual
    • replace WNASPI32.DLL with the one that comes with Nero Burning software
    I did not test this because I have no ATAPI CD writer, neither I use Nero. But what Richard says makes a big sense, because ATAPI writers derived their command set from SCSI devices, and they work in a very similar manner. Furthermore: Adaptec only cares about SCSI devices, so WNASPI32.DLL that comes from them only works with SCSI devices. The company that wrote Nero, on the other hand, they want Nero to work both with SCSI and ATAPI devices, so they developed themselves (or asked Adaptec to develop for them) a version of WNASPI32.DLL that works with ATAPI devices.

    CD-R writer device type

    CD-R writer device type didn't exist in the SCSI2 standard. This limit has been suppressed in the SCSI3 standard.

    CD-R writers (as well as CD-RW, DVD-R and DVD-RW writers) respond to the following sets of SCSI3 commands:

    • SPC (SCSI3 Primary Commands)
    • MMC (SCSI3 Multi Media Commands)

    This situation is favorable for the programmer that finally can easily deal with these kind of devices.

    Please note that more than one MMC specification and more than one SPC specification have been released by T10 in order to keep pace with the evolving technology.

    Currently MMC spans from release 1 to 4, and SPC from release 1 to 3. You can download MMC-1, MMC-2, MMC-3, MMC-4, SPC-1, SPC-2 and SPC-3 specifications from T10's site.

    For each CD-R, CD-RW, DVD-R, or DVD-RW writer there exists a MMC/SPC pair of commands sets according to the "generation" of the device. For example my Plextor CD-R 820 writer responds to MMC-1 and SPC-1 specifications. Newer devices respond to MMC-2, SPC-2 and later. Download the specification for your device from T10's site. If you don't know which generation your device is, download MMC-1 and SPC-1 and you will be safe: generations are backward compatible, and this choice will give you a solid starting point.

    When programming any device of this kind you should also be provided, as usual, with the SCSI command set reference released from the maunfacturer of the device. This requirement is not strictly required but highly recommended. I used the manufacturer's reference mainly to confirm that my device was a first generation (MMC-1/SPC-1), to interpret some vendor unique sense data, and to get info about some minor features.

    Objective of this project

    Objective of this project is burning a file into a MODE-1 track on a blank CD-R disc, and close the disc.

    The file to burn should have been already prepared on the hard disk.

    If the file were an ISO 9660 file system image file, then the resulting disc would be a true ISO 9660 MODE-1 CD-R.

    Along the way we will also see:

    • how to get information about the disc inserted into a CD device
    • how to read a sector
    • how to clone (=duplicate) an ISO 9660 file system MODE-1 CD-ROM
    This project puts the basis for the following further developments: write more than one track on a CD-R disc, duplicating audio CDs and DVDs.

    Required documentation

    The only true document you should be in possess of to follow and understand this project is the MMC-1 specification published by the T10 technical Committee.

    You can download it here (search for SCSI-3 Multimedia Commands (MMC){Date: 1997/05/06, Rev: 10a, Status: Published, Project: 1048-M, File: mmc-r10a.pdf (942631 bytes)}).

    I strongly suggest to print and bind a copy of it, and to keep it at hand.

    IMPORTANT: this document will be frequently recalled through all this article. It will be referred to as the T10-MMC-1 spec for short.

    Required device

    To implement this project you should be provided with a MMC-1 compliant CD-R (or CD-RW) writer device. Because generations are backwards compatible, any MMC-2, MMC-3 or MMC-4 compliant CD-R or CD-RW writer should work as well.

    Possibly you should be provided also with a printed copy of the SCSI command set reference released by the manufacturer of your device. This is not strictly necessary, but very useful.

    In case you don't know whether your device is compliant to any of the MMC specifications, you can always start implementing this project with no fear, because usually devices protect themselves against wrong or unexisting commands. All that you could get returned (in the worst case) should be a check condition status that, followed by a request sense, will help discovering unsupported commands or features.

    A word about "test mode"

    Test mode in a CD-R/CD-RW writer device acts like true burning of a CD-R disc but the laser is turned off, and nothing is actually written on the media.

    This mode is used, as you can easily guess, for testing purposes. It has proven to be very useful in my burning experiments, making me save dozens of bucks in badly burned medias because of wrong SCSI command sequences.

    I experimentally discovered that test mode is valid and possible only when issuing WRITE 10 SCSI3 commands, and *not* when issuing other commands like CLOSE TRACK/SESSION.

    When you send the target a CLOSE TRACK/SESSION command in test mode you will *always* be returned a check condition from the target even if everything in the system is perfectly OK.

    (Test mode is a writing parameter, and it is sent to the target by means of the Write Parameters Mode Page.)

    Brief history of this project and my Plasmon D120-20 juke box

    I am the unfortunate owner of a Plasmon 120 CDs juke box, as described here, and as you can see in this photo.

    I had the idea to utilize it as a CD duplicator. In other words I would like to get up to 120 copies of a MODE-1 CD-ROM leaving my juke box working unattended.

    Here are described, in short, all the steps that I performed to reach the objective of duplicating n copies of a CD-ROM:

    • I checked the Plasmon product list to see the CD-R writer device that would fit into my juke box: it is model CDR32XD-F
    • I sent a mail to Plasmon UK to get the SCSI command set for their CDR32XD-F unit. Soon I was sent by e-mail the required document attached in PDF format. Many thanks to Plasmon UK for providing me with the required documentation
    • I printed and bound a copy of the PDF file, and started studying it. I discovered the following:
      • Plasmon CDR32XD-F is produced by Plextor, and is equivalent to Plextor PX-W1210TS (a 12x CD-R writable and 10x CD-RW rewritable device)
      • the SCSI3 command set for Plextor devices strictly matches the MMC-1 specification released by T10 Technical Committee, hence Plasmon CDR32XD-F and all Plextor models are MMC-1 compliant devices
      • all models from Plextor share the same SCSI3 command set that I was sent by Plasmon UK
    • casually the SCSI CD-R writer in my laboratory is a Plextor 820 (bought in 1999)
    • this lucky circumstance made me start experimenting using my Plextor 820, without buying the Plasmon CDR32XD-F (for the moment)
    • my first homework has been getting info about the disk inserted into the device
    • then I started burning experiments in test mode trying to determine the correct SCSI3 command sequence to correctly burn a file into a track of a blank CD-R disc, and close the disc
    • I had to make several dozen different experiments before finding a reasonable SCSI3 command sequence that would not end up in a check condition from the target
    • during all these experiments I have been wasting time because of some major difficulties, the most time consuming of which were:
      • first of all I tried a session at once style of writing, but whichever the cue sheet I had prepared, the first WRITE 10 command has always been blocking the target, so badly that I had to write a routine to reset the SCSI bus; thus I decided to abandone session at once style of writing and started track at once
      • although I soon discovered the correct SCSI command sequence in track at once mode, I continued receiving a check condition from the target at the end of the command sequence, making me think that the sequence was wrong; actually the sequence was right, but I was using test mode to economize recordable discs, and it took me a discrete amount of time before discovering that CLOSE TRACK/SESSION command returns check condition when burning in test mode
      • when I was able to correctly burn a track in a CD-R I had to face some bad ISO 9660 file system image files generated by Easy CD Creator rel. 3.01, that made me waste many and many hours (before discovering that Easy CD Creator rel. 3.5 generates good ISO 9660 image files)
    • finally I found a complete solution to clone MODE-1 CD-ROMs

    Theory behind this project

    For you to understand next paragraphs you need to know about the following issues.

    The original CD, according to the red book, was designed to accomodate audio data tracks and was organized in frames. An audio CD contains a sequence of frames in a spiral fashion, starting near the center hole of the disc and evolving up to the outer diameter of it. Although frames are sequentially ordered, CD readers/writers are *direct access* devices because of their capability to access the media randomly. Every frame is 2352 bytes long, and can accomodate one 75th of second of audio sampled at 44 kHz (75 frames hold one second of audio).

    Each frame in the disc is not addressed by its ordinal position from the beginning of the spiral, but is addressed in a MM:SS:FF (minutes, seconds, frames) notation that is more suitable when dealing with audio.

    A common 74 minutes audio CD holds 74x60x75 = 333.000 frames.

    When someone had the great idea to use CDs for holding computer data, a new specification was written (the yellow book) and the new CD type was named MODE-1 CD-ROM.

    The yellow book introduced many changes:

    • the "frame" was renamed "sector" or, better, block
    • MM:SS:FF addressing scheme was substituted by the more intuitive LBA (Logical Block Address) addressing scheme
    • each block would have been rearranged to contain 2048 bytes of computer data, plus some bytes of EDC (Error Detection Code) and some bytes of ECC (Error Correction Code)
    A 74 minutes audio CD would have been seen like a spiral stream of 333.000 blocks starting at LBA 0 and ending at LBA 332.999. Usually CDs hold some blocks more because of the manufacturing process.

    You see that 333.000 blocks at 2 kB per block make a 640 MB (actually 666 MB) CD-ROM.

    The introduction of EDC and ECC was necessary to maximize the probability that bytes would have been read exactly as they were written. You should think that reading the famous pits on the CD surface is not a deterministic process, so to speak, and yet the eight to fourteen byte coding scheme "trick" has been adopted to reduce errors.

    You should also think that one or more wrong bytes in a audio track are not perceived by the human ears, but one or more wrong bytes in a computer data track would be absolutely unacceptable. This is why the original 2352 bytes of the original frame have been rearranged in a 2 kBytes of user data and some EDC plus ECC to guarantee that bytes are properly returned when reading pits on the surface of the disc.

    Curiosity: MODE-2 CD-ROM is almost identical to MODE-1 CD-ROM, the difference being in that EDC and ECC are not used and the space is used to accomodate more user data. This results in MODE-2 CD-ROM being more capable but less reliable than MODE-1 CD-ROM. MODE-2 CD-ROMs are used to hold, say, audio and video streams of data (e.g.: mpeg videos, etc.).

    Once the yellow book standardized CD-ROM data discs, everybody could start writing 2 kBytes blocks of data here and there on the CD surface. But this was not sufficient to keep ordered files into CD-ROMs. For this reason the ISO 9660 file system (formerly High Sierra) was invented to standardize the way of writing files and directories into CD-ROMs.

    Because of some ISO 9660 file system limits, the Joliet specification was successively released. I think you know about these issues.

    The ISO 9660 (or Joliet) specification can be found on the web, but for the purpose of this project, duplicating CDs, it is not important as you will soon realize. The only thing that we must take care of is that both ISO 9660 and Joliet file systems must start at LBA 16 of a MODE-1 CD-ROM. Blocks from LBA 0 to LBA 15 can contain any data, they don't matter. Usually these blocks are filled with zeroes.

    Final note: the orange book was successively released to introduce CD-R, the kind of disc we are going to deal with in this project. CD-ROM and CD-R, from a MODE-1 perspective, are perfectly equivalent. The only difference being that the former is printed with a "glass master" in huge plants, and the latter can be burned at home with any CD-R writer.

    Commands you should know about

    Commands involved in writing a MODE-1 CD-ROM are:
    • TEST UNIT READY: this is a very basic command that you already should know about; it must be issued at the beginning of any SCSI command sequence to check whether a device is ready to accept further commands
    • READ DISC INFORMATION: this command retrieves the Disk Information Block for the disc inserted into the device. This block is described in Table 130 of the T10-MMC-1 spec, and is used to hold all the info retrieved by this command. Bits 1 and 0 in byte 2 in the Disk Information Block (Disc Status) are described in Table 131 of the T10-MMC-1 spec, and we will use them to recognize wheter the disc inserted into the writer is empty or not. Please note that byte 3 in the Disk Information Block (Number of First Track on Disc) is #1 even if the disc is empty
    • READ TRACK INFORMATION: this command retrieves the Track Information Block for any given track of the disc inserted into the device. The block is described in Table 142 of the T10-MMC-1 spec. We will use this command to get info about track #1 in the empty disc inserted into the writer device, and in particular to retrieve the LBA start address of that track. Issuing this command for the purposes of this project is superfluous because we are always going to burn empty discs, and #1 track start address in an empty disc is always LBA zero
    • MODE SELECT: this command is used to send the Write Parameters Mode Page (WPMP) to the target device. This "mode page" will be covered next paragraph
    • WRITE 10: this command is used to actually burn blocks of user data into the CD-R disc. The behaviour of this command is influenced by the values that have been sent to the device in the Write Parameters Mode Page. You can burn up to 32 blocks (=64 kB of data) each WRITE 10. A sequence of WRITE 10 commands is used to burn user data to the media. The first WRITE 10 command takes 10 to 20 seconds before actually burn data because the target device needs to spin up the disc and to calibrate the laser beam intensity. Any successive WRITE 10 command is very fast because the disc is already spinning and the laser beam has already been calibrated
    • SYNCHRONIZE CACHE: this command must be issued immediately after the last WRITE 10 command in a sequence. It assures that all remaining data in the data buffer of the writer device are actually burned to the media
    • CLOSE TRACK/SESSION: as its name says, this command is used to close either a track or a session. Closing a track/session makes the target device burn the lead in and the lead out to the CD-R, completing the process of writing the track/session (important note: CLOSE TRACK/SESSION returns *check condition* in test mode). We will call this command with bytes 2 and 5 of the CDB respectively set to 2 and 0 (byte 2 is described at Table 118 in the T10-MMC-1 specification)
    • READ 10: this command reads one or more blocks in a burned disc. It is not required when writing, but we will use it to generate an ISO 9660 image file from an existing CD-ROM for the purpose of duplicating it

    Preparing the Write Parameters Mode Page

    The Write Parameters is is one of several mode pages defined for the kind of devices we are going to deal with. It is described in table 108 of the T10-MMC-1 spec, and contains parameters needed for the correct execution of WRITE 10 command at write time.

    Not all the values in the WPMP will be necessarily used. They will be used as applicable at writing time. If one or more paramenters hold values incompatible with the track being burned, a check condition status is returned by the target when the WRITE 10 is attempted.

    The WPMP is sent to the target, as any other mode page, by means of a MODE SELECT command. The WPMP is sent togheter with a 8 bytes long Block Descriptor (see MODE SELECT command).

    The following are the parameters that we will use to burn a MODE-1 CD-ROM track and close the disc (please refer to Table 108 in T10-MMC-1 spec). You can use different parameters as suggested in square brackets according to your eventual needs, provided you know what you are going to do. Please note that special comments are given only when T10-MMC-1 spec alone is not sufficient to understand how to set a parameter:

    • byte 0: 0x05 (don't save parameters; mode page #5)
    • byte 1: 0x32 (page length)
    • byte 2: 0x01 (no test mode [if you want to run in test mode set bit 4 to 1]; track at once)
    • byte 3: 0x46 (Multi-session: Next session not allowed [you can set it differently, see table 110 in T10-MMC-1 spec]; Track Mode: data track, recorded uninterrupted, digital copy permitted [see paragraph 3.1.10 and Table 61 in T10-MMC-1 spec])
    • byte 4: 0x08 (MODE-1 CD-ROM [see Table 111 in T10-MMC-1 spec])
    • byte 5: 0x00 (reserved)
    • byte 6: 0x00 (reserved)
    • byte 7: 0x00 (no host application code)
    • byte 8: 0x00 (session format: CD-ROM disc [see table 112 in T10-MMC-1 spec])
    • byte 9: 0x00 (reserved)
    • bytes 10 to 13: all zeroes (Packet Size not required when writing track at once, we are not using packet writing)
    • bytes 14 and 15: all zeroes (Audio Pause Length not used when writing MODE-1 CD-ROM)
    • bytes 16 to 31: all zeroes (Media Catalog Number not required [see table 63 in T10-MMC-1 spec])
    • bytes 32 to 47: all zeroes (International Standard Recording Code not required, [see table 65 in T10-MMC-1 spec])
    • byte 48: 0x00 (Sub-header Byte 0 left to zero)
    • byte 49: 0x00 (Sub-header Byte 1 left to zero)
    • byte 50: 0x00 (Sub-header Byte 2 left to zero)
    • byte 51: 0x00 (Sub-header Byte 3 left to zero)

    Preparing a DLL

    My experiences with CD-R and CD-RW writer devices are enclosed in the DLL that I am going to introduce.

    The DLL is written in win32asm. The source code is given, and you can compile it yourself, or download a ready to use compiled version of it (at the end of this paragraph). To compile the DLL you must have MASM32 v.6 installed in your PC. You can download the free compiler at hutch's site.

    The source code is either well commented or self explanatory, but you can send me inquiries to help clarifying any instruction that (despite my efforts to make it clear) might result obscure.

    C++ programmers can write their own version of the DLL in c++, although this would result in complicating a simple thing.

    Commented C++ source code examples that utilize the DLL are also given in the next paragraphs.

    The DLL offers 5 built in functions, 2 of which (FFAspiStart and FFAspiStop) are already described in Build your own ASPI DLL project. The functions are:

    • FFAspiStart: to start ASPI operations; takes one parameter: the handle (HWND) of the main window of the calling program, used to send messages to the user in case ASPI can't be properly initialized
    • FFAspiStop: to stop ASPI operations; takes no parameters
    • FFDiscInfo: useful to get info about a disc inserted into a CD-R or CD-RW writer device. It sends the target a READ DISC INFORMATION SCSI3 command, retrieves the Disc Information Block, and makes it readable to humans; the function takes the following parameters:
      • (HWND) the handle to the main window of the calling program
      • (int) the Host Adapter card number: usually 0 unless you have more than one host adapter card inserted into the bus of the PC
      • (int) the SCSI Id of the target
      • (int) the SCSI LUN of the target
      An example of using this function is given here
    • FFCDReadSect: this function reads a block (a sector) in a disc inserted into a CD-R or CD-RW writer device; it sends the target a READ 10 SCSI3 command, gets the block, and returns 2048 bytes of data; the function takes the following parameters:
      • (HWND) the handle to the main window of the calling program
      • (int) the Host Adapter card number: usually 0 unless you have more than one host adapter card inserted into the bus of the PC
      • (int) the SCSI Id of the target
      • (int) the SCSI LUN of the target
      • (int) number of the sector to read: LBA address of the block
      • (char*) pointer to the buffer that will receive the data
      An example of using this function is given here
    • FFCDWrite: this function burns a file into a MODE-1 track in a blank CD-R disc and closes the disc. The track is burned in track at once style of writing; if the file were a ISO 9660 image you get a perfect CD-ROM of user data. Essentially this function does the following:
      • check the target device for readyness
      • read the Disc Information Block for the media inserted into the target device; exit if the CD-R disc is not empty
      • read the Track Information Block for track #1 in the disc; as already described above this command is superfluous because track #1 in an empty disc always starts at LBA number zero
      • send the Write Parameters Mode Page by means of a MODE SELECT command
      • read 8 kB from the input file and burn 4 blocks into the CD-R disc
      • the previous step is repeated until the end of the input file is reached (see the note (*) below)
      • synchronize the cache to flush residual data from the buffer to the disc
      • close the track
      The function should be passed the following parameters:
      • (HWND) the handle to the main window of the calling program: it serves for the purpose of sending messages to the user in case the target returns check condition
      • (int) the Host Adapter card number: usually 0 unless you have more than one host adapter card inserted into the bus of the PC
      • (int) the SCSI Id of the target: obvious
      • (int) the SCSI LUN of the target: obvious as well
      • (HANDLE) the handle of the file to be burned: the calling program is responsible for opening and closing the image file
      An example of using this function is given here.
    (*) Note: the last call to WRITE 10 in FFCDWrite always burns 4 blocks (8 kB of user data), even if the last read from the file returned less than 8 kB. This is not correct but perfectly acceptable. It's up to you, if you want, to modify FFCDWrite to burn less than 4 blocks according to the actual number of bytes read in the last access to the input file. I use FFCDWrite *as is* and the garbage that it leaves at the end of the track does not affect the functionality of my cloned MODE-1 CD-ROMs.

    One note more: you can burn up to 32 blocks (64 kB of user data) for each call to WRITE 10 SCSI3 command. But the number of blocks does not affect the overall burning performance.

    The FFCDWrite function can be modified as follows:

    • leave the disc opened (don't close the disc): in this case you should modify the Multi-session Field Definition field in byte 3 of the Write Parameters Mode Page according to Table 110 in T10-MMC-1 spec, and byte 2 in the CDB of the CLOSE TRACK/SESSION command according to Table 118 in T10-MMC-1 spec
    • write more than one track in the disc: in this case for any successive track you should determine its starting LBA by getting the Disk Information Block of the last track in the disc
    Four file types are required to build the DLL:
    • one ASM file that contains the data segment and the DLL entry point
    • one DEF file that contains the name of the DLL and the name of the functions that have to be exported
    • some INC files that have to be included into the ASM file
    • one BAT file that acts as the *makefile* for the DLL to build
    The INC files are not actually required, but using them helps maintaining neat listings and a clear structure of the DLL. Remember that to build the DLL you should have MASM32 installed in your PC.

    Directions to build the DLL are the following:

    • make a working directory in your hard disk and name it MMC1DLL: you will use this directory to keep the following files
    • cut this file and paste it into an ASCII file named MMC1DLL.ASM
    • cut this file and paste it into an ASCII file named MMC1DLL.DEF
    • cut this file and paste it into an ASCII file named MAKEDLL.BAT
    • cut this file and paste it into an ASCII file named FFASPI.INC
    • cut this file and paste it into an ASCII file named FFCDR.INC
    • cut this file and paste it into an ASCII file named WNASPI32.INC (to be put into C:\MASM32\INCLUDE directory)
    • cut this file and paste it into an ASCII file named SCSIDEFS.INC (to be put into C:\MASM32\INCLUDE directory)
    • run MAKEDLL.BAT and have the DLL done, togheter with its LIB import library file for static linking.

    Getting info about the disc inserted into the device

    Use the FFDiscInfo function defined into the MMC1DLL.DLL described above.

    To get the c++ example source code follow this link.

    Cloning a MODE-1 CD-ROM

    To clone (duplicate) a MODE-1 CD-ROM you should do the following:
    • prepare an ISO 9660 (or Joliet) file system image file
    • burn it into a blank disc
    These steps are described in the next two paragraphs.

    The ISO 9660 (or Joliet) image file is required because files in any MODE-1 CD-ROM are supposed to be organized according to one of these widespread standards. Differently data would not be widespreadly read.

    Preparing the ISO 9660 image file

    From now on we will be only talking about an IS0 9660 file system image file. Everything we will say about it will also be valid for any Joliet file system image file.

    A *valid* ISO 9660 image file should start with 32.768 zeroes. Then at offset 32.768 (0x8000) you should find the following sequence of bytes: 0x01, 0x43, 0x44, 0x30, 0x30, 0x31, 0x01, 0x00.

    You can generate the file using Easy CD Creator, or you can do it yourself (as desribed below).

    If you use Easy CD Creator (or any equivalent program) always check that the ISO 9660 image file that has been generated is valid according to the criteria provided above. Differently you might have a delusion.

    A do-it-yourself way of getting a valid ISO 9660 image file of an existing CD-ROM is the following procedure:

    • put a good ISO 9660 MODE-1 CD-ROM into the CD-R writer device
    • prepare a program to read sequentially all the blocks in the CD-ROM starting at LBA zero and ending at the last burned block
    • write the blocks sequentially into a file in the hard disk
    The file obtained this way is an ISO 9660 image of the CD-ROM inserted into the CD-R writer device (provided the CD-ROM was an ISO 9660, of course). As simple as this !

    To get the c++ example source code of such a program follow this link.

    After burning a CD-R, as described in the next paragraph, you can use the above sample code to get the ISO 9660 image file of the just-burned CD-R. Then you can compare it with the original ISO 9660 image file that was used to burn the disc: this will prove that the two files are perfectly equal (except for the tails of the files, but don't care, it is acceptable).

    Burning the ISO 9660 image file in a blank CD-R disc

    You can burn the ISO 9660 image file once you have it done and ready to use. The file is to be burned into a blank CD-R disc inserted into your CD-R (or CD-RW) writer device, starting at LBA zero.

    To do this simply write a little c++ program that calls the FFCDWrite function into the MMC1DLL.DLL.

    To get the c++ example source code follow this link.

    Important note: the disc is ready to use just after burning, and you can browse it in any CD-ROM reader. Before browsing the disc in the *same* unit it was burned in, please eject the the disc and insert it again to let the operating system scan its contents (otherwise the disc appears empty).

    The future of this project

    Next steps in the future of this project are the following:
    • buy the CD-R writer device and mount it into my Plasmon D-Series juke box
    • buy a CD label printer and build a robot to load-print-unload medias automatically (unattended)
    • invent some trick to wrap the jewel box
    I don't know whether these investments will be remunerative, because here in Italy duplicating CD-Rs is worth less than a couple of bucks per CD copy, and it is not sure a big bargain from my standpoint.

    But anycase doing this kind of things is funny. I don't know whether I will actually build the robot to load-print-unload CDs, but I am already thinking about this project. It's only a matter of building a mechanical arm, with some limit switches and electric motors. All these items will be operated, in turn, by means of my old Analog Devices RTI-815 input/output and DAC/ADC board.

    I bought my RTI-815 in 1989. It is an excellent I/O board. These are its characteristics:

    • 10 analog inputs (90 KHz sampling rate)
    • 2 analog outputs
    • 8 digital inputs
    • 8 digital outputs
    The board can be easily programmed in asm. I implemented some funny projects ten years ago.

    Final notes

    I put my best efforts to make this project clear and understandable, but I am always been writing in a hurry. If you notice any error, inconsistence, obscure phrase, or so I will be glad to repair it provided you send me a mail. Thanks for your cooperation.

    Last minute news and a little bug

    My friend Khalid Belasri, a young Moroccan engineer, sent the following link: IDiscMaster::RecordDisc. By following the link you will find the Microsoft's approach to burning a track into a MODE-1 CD-R using the Device I/O section of the Platform SDK.

    This is the description of IDiscMaster::RecordDisc function: "The RecordDisc method burns the staged image to media in the active disc recorder"; and this is its prototype:

      HRESULT RecordDisc(
        boolean bSimulate,
        boolean bEjectAfterBurn
    Try it ! (I didn't already).

    THE FOLLOWING BUG HAS BEEN FIXED as of nov. 4th 2002

    Khalid also made me note a little bug in my assembly code. The doubleword LBA is initialized (LBA=0) in the data segment of MMC1DLL.ASM and never again. This means that LBA will be filled with zero only once when the application loads MMC1DLL.DLL (using LoadLibrary() API call), and FFCDWrite will work properly only the first time it is called from the application program. Any subsequent call will fail because LBA is not reset.

    Actually LBA should be initialized each time FFCDWrite is called, and not just once at LoadLibrary time. I will fix this as soon as I can. In the meantime you can use FFCDWrite provided you load MMC1DLL.DLL (LoadLibrary), call FFCDWrite, unload the DLL (FreeLibrary) and then reload MMC1DLL.DLL (LoadLibrary again) before calling FFCDWrite again. Sorry for the inconvenience.