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

Do you the mistake in my USB descriptor?

Hello,
I am trying to add a second MSC interface to my USB device, but despite that the second interface is identified by Windows, I get a problem notification (the respective endpoint is never addressed). I just don't see what's wrong. Do you? Thanks.

/* USB Standard Device Descriptor */
const U8 USB_DeviceDescriptor[] = {
  USB_DEVICE_DESC_SIZE,              /* bLength */
  USB_DEVICE_DESCRIPTOR_TYPE,        /* bDescriptorType */
  WBVAL(0x0200), /* 2.00 */          /* bcdUSB */
  0x00,                              /* bDeviceClass */
  0x00,                              /* bDeviceSubClass */
  0x00,                              /* bDeviceProtocol */
  USB_MAX_PACKET0,                   /* bMaxPacketSize0 */
  WBVAL(0xC251),                     /* idVendor */
  WBVAL(0x1D03),                     /* idProduct */
  WBVAL(0x0100), /* 1.00 */          /* bcdDevice */
  0x01,                              /* iManufacturer */
  0x02,                              /* iProduct */
  0x03,                              /* iSerialNumber */
  0x01                               /* bNumConfigurations: one possible configuration*/
};

/* USB Configuration Descriptor */
/*   All Descriptors (Configuration, Interface, Endpoint, Class, Vendor) */
const U8 USB_ConfigDescriptor[] = {
/* Configuration 1 */
  USB_CONFIGUARTION_DESC_SIZE,       /* bLength */
  USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType */
  WBVAL(                             /* wTotalLength */
    1*USB_CONFIGUARTION_DESC_SIZE +
    2*USB_INTERFACE_DESC_SIZE     +
    4*USB_ENDPOINT_DESC_SIZE
  ),
  0x02,                              /* bNumInterfaces */
  0x01,                              /* bConfigurationValue: 0x01 is used to select this configuration */
  0x00,                              /* iConfiguration: no string to describe this configuration */
  USB_CONFIG_SELF_POWERED /*|*/       /* bmAttributes */
/*USB_CONFIG_REMOTE_WAKEUP*/,
  USB_CONFIG_POWER_MA(100),          /* bMaxPower, device power consumption is 100 mA */

/* Interface 0, Alternate Setting 0, MSC Class */
  USB_INTERFACE_DESC_SIZE,           /* bLength */
  USB_INTERFACE_DESCRIPTOR_TYPE,     /* bDescriptorType */
  0x01,                              /* bInterfaceNumber */
  0x00,                              /* bAlternateSetting */
  0x02,                              /* bNumEndpoints */
  USB_DEVICE_CLASS_STORAGE,          /* bInterfaceClass */
  MSC_SUBCLASS_SCSI,                 /* bInterfaceSubClass */
  MSC_PROTOCOL_BULK_ONLY,            /* bInterfaceProtocol */
  0x04,                              /* iInterface */

/* Endpoint, EP2 Bulk IN */
  USB_ENDPOINT_DESC_SIZE,            /* bLength */
  USB_ENDPOINT_DESCRIPTOR_TYPE,      /* bDescriptorType */
  USB_ENDPOINT_IN(2),                /* bEndpointAddress */
  USB_ENDPOINT_TYPE_BULK,            /* bmAttributes */
  WBVAL(0x0040),                     /* wMaxPacketSize */
  0x00,                              /* bInterval: ignore for Bulk transfer */

/* Endpoint, EP2 Bulk OUT */
  USB_ENDPOINT_DESC_SIZE,            /* bLength */
  USB_ENDPOINT_DESCRIPTOR_TYPE,      /* bDescriptorType */
  USB_ENDPOINT_OUT(2),               /* bEndpointAddress */
  USB_ENDPOINT_TYPE_BULK,            /* bmAttributes */
  WBVAL(0x0040),                     /* wMaxPacketSize */
  0x00,                              /* bInterval: ignore for Bulk transfer */

/* Interface 1, Alternate Setting 0, MSC Class */
  USB_INTERFACE_DESC_SIZE,           /* bLength */
  USB_INTERFACE_DESCRIPTOR_TYPE,     /* bDescriptorType */
  0x02,                              /* bInterfaceNumber */
  0x00,                              /* bAlternateSetting */
  0x02,                              /* bNumEndpoints */
  USB_DEVICE_CLASS_STORAGE,          /* bInterfaceClass */
  MSC_SUBCLASS_SCSI,                 /* bInterfaceSubClass */
  MSC_PROTOCOL_BULK_ONLY,            /* bInterfaceProtocol */
  0x05,                              /* iInterface */

/* Endpoint, EP3 Bulk IN */
  USB_ENDPOINT_DESC_SIZE,            /* bLength */
  USB_ENDPOINT_DESCRIPTOR_TYPE,      /* bDescriptorType */
  USB_ENDPOINT_IN(3),                /* bEndpointAddress */
  USB_ENDPOINT_TYPE_BULK,            /* bmAttributes */
  WBVAL(0x0040),                     /* wMaxPacketSize */
  0x00,                              /* bInterval: ignore for Bulk transfer */

/* Endpoint, EP3 Bulk OUT */
  USB_ENDPOINT_DESC_SIZE,            /* bLength */
  USB_ENDPOINT_DESCRIPTOR_TYPE,      /* bDescriptorType */
  USB_ENDPOINT_OUT(3),               /* bEndpointAddress */
  USB_ENDPOINT_TYPE_BULK,            /* bmAttributes */
  WBVAL(0x0040),                     /* wMaxPacketSize */
  0x00,                              /* bInterval: ignore for Bulk transfer */

/* Terminator */
  0                                  /* bLength */
};


