Board Support Packages

Updated: April 19, 2023

If you have a BSP for QNX SDP 6.6 or earlier, and you need to update that BSP to QNX SDP 7.x, we recommend that you do so as follows:

  1. Find a QNX SDP 7.x BSP that uses the same (or similar) SoC or CPU as your BSP.
  2. Create a copy of the version 7.x BSP, and then incorporate any custom code from your BSP into it (in particular, board startup code, IPL code, and any device driver code that you may have modified).

QNX SDP 7.x includes the latest, up-to-date versions of various startup library code, other support libraries, device drivers, and utilities; even if you manually update an older BSP so that it compiles in a QNX SDP 7.x environment, you won't necessarily incorporate all of these changes and updates into your own updated BSP, and may wind up with something that isn't equivalent to an SDP 7.x BSP. Therefore, we recommend incorporating your board-specific code deltas into an existing QNX SDP 7.x BSP, rather than attempt to manually bring a QNX SDP 6.x BSP forward to SDP 7.x.

For more information about working with BSPs, see the Using QNX BSPs chapter of Building Embedded Systems. See also QNX SDP 7.1: Troubleshooting Board Support Packages, which you can download from our website at http://www.qnx.com/download/feature.html?programid=51297.

Audio drivers

Updates to io-audio require audio drivers (deva-*) to make some minor modifications to work in QNX SDP 7.1.

QSA trigger callbacks

To allow a deva -* driver to respond to a stop based on its cause, the ADO_PCM_TRIGGER_STOP command in the pcm_trigger enumeration is now replaced by two commands:
enum pcm_trigger
{
    ADO_PCM_TRIGGER_GO,
    ADO_PCM_TRIGGER_STOP_DRAIN,
    ADO_PCM_TRIGGER_STOP_DROP,
};
ADO_PCM_TRIGGER_STOP_DRAIN
Stop the interface after the buffered data has been played to completion.
ADO_PCM_TRIGGER_STOP_DROP
Stop the interface immediately and drop or discard buffered data.
To take advantage of the new commands, you must update your drivers.

In most cases, the deva -* driver does not need to distinguish the reason for a stop and can continue to use a basic if else statement. For example:

if (cmd == ADO_PCM_TRIGGER_GO)
{
    ...
    ...
}
else
{
/* STOP */
    ...
    ...
}
Drivers that handle the drain and drop stops differently can check the stop command as needed. For example:
switch (cmd)
{
    case ADO_PCM_TRIGGER_GO:
        break;
    case ADO_PCM_TRIGGER_STOP_DROP:
        break;
    case ADO_PCM_TRIGGER_STOP_DRAIN:
        break;
    default:
          break;
}

Audio driver mixer APIs and PCM channel maps

The audio driver mixer APIs have been updated to use snd_pcm_chmap_t to provide channel location information.

Function or structure Required update
ado_mixer_group_create()

ado_mixer_playback_group_create()

ado_mixer_capture_group_create()
Replace uint32_t channels with snd_pcm_chmap_t *chmap.
ado_mixer_element_balance1() Replace uint32_t chan_mask with snd_pcm_chmap_t *chmap.
ado_chmap_to_mixer_chn() Change return value from uint32_t to uint64_t.
ado_mixer_element_io()

ado_mixer_element_sw3()

Replace snd_mixer_voice_t array with a snd_pcm_chmap_t *chmap.
ado_mixer_dgroup_t
  • Replace uint32_t channels with uint64_t channels.
  • Remove number_of_channels and first_channel_index members.
  • Add snd_pcm_chmap_t *chmap.

Volume and mute callback

Any driver code that handles volume levels and mute callback needs to be updated to handle volume and mute data as contiguous channel sets.

Do not use SND_MIXER_CHN_* definitions to index into volume arrays or mute bits in your volume and mute callbacks. Volume and mute data are contiguous channel sets based on the ordering defined in the PCM channel map (snd_chmap_t). Because everything is contiguous, you can directly use the loop index when you walk the channels.

ado_pcm_capabilities_t

