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!
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
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.
> 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
View all questions in Keil forum