/* USB String Descriptor (optional) */
const U8 USB_StringDescriptor[] = {
/* Index 0x00: LANGID Codes */
  0x04,                              /* bLength */
  USB_STRING_DESCRIPTOR_TYPE,        /* bDescriptorType */
  WBVAL(0x0409), /* US English */    /* wLANGID */
/* Index 0x01: Manufacturer */
  (13*2 + 2),                        /* bLength (13 Char + Type + lenght) */
  USB_STRING_DESCRIPTOR_TYPE,        /* bDescriptorType */
  'K',0,
  'e',0,
  'i',0,
  'l',0,
  ' ',0,
  'S',0,
  'o',0,
  'f',0,
  't',0,
  'w',0,
  'a',0,
  'r',0,
  'e',0,
/* Index 0x02: Product */
  (19*2 + 2),                        /* bLength ( 19 Char + Type + lenght) */
  USB_STRING_DESCRIPTOR_TYPE,        /* bDescriptorType */
'U',0,//  'K',0,                                         //Device manager => Universal Serial Bus controllers
'S',0,//  'e',0,
'B',0,//  'i',0,
' ',0,//  'l',0,
  ' ',0,
'L',0,//  'M',0,
'P',0,//  'C',0,
'C',0,//  'B',0,
'2',0,//  '2',0,
'4',0,//  '4',0,
'7',0,//  '0',0,
'8',0,//  '0',0,
  ' ',0,
  'M',0,
  'e',0,
  'm',0,
  'o',0,
  'r',0,
  'y',0,
/* Index 0x03: Serial Number */
  (12*2 + 2),                        /* bLength (12 Char + Type + lenght) */
  USB_STRING_DESCRIPTOR_TYPE,        /* bDescriptorType */
  '0',0,                             /* allowed characters are       */
  '0',0,                             /*   0x0030 - 0x0039 ('0'..'9') */
  '0',0,                             /*   0x0041 - 0x0046 ('A'..'F') */
  '1',0,                             /*   length >= 26               */
  'A',0,
  '0',0,
  '0',0,
  '0',0,
  '0',0,
  '0',0,
  '0',0,
  '0',0,
/* Index 0x04: Interface 0, Alternate Setting 0 */
  ( 9*2 + 2),                        /* bLength (6 Char + Type + lenght) */
  USB_STRING_DESCRIPTOR_TYPE,        /* bDescriptorType */
  'I',0,
  '/',0,
  'O',0,
  ' ',0,
  'D',0,
  'r',0,
  'i',0,
  'v',0,
  'e',0,
/* Index 0x05: Interface 1, Alternate Setting 0 */
  ( 12*2 + 2),                        /* bLength (6 Char + Type + lenght) */
  USB_STRING_DESCRIPTOR_TYPE,        /* bDescriptorType */
  'O',0,
  'u',0,
  't',0,
  'p',0,
  'u',0,
  't',0,
  ' ',0,
  'D',0,
  'r',0,
  'i',0,
  'v',0,
  'e',0,
};