The ado_pcm_capabilities_t structure now includes a channel map that should be filled in. If you do not fill it, io-audio automatically creates a default channel map based on the number of voices. You can use the ado_pcm_get_default_chmap() helper function to get the default map.

However, to expose the channel mapping clearly, QNX recommends that the driver set the channel mapping explicitly using ado_pcm_get_default_chmap(), ado_pcm_parse_chmap() or by manually creating a channel map.

The ado_pcm_parse_chmap() function allows you to create a channel map based on command line options. Because the channel map it returns is allocated on the heap (unlike the static, default channel maps), it is the driver's responsibility to free this channel map in the ctrl_destroy() callback.

For example:

ctrl_init()
{
   .
   .
   .
   if (hw_ctx->tx_chmap)
   {
      /* chmap was allocated from command line parsing */
      hw_ctx->playback.pcm_caps.chmap = hw_ctx->tx_chmap;
   }
   else
   {
      /* No chmap was provided on the command line, use a static default chmap */
      hw_ctx->playback.pcm_caps.chmap = ado_pcm_get_default_chmap(hw_ctx->playback.voices);
   }
   /* Do the same for capture */
   ado_pcm_create(…);
   .
   .
   .
}


ctrl_destroy()
{
   .
   .
   .
   if (hw_ctx->tx_chmap)
      ado_free(hw_ctx->tx_chmap);

   if (hw_ctx->rx_chmap)
      ado_free(hw_ctx->rx_chmap);
   
   ado_free(hw_ctx);
}

The ctrl_version() callback

The date argument of the ctrl_version() callback has been updated from char * to a char**:

ado_dll_version_t ctrl_version;
void ctrl_version (int *major, int *minor, const char **date)
{
    *major = ADO_MAJOR_VERSION;
    *minor = 1;
    *date = __DATE__;
}

Memory and PCI APIs

The following memory functions now require an ado_card_t pointer as the first parameter:

Function Synopsis
ado_device_mmap()
ado_device_mmap ( ado_card_t *card,
                  unsigned long addr ,
                  unsigned long size )
ado_device_munmap()
ado_device_munmap ( ado_card_t *card,
                    void *addr ,
                    unsigned long size )
ado_device_mmap_io()
uintptr_t ado_device_mmap_io ( ado_card_t *card,
                               unsigned long addr ,
                               unsigned long size )
ado_device_munmap_io ()
int ado_device_munmap_io ( ado_card_t *card,
                           uintptr_t addr ,
                           unsigned long size )
ado_pcm_buf_alloc()
void *ado_pcm_buf_alloc ( ado_card_t *card,
                          struct ado_pcm_config *config ,
                          size_t size ,
                          uint32_t flags );
ado_pcm_buf_map()
void *ado_pcm_buf_map ( ado_card_t *card,
                        struct ado_pcm_config *config ,
                        off64_t phys_addr ,
                        size_t size ,
                        uint32_t flags );
ado_pcm_buf_free()
void ado_pcm_buf_free ( ado_card_t *card,
                        struct ado_pcm_config *config );

The following PCM functions have been removed and replaced:

Removed function Replacement function
ado_shm_alloc() ado_pcm_buf_alloc()
ado_shm_map() ado_pcm_buf_map()
ado_shm_free() ado_pcm_buf_free()

The ado_pcm_buf_*() functions create shared memory objects for the buffers so that libasound can access the memory for client data processing via the libasound MMAP plugin.

In addition, there are two new functions for more general physical memory mappings: ado_mmap_phys() and ado_munmap_phys(). These mappings would be private to the driver (no shared object created for exposure via libasound MMAP plugin).

PCM buffer allocations should use the ado_pcm_buf_*() functions and generic physical memory allocations should use ado_mmap_phys(). Device registers mappings should continue to use ado_device_*() functions.

The following PCI functions now require an ado_card_t pointer as the first parameter:

Function Synopsis
ado_pci_device()
struct ado_pci *ado_pci_device ( ado_card_t *card,
                                 uint32_t vendor ,
                                 uint32_t device ,
                                 char *args )
ado_device_munmap()
void ado_pci_release ( ado_card_t *card,
                       struct ado_pci *pci )