2.8.2.3.1 Library Initialization
The MSD Function Driver instance for a USB Device configuration is initialized by the USB Device Layer when the Host sets that configuration. This process does not require application intervention. Each instance of the MSD Function Driver should be registered with the USB Device Layer through the Device Layer Function Driver Registration Table. While registering the MSD Function Driver, the driver member of the Function Driver Registration Table entry should be set to USB_DEVICE_MSD_FUNCTION_DRIVER. This is an opaque function driver entry point provided by the MSD Function Driver for the Device Layer to use.
The MSD Function Driver requires an initialization data structure to be defined for each instance of the function driver. This initialization data structure should be of the type USB_DEVICE_MSD_INIT. This initialization data structure contains the following:
- The number of Logical Unit Numbers (LUNs) in this MSD Function Driver instance.
- A pointer to the USB_MSD_CBW type data structure. This pointer is used by the MSD Function Driver to receive the Command Block Wrapper (CBW) from the Host. For a PIC32MZ device, this array should be placed in coherent memory and should be aligned on a 4-byte boundary.
- A pointer to the USB_MSD_CSW type data structure. This pointer is used by the MSD Function Driver to send the Command Status Wrapper (CSW) to the Host. For a PIC32MZ device, this array should be placed in coherent memory and should be aligned on a 4-byte boundary.
- A pointer to the array of media driver initialization data structure. There should be one structure for every LUN. This is a USB_DEVICE_MSD_MEDIA_INIT_DATA type of data structure. There exists a one-to-one mapping between the LUN and the media driver initialization data structure.
The following figure shows a pictorial representation of the MSD Function Driver initialization data structure.
The USB_DEVICE_MSD_MEDIA_INIT_DATA data structure allows a media driver to be plugged into the MSD Function Driver. Any media driver that needs to be plugged into the MSD Function Driver needs to implement the interface (function pointer signatures) specified by the USB_DEVICE_MSD_MEDIA_FUNCTIONS type. For every LUN, a SCSI Inquiry Response data structure needs to be made available.
Use the following guidelines while implementing the media driver:
- Read functions should be non-blocking.
- Write functions should be non-blocking.
- The media driver should provide an event to indicate when a block transfer has complete. It should allow the event handler to be registered.
- Where required, the write function should erase and write to the storage area in one operation. The MSD Function Driver does not explicitly call the erase operation.
- The media driver should provide a media geometry object when required. This media geometry object allows the MSD Function Driver to understand the media characteristics. This object is of the type, SYS_FS_MEDIA_GEOMETRY.
The following code shows an example of plugging the MPLAB Harmony NVM Driver into the MSD Function Driver. The coherency and alignment attributes that are applied to the sectorBuffer, msdCBW, and msdCBW data objects is needed for operation on PIC32MZ devices.
/*********************************************** * Sector buffer needed by for the MSD LUN. ***********************************************/ uint8_t sectorBuffer[512] __attribute__((coherent)) __attribute__((aligned(4))); /*********************************************** * CBW and CSW structure needed by the MSD * function driver instance. ***********************************************/ USB_MSD_CBW msdCBW __attribute__((coherent)) __attribute__((aligned(4))); USB_MSD_CSW msdCSW __attribute__((coherent)) __attribute__((aligned(4))); /*********************************************** * Because the PIC32MZ flash row size if 2048 * and the media sector size if 512 bytes, we * have to allocate a buffer of size 2048 * to backup the row. A pointer to this row * is passed in the media initialization data * structure. ***********************************************/ uint8_t flashRowBackupBuffer [DRV_NVM_ROW_SIZE]; /******************************************* * MSD Function Driver initialization *******************************************/ USB_DEVICE_MSD_MEDIA_INIT_DATA msdMediaInit[1] = { { DRV_NVM_INDEX_0, 512, sectorBuffer, flashRowBackupBuffer, (void *)diskImage, { 0x00, // peripheral device is connected, direct access block device 0x80, // removable 0x04, // version = 00=> does not conform to any standard, 4=> SPC-2 0x02, // response is in format specified by SPC-2 0x20, // n-4 = 36-4=32= 0x20 0x00, // sccs etc. 0x00, // bque=1 and cmdque=0,indicates simple queuing 00 is obsolete, // but as in case of other device, we are just using 00 0x00, // 00 obsolete, 0x80 for basic task queuing { 'M','i','c','r','o','c','h','p' }, { 'M','a','s','s',' ','S','t','o','r','a','g','e',' ',' ',' ',' ' }, { '0','0','0','1' } }, { DRV_NVM_IsAttached, DRV_NVM_BLOCK_Open, DRV_NVM_BLOCK_Close, DRV_NVM_GeometryGet, DRV_NVM_BlockRead, DRV_NVM_BlockEraseWrite, DRV_NVM_IsWriteProtected, DRV_NVM_BLOCK_EventHandlerSet, DRV_NVM_BlockStartAddressSet } } }; /******************************************* * MSD Function Driver initialization *******************************************/ USB_DEVICE_MSD_INIT msdInit = { /* Number of LUNS */ 1, /* Pointer to a CBW structure */ &msdCBW, /* Pointer to a CSW structure */ &msdCSW, /* Pointer to a table of Media Initialization data structures */ &msdMediaInit[0] }; /***************************************************** * USB Device Function Registration Table *****************************************************/ const USB_DEVICE_FUNCTION_REGISTRATION_TABLE funcRegistrationTable[1] = { { .speed = USB_SPEED_FULL | USB_SPEED_HIGH, // Device Speed .configurationValue = 1, // Configuration value .interfaceNumber = 0, // Start interface number .numberOfInterfaces = 1, // Number of interfaces owned .funcDriverIndex = 0, // Function driver index .funcDriverInit = (void*)&msdInit, // Pointer to initialization data structure .driver = USB_DEVICE_MSD_FUNCTION_DRIVER // Pointer to function driver } };