This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

RL-ARM mass storage sample and CD-ROM

Hi my friends!

I've used RL-ARM mass storage code from sample codes of KEIL 4.03 on AT91SAM7S256.
when I attach it to PC , the system recognizes it as a flash disk, correctly;

now I want to change it to apear as a CD-ROM in windows.

I want to know any changes in code.

can anyone help me?

thanks for your help!

Parents
  • Both of USB drive (stick) and CD/DVD drive are supported by USB Mass-Storage Class, Bulk-Only Transport. Therefore, there is no difference on the USB protocol layer.

    The differences lie in the SCSI command layer.
    1) PDT (Peripheral Device Type): 00h (Direct-Access device, eg. USB drive) --> 05h (CD/DVD)

    2) Sector (Block) size: 512 byte --> 2048 bytes

    3) Required SCSI command set
    - READ10 --> READ12
    - WRITE10 --> WRITE12 (for CD-R/DVD-R)
    - Start/Stop Uint (optional --> required)
    - Read TOC (Not Available --> required) - information of sections/tracks on the CD
    -- see "5.1 READ TOC" on usb_msc_boot_1.0.pdf for bootable CD
    www.usb.org/.../usb_msc_boot_1.0.pdf

    Lastly, as of the contents on the CD image, see these specs.

    ECMA-119 (ISO9660)
    www.ecma-international.org/.../Ecma-119.htm

    Joliet Specification
    pierrelib.pagesperso-orange.fr/.../joliet_spec_v1.html

    “El Torito” Bootable CD-ROM Format Specification
    bochs.sourceforge.net/.../el-torito.pdf.gz




    > I've used RL-ARM mass storage code from sample codes of KEIL 4.03 on AT91SAM7S256.

    Is this example?
    C:\Keil\ARM\Boards\Atmel\AT91SAM7S-EK\RL\USB\RTX_Memory

    It's the first time I look in this example. With quick look, it looks like almost same as NXP LPC examples, except for the hardware layer.

    1) PDT
    PDT is reported in the reply to INQUIRY command.

    mscuser.c
    
    void MSC_Inquiry (void) {
    
      if (!DataInFormat()) return;
    
      BulkBuf[ 0] = 0x00;          /* Direct Access Device */   <--- 0x05 (CD/DVD)
      ...
    

    2) Sector (Block) size
    The sector size is defined in the mscuser.h
    It is applied to READ CAPACITY and READ FORMAT CAPACITY command, automatically.

    mscuser.h
    
    /* Mass Storage Memory Layout */
    #define MSC_MemorySize  8192  // <---- tune this size for the total CD capacity
    #define MSC_BlockSize   512   // <---- 2048
    

    3) Required SCSI command set
    Add definitions for the extra SCSI commands

    msc.h
    
    /* SCSI Commands */
    ...
    #define SCSI_READ12                     0xA8
    #define SCSI_WRITE12                    0xAA
    #define SCSI_READ_TOC                   0x43
    

    SCSI command parser is modified, as follows,

    mscuser.c
    
    void MSC_GetCBW (void) {
       ...
       ...
          switch (CBW.CB[0]) {
            ...
            ...
            case SCSI_START_STOP_UNIT:
              // goto fail;
              MSC_StartStopUnit();   // <--- add these lines
              break;
            ...
            ...
            case SCSI_READ10:        // <--- change just the label to SCSI_READ12
              ...
              ...
            case SCSI_WRITE10:       // <--- change just the label to SCSI_WRITE12
              ...
              ...
            case SCSI_READ_TOC:      // <--- add these lines
              MSC_ReadTOC();
              break;
    
    void MSC_StartStopUnit (void) {
    
      CSW.bStatus = CSW_CMD_FAILED;
    
      if (CBW.CB[4] & 0x02) {             // check LOEJ (Load/Eject) bit
        if (CBW.CB[4] & 0x01) {           // check START bit
          //
          // load medium, if required
          //
        } else {
          //
          // unload medium, if required
          //
        }
        CSW.bStatus = CSW_CMD_PASSED;
      }
      MSC_SetCSW();
    }
    
    BOOL MSC_RWSetup (void) {
      ...
      ...
      /* Number of Blocks to transfer */
    //  n = (CBW.CB[7] <<  8) |      // <--- modify these lines
    //      (CBW.CB[8] <<  0);
    
      n =   (CBW.CB[6] << 24)
          | (CBW.CB[7] << 16)
          | (CBW.CB[8] <<  8)
          | (CBW.CB[9] <<  0);
     ...
    }
    
    void MSC_ReadTOC (void) {
               // check command parameters
      if (  ((CBW.CB[1] & 0x02) != 0)     // MSF field
         || ((CBW.CB[2] & 0x0F) != 0)     // Format-A field
         || ( CBW.CB[7]         != 0x00)  // Allocation Length MSB field
         || ( CBW.CB[8]         != 0x0C)  // Allocation Length LSB field
         || ((CBW.CB[9] & 0xC0) != 0x40)  // Format-B field
         ) return;
    
               // TOC header
      BulkBuf[ 0] = 0x00;      // TOC Data Length (= 0x0A)
      BulkBuf[ 1] = 0x0A;
      BulkBuf[ 2] = 0x01;      // First Complete Session Number (= 0x01)
      BulkBuf[ 3] = 0x01;      // Last  Complete Session Number (= 0x01 for single session)
               // TOC Track Descriptor
      BulkBuf[ 4] = 0x00;      // Reserved
      BulkBuf[ 5] = 0x14;      // ADR/CTL
      BulkBuf[ 6] = 0x01;      // First Track Number in Last Complete Session
      BulkBuf[ 7] = 0x00;      // Reserved
      BulkBuf[ 8] = 0x00;      // Logical Block Address of First Track in Last Session
      BulkBuf[ 9] = 0x00;
      BulkBuf[10] = 0x00;
      BulkBuf[11] = 0x00;
    
      BulkLen = 12;
      DataInTransfer();
    }
    

    Tsuneo

Reply
  • Both of USB drive (stick) and CD/DVD drive are supported by USB Mass-Storage Class, Bulk-Only Transport. Therefore, there is no difference on the USB protocol layer.

    The differences lie in the SCSI command layer.
    1) PDT (Peripheral Device Type): 00h (Direct-Access device, eg. USB drive) --> 05h (CD/DVD)

    2) Sector (Block) size: 512 byte --> 2048 bytes

    3) Required SCSI command set
    - READ10 --> READ12
    - WRITE10 --> WRITE12 (for CD-R/DVD-R)
    - Start/Stop Uint (optional --> required)
    - Read TOC (Not Available --> required) - information of sections/tracks on the CD
    -- see "5.1 READ TOC" on usb_msc_boot_1.0.pdf for bootable CD
    www.usb.org/.../usb_msc_boot_1.0.pdf

    Lastly, as of the contents on the CD image, see these specs.

    ECMA-119 (ISO9660)
    www.ecma-international.org/.../Ecma-119.htm

    Joliet Specification
    pierrelib.pagesperso-orange.fr/.../joliet_spec_v1.html

    “El Torito” Bootable CD-ROM Format Specification
    bochs.sourceforge.net/.../el-torito.pdf.gz




    > I've used RL-ARM mass storage code from sample codes of KEIL 4.03 on AT91SAM7S256.

    Is this example?
    C:\Keil\ARM\Boards\Atmel\AT91SAM7S-EK\RL\USB\RTX_Memory

    It's the first time I look in this example. With quick look, it looks like almost same as NXP LPC examples, except for the hardware layer.

    1) PDT
    PDT is reported in the reply to INQUIRY command.

    mscuser.c
    
    void MSC_Inquiry (void) {
    
      if (!DataInFormat()) return;
    
      BulkBuf[ 0] = 0x00;          /* Direct Access Device */   <--- 0x05 (CD/DVD)
      ...
    

    2) Sector (Block) size
    The sector size is defined in the mscuser.h
    It is applied to READ CAPACITY and READ FORMAT CAPACITY command, automatically.

    mscuser.h
    
    /* Mass Storage Memory Layout */
    #define MSC_MemorySize  8192  // <---- tune this size for the total CD capacity
    #define MSC_BlockSize   512   // <---- 2048
    

    3) Required SCSI command set
    Add definitions for the extra SCSI commands

    msc.h
    
    /* SCSI Commands */
    ...
    #define SCSI_READ12                     0xA8
    #define SCSI_WRITE12                    0xAA
    #define SCSI_READ_TOC                   0x43
    

    SCSI command parser is modified, as follows,

    mscuser.c
    
    void MSC_GetCBW (void) {
       ...
       ...
          switch (CBW.CB[0]) {
            ...
            ...
            case SCSI_START_STOP_UNIT:
              // goto fail;
              MSC_StartStopUnit();   // <--- add these lines
              break;
            ...
            ...
            case SCSI_READ10:        // <--- change just the label to SCSI_READ12
              ...
              ...
            case SCSI_WRITE10:       // <--- change just the label to SCSI_WRITE12
              ...
              ...
            case SCSI_READ_TOC:      // <--- add these lines
              MSC_ReadTOC();
              break;
    
    void MSC_StartStopUnit (void) {
    
      CSW.bStatus = CSW_CMD_FAILED;
    
      if (CBW.CB[4] & 0x02) {             // check LOEJ (Load/Eject) bit
        if (CBW.CB[4] & 0x01) {           // check START bit
          //
          // load medium, if required
          //
        } else {
          //
          // unload medium, if required
          //
        }
        CSW.bStatus = CSW_CMD_PASSED;
      }
      MSC_SetCSW();
    }
    
    BOOL MSC_RWSetup (void) {
      ...
      ...
      /* Number of Blocks to transfer */
    //  n = (CBW.CB[7] <<  8) |      // <--- modify these lines
    //      (CBW.CB[8] <<  0);
    
      n =   (CBW.CB[6] << 24)
          | (CBW.CB[7] << 16)
          | (CBW.CB[8] <<  8)
          | (CBW.CB[9] <<  0);
     ...
    }
    
    void MSC_ReadTOC (void) {
               // check command parameters
      if (  ((CBW.CB[1] & 0x02) != 0)     // MSF field
         || ((CBW.CB[2] & 0x0F) != 0)     // Format-A field
         || ( CBW.CB[7]         != 0x00)  // Allocation Length MSB field
         || ( CBW.CB[8]         != 0x0C)  // Allocation Length LSB field
         || ((CBW.CB[9] & 0xC0) != 0x40)  // Format-B field
         ) return;
    
               // TOC header
      BulkBuf[ 0] = 0x00;      // TOC Data Length (= 0x0A)
      BulkBuf[ 1] = 0x0A;
      BulkBuf[ 2] = 0x01;      // First Complete Session Number (= 0x01)
      BulkBuf[ 3] = 0x01;      // Last  Complete Session Number (= 0x01 for single session)
               // TOC Track Descriptor
      BulkBuf[ 4] = 0x00;      // Reserved
      BulkBuf[ 5] = 0x14;      // ADR/CTL
      BulkBuf[ 6] = 0x01;      // First Track Number in Last Complete Session
      BulkBuf[ 7] = 0x00;      // Reserved
      BulkBuf[ 8] = 0x00;      // Logical Block Address of First Track in Last Session
      BulkBuf[ 9] = 0x00;
      BulkBuf[10] = 0x00;
      BulkBuf[11] = 0x00;
    
      BulkLen = 12;
      DataInTransfer();
    }
    

    Tsuneo

Children
  • Hey Tsuneo!
    your answers are the most unique, effective, flawless and complete ones all over this forum and any other forum i saw.

    Thank you man
    and ...
    God Bless You!(well, Keil should not forget about its own share too :D)

  • Hi Tsuneo!

    Thanks for your first help!

    I changed codes according to your help and loaded it to my board and attached it to a PC.
    It appeared as a CD-ROM in different versions of windows (WIN& & XP)(x64 & x32).

    But there is a problem, it didn't work correctly.
    Then I debugged it and I found that the MSC_ReadTOC function returns at if. . . at the beginning of function, because some of condition is true and it becomes true and the function returns.
    according to usb_msc_boot_1.0.pdf document , CBW.CB elements must be differ from what are now.

    whats your idea about this!

    And one another question:
    Original sample code of atmel consist of one image of a text file , that is copied to ram for demo in USB drive (stick) state, and the ram is the storage media. So when we attached it to computer we see a text file in it .Now we change the code to CD-ROM state , must we see it in cd-rom as before or cd-rom can't show it because of CD IMAGE concepts or other reason?

    You are best helper for this forum, thank you for your reply again. :)

  • Hi my friend , Tsuneo!

    I come back for more explanation about the problem.

    first question is that in mscuser.c , we have SCSI_READ10 in definition of function MSC_BulkIn() , we must change it to 12 or not?

    When I debug code, the CBW.CB elements that make the if statement true are:

    CBW.CB[1]= 0x02
    CBW.CB[2]= 0x00
    CBW.CB[7]= 0x03
    CBW.CB[8]= 0x24
    CBW.CB[9]= 0x00

    I think that there are some wrong parameter that are sent in previous commands before MSC-ReadTOC that make the wrong received command from pc in this point.

    please help me, thanks.

  • Hi my friend again!

    I thought that monitoring device with a application like device monitoring studio can help us, so the result is :

    command level

    START

    000027: SCSI Primary Command Set 2 (DOWN), 09.09.2012 15:46:16.282 +0.0
    Opcode:  0x12
    
    Name: INQUIRY
    Enable Vital Product Data: FALSE
    Command Support Data: FALSE
    Page or OPCODE: 0x0
    Allocation Length: 0x24
    Control: 0x0
    000030: Expected Data Received (UP), 09.09.2012 15:46:16.286 +0.002
    Size: 0x24
    
    
    000032: Command Status Wrapper (UP), 09.09.2012 15:46:16.288 +0.002
    
    
    000033: SCSI Primary Command Set 2 (DOWN), 09.09.2012 15:46:16.288 +0.0
    Opcode:  0x12
    
    Name: INQUIRY
    Enable Vital Product Data: FALSE
    Command Support Data: FALSE
    Page or OPCODE: 0x0
    Allocation Length: 0x24
    Control: 0x0
    000036: Expected Data Received (UP), 09.09.2012 15:46:16.292 +0.002
    Size: 0x24
    
    
    000038: Command Status Wrapper (UP), 09.09.2012 15:46:16.294 +0.002
    
    
    000039: SCSI Primary Command Set 2 (DOWN), 09.09.2012 15:46:16.294 +0.0
    Opcode:  0x12
    
    Name: INQUIRY
    Enable Vital Product Data: TRUE
    Command Support Data: FALSE
    Page or OPCODE: 0x80
    Allocation Length: 0xff
    Control: 0x0
    000042: Expected Data Received (UP), 09.09.2012 15:46:16.298 +0.002
    Size: 0x24
    
    
    000044: Command Status Wrapper (UP), 09.09.2012 15:46:16.299 +0.001
    
    
    000047: SCSI Primary Command Set 2 (DOWN), 09.09.2012 15:46:16.303 +0.004
    Opcode:  0x12
    
    Name: INQUIRY
    Enable Vital Product Data: FALSE
    Command Support Data: FALSE
    Page or OPCODE: 0x0
    Allocation Length: 0x24
    Control: 0x0
    000050: Expected Data Received (UP), 09.09.2012 15:46:16.306 +0.002
    Size: 0x24
    
    
    000052: Command Status Wrapper (UP), 09.09.2012 15:46:16.308 +0.002
    
    
    000053: SCSI Primary Command Set 2 (DOWN), 09.09.2012 15:46:16.308 +0.0
    Opcode:  0x12
    
    Name: INQUIRY
    Enable Vital Product Data: FALSE
    Command Support Data: FALSE
    Page or OPCODE: 0x0
    Allocation Length: 0x25
    Control: 0x0
    000056: Expected Data Received (UP), 09.09.2012 15:46:16.312 +0.002
    Size: 0x24
    
    
    000058: Command Status Wrapper (UP), 09.09.2012 15:46:16.313 +0.001
    
    
    000059: SCSI Primary Command Set 2 (DOWN), 09.09.2012 15:46:16.313 +0.0
    Opcode:  0x12
    
    Name: INQUIRY
    Enable Vital Product Data: FALSE
    Command Support Data: FALSE
    Page or OPCODE: 0x0
    Allocation Length: 0x24
    Control: 0x0
    000062: Expected Data Received (UP), 09.09.2012 15:46:16.317 +0.002
    Size: 0x24
    
    
    000064: Command Status Wrapper (UP), 09.09.2012 15:46:16.319 +0.002
    
    
    000065: SFF-8020i, MMC2 (ATAPI) command set (DOWN), 09.09.2012 15:46:16.320 +0.001
    Opcode:  0x4a
    
    Name: GET EVENT/STATUS
    IMMED: TRUE
    Notification Class Request:0x0
    Allocation Length:0x8
    Control: 0x0
    
    
    000069: SFF-8020i, MMC2 (ATAPI) command set (DOWN), 09.09.2012 15:46:16.476 +0.153
    Opcode:  0x46
    
    Name: GET CONFIGURATION (MMC)
    Request Type: LU shall return Feature Header and all Feature Descriptors
    Starting Feature Number:0x0
    Allocation Length:0x8
    Control: 0x0
    
    
    000073: SFF-8020i, MMC2 (ATAPI) command set (DOWN), 09.09.2012 15:46:16.633 +0.153
    Opcode:  0x46
    
    Name: GET CONFIGURATION (MMC)
    Request Type: LU shall return Feature Header and all Feature Descriptors
    Starting Feature Number:0x0
    Allocation Length:0x8
    Control: 0x0
    
    
    000077: SFF-8020i, MMC2 (ATAPI) command set (DOWN), 09.09.2012 15:46:16.790 +0.153
    Opcode:  0x46
    
    Name: GET CONFIGURATION (MMC)
    Request Type: LU shall return Feature Header and all Feature Descriptors
    Starting Feature Number:0x0
    Allocation Length:0x8
    Control: 0x0
    
    
    000081: SFF-8020i, MMC2 (ATAPI) command set (DOWN), 09.09.2012 15:46:16.947 +0.153
    Opcode:  0x46
    
    Name: GET CONFIGURATION (MMC)
    Request Type: LU shall return Feature Header and all Feature Descriptors
    Starting Feature Number:0x0
    Allocation Length:0x8
    Control: 0x0
    
    
    000085: SFF-8020i, MMC2 (ATAPI) command set (DOWN), 09.09.2012 15:46:17.104 +0.153
    Opcode:  0x46
    
    Name: GET CONFIGURATION (MMC)
    Request Type: LU shall return Feature Header and all Feature Descriptors
    Starting Feature Number:0x0
    Allocation Length:0x8
    Control: 0x0
    
    
    000089: SFF-8020i, MMC2 (ATAPI) command set (DOWN), 09.09.2012 15:46:17.261 +0.153
    Opcode:  0x46
    
    Name: GET CONFIGURATION (MMC)
    Request Type: LU shall return Feature Header and all Feature Descriptors
    Starting Feature Number:0x0
    Allocation Length:0x8
    Control: 0x0
    
    
    000093: SFF-8020i, MMC2 (ATAPI) command set (DOWN), 09.09.2012 15:46:17.418 +0.153
    Opcode:  0x25
    
    Name: READ CAPACITY (MMC)
    Logical Block Address:0x0
    Control: 0x0
    
    
    
    
    000097: SFF-8020i, MMC2 (ATAPI) command set (DOWN), 09.09.2012 15:46:17.575 +0.153
    Opcode:  0x25
    
    Name: READ CAPACITY (MMC)
    Logical Block Address:0x0
    Control: 0x0
    
    
    
    
    000101: SFF-8020i, MMC2 (ATAPI) command set (DOWN), 09.09.2012 15:46:17.732 +0.153
    Opcode:  0x25
    
    Name: READ CAPACITY (MMC)
    Logical Block Address:0x0
    Control: 0x0
    
    
    
    
    000105: SCSI Primary Command Set 2 (DOWN), 09.09.2012 15:46:17.889 +0.153
    
    Name: TEST UNIT READY
    Control: 0x0
    
    
    
    000108: Command Status Wrapper (UP), 09.09.2012 15:46:17.893 +0.002
    
    
    000109: SCSI Primary Command Set 2 (DOWN), 09.09.2012 15:46:18.046 +0.153
    
    Name: TEST UNIT READY
    Control: 0x0
    
    
    
    000112: Command Status Wrapper (UP), 09.09.2012 15:46:18.050 +0.002
    
    
    000113: SCSI Primary Command Set 2 (DOWN), 09.09.2012 15:46:18.050 +0.0
    
    Name: TEST UNIT READY
    Control: 0x0
    
    
    
    000116: Command Status Wrapper (UP), 09.09.2012 15:46:18.054 +0.002
    
    
    000117: SCSI Primary Command Set 2 (DOWN), 09.09.2012 15:46:18.054 +0.0
    
    Name: TEST UNIT READY
    Control: 0x0
    
    
    
    000120: Command Status Wrapper (UP), 09.09.2012 15:46:18.058 +0.002
    
    
    000121: SFF-8020i, MMC2 (ATAPI) command set (DOWN), 09.09.2012 15:46:18.058 +0.0
    Opcode:  0x43
    
    Name: READ TOC/PMA/ATIP (MMC)
    MSF: TRUE
    SUBQ: FALSE
    Track Number: 0x0
    Allocation Length:0x324
    Control: 0x0
    


    END
    After this command , no other command transferred.
    I will post mass storage level in next post.

    Thank you for your help!

  • > first question is that in mscuser.c , we have SCSI_READ10 in definition of function MSC_BulkIn() , we must change it to 12 or not?

    READ10 or READ12?
    USB MSC compliance (*1) defines READ12 is required, and READ10 is optional for CD/DVD.
    But Major OS (Windows/Linux/MacOSX) issues READ10 first. When READ10 fails, READ12 is applied. Therefore, you may support both of them; READ12 for compliance, READ10 for performance.

    The difference of READ10 and READ12 lies in the size and location of TRANSFER LENGTH parameter.
    READ10: two bytes (byte 7, 8 - starting from 0)
    READ12: four bytes (byte 6, 7, 8, 9)
    In the KEIL MSC implementation, MSC_RWSetup() picks up TRANSFER LENGTH from the CB (Command Block)

    To support both of READ10 and READ12,
    - Don't need to touch to SCSI_READ10 label and MSC_RWSetup()
    - Add extra SCSI_READ12 label and MSC_RWSetup12(), which are copied from READ10 implementation, and modified.

    mscuser.c
    void MSC_GetCBW (void) {
       ...
       ...
          switch (CBW.CB[0]) {
            ...
            ...
            case SCSI_READ10:         // <--- don't need to touch to
              ...
              // no change
              ...
            case SCSI_READ12:         // <--- Add this label and contents
              if (MSC_RWSetup12()) {  // <--- replace to MSC_RWSetup12, the rest is same as READ10
                if ((CBW.bmFlags & 0x80) != 0) {
                  AT91C_BASE_PIOA->PIO_CODR = LED1;  /* Turn On Read LED */
                  BulkStage = MSC_BS_DATA_IN;
                  MSC_MemoryRead();
                } else {
                  USB_SetStallEP(MSC_EP_OUT);
                  CSW.bStatus = CSW_PHASE_ERROR;
                  MSC_SetCSW();
                }
              }
              break;
    

    BOOL MSC_RWSetup (void) {
      ...
      // no change
      ...
    }
    
    BOOL MSC_RWSetup12 (void) {
      ...                            // <---  copy the contents of MSC_RWSetup()
      ...
      /* Number of Blocks to transfer */
    //  n = (CBW.CB[7] <<  8) |      // <--- modify these lines
    //      (CBW.CB[8] <<  0);
    
      n =   (CBW.CB[6] << 24)
          | (CBW.CB[7] << 16)
          | (CBW.CB[8] <<  8)
          | (CBW.CB[9] <<  0);
     ...
    }
    

    (*1) USB Mass Storage Class Compliance Test Specification
    www.singlix.org/.../MSC-compliance-0_9a.pdf
    4.2 Command Set Information

    Tsuneo

  • > I think that there are some wrong parameter that are sent in previous commands before MSC-ReadTOC that make the wrong received command from pc in this point.

    Windows put both of READ_TOC(MSF:0) and READ_TOC(MSF:1)
    In above implementation, just READ_TOC(MSF:0) is supported.
    To support both, MSC_ReadTOC() changes as follows,

    const BYTE SCSI_TOC_MSF0[] = {
           // TOC response header
      0x00, 0x0A,             // Data Length
      0x01,                   // First Track
      0x01,                   // Last Track
            // track descriptor
      0x00,                   // Reserved
      0x14,                   // ADR/CONTROL
      0x01,                   // Track Number
      0x00,                   // Reserved
      0x00, 0x00, 0x00, 0x00  // Track Start Address
    };
    
    const BYTE SCSI_TOC_MSF1[] = {
           // TOC response header
      0x00, 0x12,             // Data Length
      0x01,                   // First Track
      0x01,                   // Last Track
           // track descriptor 1
      0x00,                   // Reserved
      0x14,                   // ADR/CONTROL
      0x01,                   // Track Number
      0x00,                   // Reserved
      0x00, 0x00, 0x02, 0x00, // start address in MSF format (fixed)
           // track descriptor 2
      0x00,                   // Reserved
      0x14,                   // ADR/CONTROL
      0xAA,                   // Track Number: Lead-out area
      0x00,                   // Reserved
      0x00, 0x39, 0x06, 0x06  // Lead-out start address in MSF format
                              // (variable, depending on the size of track 1)
    };
    
    void MSC_ReadTOC (void) {
      if (  ((CBW.CB[1] & 0x02) == 0)     // MSF field
         && ((CBW.CB[2] & 0x0F) == 0)     // Format field
         )
      {
        memcpy( BulkBuf, SCSI_TOC_MSF0, sizeof(SCSI_TOC_MSF0) );
        BulkLen = sizeof(SCSI_TOC_MSF0);
        DataInTransfer();
      }
    
      if (  ((CBW.CB[1] & 0x02) == 1)     // MSF field
         && ((CBW.CB[2] & 0x0F) == 0)     // Format field
         )
      {
        memcpy( BulkBuf, SCSI_TOC_MSF1, sizeof(SCSI_TOC_MSF1) );
        BulkLen = sizeof(SCSI_TOC_MSF1);
        DataInTransfer();
      }
    }
    

    Tsuneo

  • > Now we change the code to CD-ROM state , must we see it in cd-rom as before or cd-rom can't show it because of CD IMAGE concepts or other reason?

    KEIL original example gives disk image in DiskImage[] ROM array (DiskImg.c).
    This disk image consists of FAT file system
    - MBR (Master Boot Record)
    - Boot sector
    - FAT
    - Root directory
    - File sectors

    For CD implementation, you have to replace the contents of the disk image into CD one, which is formatted following to ISO9660 (ECMA-119) spec (see my first post). You may easily make it using a CD-R writer utility, which has a function to make ISO9660 image file.

    At the entry of main() (memory.c), the contents of DiskImage[] is copied to Memory[] RAM array. READ10 and WRITE10 access to Memory[] array. For read-only CD, READ10 may directly access to DiskImage[] ROM array, instead of the RAM array.

    Tsuneo

  • Hi my friend Tsuneo!

    I do what you post for me but , that didn't work .
    I changed what you said and I made an iso file and fetch the byte stream of it and changed the code according that (disk Image , size , . . . ) , but when I attach device to computer , my computer (explorer) goes to a wait sate and can't work with the device.

    thank my friend!

  • Hi Mr Chinzei.

    Me and my friend Meysam were working around your solution to make our USB Mass storage device a CD-ROM.

    BUt As we started the work, lots of problems poped out.

    we changed the PDT and Sector size as you guided. We also implemented the following commands as you said: * Read12 * Write12 * Start/Stop unit * Read TOC

    Then we loaded an image of a sample CD into device memory.

    But it seams we can't get it to work, So I think we have to check it out with the standard specifications.

    We searced for some guides or references about this matter and this is what we found:

    SCSI Multimedia commands from T10.org.

    What i see in here is 6 different versions of MMC commands. I looked in MMC-4 and there's alot of commands for CD-ROM devices in it which I can't get why and how you only choosed a subset of these commands for us to implement.

    I am wondering now, whether you know an implementation guidance or a book in which the essential steps for making a CD-ROM device is explained or you use the T10 references too.

    Do you know any useful book or guide for my problem?

  • We could get our CD-ROM to work!

    I post the modifications we made to your soluton in order to help others who might read this thread later.

    First:
    I changed the Read TOC function so that it respond to all other read TOC formats too.
    It is a shame! but I responded all Formats with the same data, Like another USB CD-ROM I was monitoring its commands.

    well, my analisys is that we had to make a proper response to any Read TOC which this code do not.

    Also the '1' at second if is a logical error.

    void MSC_ReadTOC (void) {
      if (  ((CBW.CB[1] & 0x02) == 0)     // MSF field
         && ((CBW.CB[2] & 0x0F) == 0)     // Format field
         )
      {
        memcpy( BulkBuf, SCSI_TOC_MSF0, sizeof(SCSI_TOC_MSF0) );
        BulkLen = sizeof(SCSI_TOC_MSF0);
        DataInTransfer();
      }
    
      if (  ((CBW.CB[1] & 0x02) == 1)     // MSF field <-----===== Change '1' to '2'
         && ((CBW.CB[2] & 0x0F) == 0)     // Format field
         )
      {
        memcpy( BulkBuf, SCSI_TOC_MSF1, sizeof(SCSI_TOC_MSF1) );
        BulkLen = sizeof(SCSI_TOC_MSF1);
        DataInTransfer();
      }
    
    //<-----===== Put the code to handle other formats here, even if you going to fail it(i did not test the fail myself)
    
    }
    

    After this the CD can be succecfully recognized in windows, but it has two halts(1 min each).
    These halts happen after failing "Read Disc Information" and "Get Configuration Commands" which was removed after implementing these commads based on MMC commands reffrence from T10.org