Parents
  • Hello Tsuneo,

    Yes I did all that - I am now working with logical endpoints 2 and 5, which are bulk only for the LPC2478. both are now addressed, but the second interface hangs the system and eventually reports an error. So I understand that in theory, I can map a device to 2 drives?
    But, what if I want to unmount the device using SCSI commands? Am I current in assuming the I need to fail the "test unit ready" command, and to report an unmount in the ensuing "request sense"? Sorry for the basic question, I never had to work with SCSI before.

Reply
  • Hello Tsuneo,

    Yes I did all that - I am now working with logical endpoints 2 and 5, which are bulk only for the LPC2478. both are now addressed, but the second interface hangs the system and eventually reports an error. So I understand that in theory, I can map a device to 2 drives?
    But, what if I want to unmount the device using SCSI commands? Am I current in assuming the I need to fail the "test unit ready" command, and to report an unmount in the ensuing "request sense"? Sorry for the basic question, I never had to work with SCSI before.

Children
  • The two MSC interfaces work independently.
    That is, you have to implement two pairs of these handlers, so as the pairs work independently.
    - Bulk endpoint handler
    - BOT handler (CBW-CSW)
    - SCSI command handler

    Maybe some of the handlers for the second interface are still mixed up with the first one.

    When you implement it with multiple LUN (Logical Unit Number) on a single MSC interface, it's much simpler. Just dispatch the drive by LUN at SCSI handler. You don't need to touch to any other part of the implementation.

    Tsuneo

  • Tsuneo,
    Thanks for your reply. I managed to get it to work using SCSI commands that unmount the drive while the device updates the file system but I am not satisfied. I could have done the same with the soft-connect pin of the LPC2478. I am interested in the LUN solution: I had a look at the Keil USB software and to the best of my judgment, it is not supported. apart from that, what do you mean by "Just dispatch the drive by LUN at SCSI handler" ?

    thanks for your advise

  • Tsuneo,
    I understand what you mean. I report a maximum number of LUNs of 1, but my drives are not mapped in explorer. Can you say something about this? Have I forgotten something? I am using Windows XP SP3, which seems to support multiple LUNs.

  • Tsuneo,

    Thanks for your help. I managed to get it to work - quite entertaining to see my controller single MSC interface mapped to TWO explorer windows :-)
    By due to memory usage reasons we are probably going to use the soft connect pin of the LPC2478 for the duration of the file creation. we can do it with 2 drives, but it would mean a separate piece of RAM for our own FAT (RL-ARM's RAM drive is already occupied...!) and correct operation on hosts starting at XP SP3 (I thought it was implemented before?).

  • Multiple LUN implementation

    Based on this Keil example,
    LPC2368 / LPC2378 USB Mass Storage Device Example (and for LPC2458/2468)
    http://www.keil.com/download/docs/336.asp

    Get_Max_LUN request returns the last LUN supported.
    LUN numbering starts with zero.

    mscuser.c
    
    #define MSC_NUM_OF_LUNS    2                       // support two drives on this MSC IF
    #define MSC_LAST_LUN       (MSC_NUM_OF_LUNS - 1)   // LUN start with zero
    
    /*
     *  MSC Get Max LUN Request Callback
     *   Called automatically on Get Max LUN Request
     *    Parameters:      None (global SetupPacket and EP0Buf)
     *    Return Value:    TRUE - Success, FALSE - Error
     */
    
    BOOL MSC_GetMaxLUN (void) {
      EP0Buf[0] = MSC_LAST_LUN;    // return the last LUN
      return (TRUE);
    }
    

    CBW.bLUN holds the target LUN for the SCSI commands.

    /*
     *  MSC Get Command Block Wrapper Callback
     *    Parameters:      None (global variables)
     *    Return Value:    None
     */
    
    void MSC_GetCBW (void) {
      DWORD n;
    
      for (n = 0; n < BulkLen; n++) {
        *((BYTE *)&CBW + n) = BulkBuf[n];
      }
      if ((BulkLen == sizeof(CBW)) && (CBW.dSignature == MSC_CBW_Signature)) {
        /* Valid CBW */
        CSW.dTag = CBW.dTag;
        CSW.dDataResidue = CBW.dDataLength;
        if ((CBW.bLUN  > MSC_LAST_LUN) || (CBW.bCBLength < 1) || CBW.bCBLength > 16) {
    fail: CSW.bStatus = CSW_CMD_FAILED;
          MSC_SetCSW();
        } else {
          ...
    

    Handle these SCSI command for the specified drive by CBW.bLUN
    If the command does the same process for the two drives, you don't need to modify these handlers.
    mscuser.c
    - MSC_TestUnitReady()
    - MSC_Inquiry()
    - MSC_ModeSense6()
    - MSC_ModeSense10()
    - MSC_ReadFormatCapacity()
    - MSC_ReadCapacity()

    These command handler should be modified to process the target drive by the CBW.bLUN (0 or 1)
    mscuser.c
    - MSC_RequestSense()
    - MSC_RWSetup()
    - MSC_MemoryRead()
    - MSC_MemoryWrite()
    - MSC_MemoryVerify()

    For example, this MSC_MemoryRead() returns different memory location depending on LUN.

    /*
     *  MSC Memory Read Callback
     *   Called automatically on Memory Read Event
     *    Parameters:      None (global variables)
     *    Return Value:    None
     */
    
    void MSC_MemoryRead (void) {
      DWORD n;
      DWORD drive_offset;
    
      switch ( CBW.bLUN ) {
         case 0:  drive_offset = 0;
         case 1:  drive_offset = MSC_MemorySize;
      }
      if (Length > MSC_MAX_PACKET) {
        n = MSC_MAX_PACKET;
      } else {
        n = Length;
      }
    
      if ((Offset + n) > MSC_MemorySize) {
        n = MSC_MemorySize - Offset;
        BulkStage = MSC_BS_DATA_IN_LAST_STALL;
      }
    
      USB_WriteEP(MSC_EP_IN, &Memory[Offset + drive_offset], n);
      Offset += n;
      Length -= n;
    
      CSW.dDataResidue -= n;
    
      if (Length == 0) {
        BulkStage = MSC_BS_DATA_IN_LAST;
      }
    
      if (BulkStage != MSC_BS_DATA_IN) {
        FIO2CLR = LED_RD;            /* Turn Off Read LED */
        CSW.bStatus = CSW_CMD_PASSED;
      }
    }
    

    Tsuneo

  • Oops, I missed to append " break;" to each cases in above switch statement :-)



    "I could have done the same with the soft-connect pin of the LPC2478."

    When soft-connect is applied to mounted drive, Windows will complaint with surprised removal.
    Unmount (Eject) the drive on a PC application first.

    Eject USB disks using C#
    www.codeproject.com/.../usbeject.aspx

    Tsuneo

  • thanks for the tip, Tsuneo. I will do the SCSI unmount thing first, then toggle the soft connect pin.