summaryrefslogblamecommitdiffstats
path: root/cpukit/libblock/src/media.c
blob: c176e12243d3ff9a6c41c3f18b7f09440f58bc8d (plain) (tree)
1
2
3
4
5
6
7
8
9








                               
                                                                      

                        
                 





                                                          
                                        

   
                   

                   
                   
 

                        

                        
                         

                         
                        
                         






                                     
               




















                                                     
                                                                  
 
                      
 
                                 



                        
                                   



























                                                                           
                      
 










                                                                        
            
                           
     

                        

   

           








                                              
                      
 
         
 
                                               
 




                                                 

   

           
















































                                                                        


                                                          











                                       
                                               



























                                                            
                                                       
                                             

















































































































































































                                                                               
                                                


                                                     

                                                             
                                 
                                      
            









                                                  
     
 


                                               




























                                                   
                                            


















                                                                           




                                                                         




                                  
                    



                        
                                                                            











































































                                                   
                                                                 




                            


                                       
                  
                 














                                                     
                                           



                                          

               
                               
                           
                 

























                                                        
                           





































































































                                                                           

                               











































                                            

                               

 


                                           
                         
 
                  

                           




















































































































                                                                               
         































                                                                   
/**
 * @file
 *
 * @ingroup RTEMSMedia
 *
 * @brief Media implementation.
 */

/*
 * Copyright (c) 2009-2013 embedded brains GmbH.  All rights reserved.
 *
 *  embedded brains GmbH
 *  Dornierstr. 4
 *  82178 Puchheim
 *  Germany
 *  <rtems@embedded-brains.de>
 *
 * The license and distribution terms for this file may be
 * found in the file LICENSE in this distribution or at
 * http://www.rtems.org/license/LICENSE.
 */

#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>

#include <rtems/media.h>

#include <rtems.h>
#include <rtems/bdbuf.h>
#include <rtems/blkdev.h>
#include <rtems/bdpart.h>
#include <rtems/libio.h>
#include <rtems/dosfs.h>
#include <rtems/thread.h>

typedef struct {
  rtems_bdpart_partition *partitions;
  size_t *count;
} partition_table;

typedef struct {
  size_t index;
  rtems_blkdev_bnum begin;
  rtems_blkdev_bnum count;
} partition;

typedef struct media_item {
  rtems_chain_node node;
  struct media_item *parent;
  char *disk_path;
  char *mount_path;
} media_item;

typedef struct listener_item {
  rtems_chain_node node;
  rtems_media_listener listener;
  void *listener_arg;
} listener_item;

static RTEMS_CHAIN_DEFINE_EMPTY(listener_item_chain);

static RTEMS_CHAIN_DEFINE_EMPTY(media_item_chain);

static rtems_mutex media_mutex = RTEMS_MUTEX_INITIALIZER("Media");

static void lock(void)
{
  rtems_mutex_lock(&media_mutex);
}

static void unlock(void)
{
  rtems_mutex_unlock(&media_mutex);
}

static listener_item *find_listener(
  rtems_media_listener listener,
  void *listener_arg
)
{
  rtems_chain_node *node = rtems_chain_first(&listener_item_chain);

  while (!rtems_chain_is_tail(&listener_item_chain, node)) {
    listener_item *item = (listener_item *) node;

    if (item->listener == listener && item->listener_arg == listener_arg) {
      return item;
    }

    node = rtems_chain_next(node);
  }

  return NULL;
}

rtems_status_code rtems_media_listener_add(
  rtems_media_listener listener,
  void *listener_arg
)
{
  rtems_status_code sc = RTEMS_SUCCESSFUL;
  listener_item *item;

  lock();

  item = find_listener(listener, listener_arg);

  if (item == NULL) {
    item = malloc(sizeof(*item));
    if (item != NULL) {
      item->listener = listener;
      item->listener_arg = listener_arg;
      rtems_chain_initialize_node(&item->node);
      rtems_chain_append_unprotected(&listener_item_chain, &item->node);
    } else {
      sc = RTEMS_NO_MEMORY;
    }
  } else {
    sc = RTEMS_TOO_MANY;
  }

  unlock();

  return sc;
}

rtems_status_code rtems_media_listener_remove(
  rtems_media_listener listener,
  void *listener_arg
)
{
  rtems_status_code sc = RTEMS_SUCCESSFUL;
  listener_item *item;

  lock();

  item = find_listener(listener, listener_arg);

  if (item != NULL) {
    rtems_chain_extract_unprotected(&item->node);
    free(item);
  } else {
    sc = RTEMS_INVALID_ID;
  }

  unlock();

  return sc;
}

static rtems_status_code notify(
  rtems_media_event event,
  rtems_media_state state,
  const char *src,
  const char *dest
)
{
  rtems_status_code sc = RTEMS_SUCCESSFUL;
  rtems_status_code rsc = RTEMS_SUCCESSFUL;
  rtems_chain_node *node = rtems_chain_first(&listener_item_chain);

  while (!rtems_chain_is_tail(&listener_item_chain, node)) {
    listener_item *item = (listener_item *) node;

    sc = (*item->listener)(event, state, src, dest, item->listener_arg);
    if (sc != RTEMS_SUCCESSFUL) {
      rsc = sc;
    }

    node = rtems_chain_next(node);
  }

  return rsc;
}

static void error(
  rtems_media_state state,
  const char *src,
  const char *dest
)
{
  notify(RTEMS_MEDIA_EVENT_ERROR, state, src, dest);
}

static media_item *get_media_item(
  const char *disk_path,
  const char *mount_path
)
{
  rtems_chain_node *node = rtems_chain_first(&media_item_chain);

  while (!rtems_chain_is_tail(&media_item_chain, node)) {
    media_item *item = (media_item *) node;

    if (
      (disk_path == NULL || strcmp(disk_path, item->disk_path) == 0)
        && (mount_path == NULL
          || (item->mount_path != NULL
            && strcmp(mount_path, item->mount_path) == 0))
    ) {
      return item;
    }

    node = rtems_chain_next(node);
  }

  return NULL;
}

static void free_item(media_item *item)
{
  rtems_chain_extract_unprotected(&item->node);
  free(item->mount_path);
  free(item);
}

static void create_item(
  media_item *parent,
  const char *disk_path,
  const char *mount_path
)
{
  size_t disk_path_size = strlen(disk_path) + 1;
  media_item *item = malloc(sizeof(*item) + disk_path_size);

  if (item != NULL) {
    if (mount_path != NULL) {
      item->mount_path = strdup(mount_path);

      if (item->mount_path == NULL) {
        free(item);

        return;
      }
    } else {
      item->mount_path = NULL;
    }

    item->parent = parent;
    item->disk_path = (char *) item + sizeof(*item);
    memcpy(item->disk_path, disk_path, disk_path_size);
    rtems_chain_initialize_node(&item->node);
    rtems_chain_append(&media_item_chain, &item->node);
  }
}

static void remove_mount_point(const char *mount_path)
{
  media_item *item = get_media_item(NULL, mount_path);

  if (item != NULL) {
    free(item->mount_path);
    item->mount_path = NULL;
  } else {
    error(RTEMS_MEDIA_ERROR_MOUNT_POINT_UNKNOWN, mount_path, NULL);
  }
}

static void remove_partition(const char *partition_path)
{
  media_item *item = get_media_item(partition_path, NULL);

  if (item != NULL) {
    if (item->mount_path != NULL) {
      error(
        RTEMS_MEDIA_ERROR_PARTITION_DETACH_WITH_MOUNT,
        partition_path,
        item->mount_path
      );
    }
    free_item(item);
  } else {
    error(RTEMS_MEDIA_ERROR_PARTITION_UNKNOWN, partition_path, NULL);
  }
}

static void remove_disk(const char *disk_path)
{
  media_item *item = get_media_item(disk_path, NULL);

  if (item != NULL) {
    rtems_chain_node *node = rtems_chain_first(&media_item_chain);

    while (!rtems_chain_is_tail(&media_item_chain, node)) {
      media_item *child = (media_item *) node;

      node = rtems_chain_next(node);

      if (child->parent == item) {
        if (child->mount_path != NULL) {
          error(
            RTEMS_MEDIA_ERROR_MOUNT_POINT_ORPHAN,
            child->mount_path,
            disk_path
          );
        }
        error(RTEMS_MEDIA_ERROR_PARTITION_ORPHAN, child->disk_path, disk_path);
        free_item(child);
      }
    }

    free_item(item);
  } else {
    error(RTEMS_MEDIA_ERROR_DISK_UNKNOWN, disk_path, NULL);
  }
}

static void add_disk(const char *disk_path)
{
  media_item *item = get_media_item(disk_path, NULL);

  if (item != NULL) {
    error(RTEMS_MEDIA_ERROR_DISK_EXISTS, disk_path, NULL);
    remove_disk(disk_path);
  }

  create_item(NULL, disk_path, NULL);
}

static void add_partition(const char *disk_path, const char *partition_path)
{
  media_item *item = get_media_item(partition_path, NULL);
  media_item *parent = get_media_item(disk_path, NULL);

  if (item != NULL) {
    error(RTEMS_MEDIA_ERROR_DISK_OR_PARTITION_EXISTS, partition_path, NULL);
    remove_disk(partition_path);
  }

  if (parent != NULL) {
    create_item(parent, partition_path, NULL);
  } else {
    error(
      RTEMS_MEDIA_ERROR_PARTITION_WITH_UNKNOWN_DISK,
      partition_path,
      disk_path
    );
  }
}

static void add_mount_point(const char *disk_path, const char *mount_path)
{
  media_item *item = get_media_item(disk_path, NULL);

  if (item != NULL) {
    if (item->mount_path != NULL) {
      error(RTEMS_MEDIA_ERROR_MOUNT_POINT_EXISTS, item->mount_path, NULL);
      free(item->mount_path);
    }
    item->mount_path = strdup(mount_path);
  } else {
    error(RTEMS_MEDIA_ERROR_DISK_OR_PARTITION_UNKNOWN, disk_path, NULL);
  }
}

static bool is_add_state(rtems_media_state state)
{
  return state == RTEMS_MEDIA_STATE_SUCCESS;
}

static bool is_remove_state(rtems_media_state state)
{
  return state == RTEMS_MEDIA_STATE_SUCCESS
    || state == RTEMS_MEDIA_STATE_FAILED;
}

static rtems_status_code remember_event(
  rtems_media_event event,
  rtems_media_state state,
  const char *src,
  const char *dest
)
{
  switch (event) {
    case RTEMS_MEDIA_EVENT_DISK_ATTACH:
      if (is_add_state(state)) {
        add_disk(dest);
      }
      break;
    case RTEMS_MEDIA_EVENT_PARTITION_ATTACH:
      if (is_add_state(state)) {
        add_partition(src, dest);
      }
      break;
    case RTEMS_MEDIA_EVENT_MOUNT:
      if (is_add_state(state)) {
        add_mount_point(src, dest);
      }
      break;
    case RTEMS_MEDIA_EVENT_UNMOUNT:
      if (is_remove_state(state)) {
        remove_mount_point(src);
      }
      break;
    case RTEMS_MEDIA_EVENT_PARTITION_DETACH:
      if (is_remove_state(state)) {
        remove_partition(src);
      }
      break;
    case RTEMS_MEDIA_EVENT_DISK_DETACH:
      if (is_remove_state(state)) {
        remove_disk(src);
      }
      break;
    default:
      break;
  }

  return RTEMS_SUCCESSFUL;
}

static rtems_status_code process_event(
  rtems_media_event event,
  const char *src,
  char **dest_ptr,
  rtems_media_worker worker,
  void *worker_arg
)
{
  rtems_status_code sc = RTEMS_SUCCESSFUL;
  rtems_status_code sc_retry = RTEMS_SUCCESSFUL;
  rtems_media_state state = RTEMS_MEDIA_STATE_FAILED;
  char *dest = NULL;

  do {
    sc = notify(event, RTEMS_MEDIA_STATE_INQUIRY, src, NULL);
    if (sc == RTEMS_SUCCESSFUL) {
      state = RTEMS_MEDIA_STATE_READY;
    } else {
      state = RTEMS_MEDIA_STATE_ABORTED;
    }

    sc = (*worker)(state, src, &dest, worker_arg);
    if (state == RTEMS_MEDIA_STATE_READY) {
      if (sc == RTEMS_SUCCESSFUL) {
        state = RTEMS_MEDIA_STATE_SUCCESS;
      } else {
        state = RTEMS_MEDIA_STATE_FAILED;
      }
    }

    sc_retry = notify(event, state, src, dest);
  } while (state == RTEMS_MEDIA_STATE_FAILED
    && sc_retry == RTEMS_INCORRECT_STATE);
  remember_event(event, state, src, dest);

  if (state == RTEMS_MEDIA_STATE_SUCCESS) {
    sc = RTEMS_SUCCESSFUL;
  } else if (state == RTEMS_MEDIA_STATE_ABORTED) {
    sc = RTEMS_UNSATISFIED;
  } else {
    sc = RTEMS_IO_ERROR;
  }

  if (dest_ptr != NULL && sc == RTEMS_SUCCESSFUL) {
    *dest_ptr = dest;
  } else {
    free(dest);
  }

  return sc;
}

static rtems_status_code mount_worker(
  rtems_media_state state,
  const char *src,
  char **dest,
  void *worker_arg
)
{
  int rv = 0;

  if (state == RTEMS_MEDIA_STATE_READY) {
    rtems_dosfs_mount_options mount_options;
    char *mount_path = NULL;

    if (worker_arg == NULL) {
      mount_path = rtems_media_replace_prefix(RTEMS_MEDIA_MOUNT_BASE, src);
    } else {
      mount_path = strdup(worker_arg);
    }

    if (mount_path == NULL) {
      return RTEMS_IO_ERROR;
    }

    rv = rtems_mkdir(mount_path, S_IRWXU | S_IRWXG | S_IRWXO);
    if (rv != 0) {
      free(mount_path);

      return RTEMS_IO_ERROR;
    }

    memset(&mount_options, 0, sizeof(mount_options));

    /* In case this fails, we fall back to use the default converter */
    mount_options.converter = rtems_dosfs_create_utf8_converter("CP850");

    rv = mount(
      src,
      mount_path,
      RTEMS_FILESYSTEM_TYPE_DOSFS,
      RTEMS_FILESYSTEM_READ_WRITE,
      &mount_options
    );
    if (rv != 0) {
      rmdir(mount_path);
      free(mount_path);
      (*mount_options.converter->handler->destroy)(mount_options.converter);

      return RTEMS_IO_ERROR;
    }

    *dest = mount_path;
  }

  return RTEMS_SUCCESSFUL;
}

static rtems_status_code do_mount(
  const char *src,
  char **dest_ptr,
  rtems_media_worker worker,
  void *worker_arg
)
{
  if (worker == NULL) {
    worker = mount_worker;
  }

  return process_event(
    RTEMS_MEDIA_EVENT_MOUNT,
    src,
    dest_ptr,
    worker,
    worker_arg
  );
}

static rtems_status_code do_partition_attach(
  const char *src,
  char **dest_ptr,
  rtems_media_worker worker,
  void *worker_arg
)
{
  rtems_status_code sc = RTEMS_SUCCESSFUL;
  char *part_path = NULL;

  if (worker != NULL) {
    sc = process_event(
      RTEMS_MEDIA_EVENT_PARTITION_ATTACH,
      src,
      &part_path,
      worker,
      worker_arg
    );

    if (sc == RTEMS_SUCCESSFUL) {
      sc = do_mount(part_path, NULL, NULL, NULL);
    }
  } else {
    sc = RTEMS_INVALID_ADDRESS;
  }

  if (dest_ptr != NULL && sc == RTEMS_SUCCESSFUL) {
    *dest_ptr = part_path;
  } else {
    free(part_path);
  }

  return sc;
}

static rtems_status_code partition_attach_worker(
  rtems_media_state state,
  const char *src,
  char **dest,
  void *worker_arg
)
{
  rtems_status_code sc = RTEMS_SUCCESSFUL;

  if (state == RTEMS_MEDIA_STATE_READY) {
    partition *part = worker_arg;
    char *part_path = rtems_media_append_minor(src, part->index);

    if (part_path == NULL) {
      return RTEMS_IO_ERROR;
    }

    sc = rtems_blkdev_create_partition(
      part_path,
      src,
      part->begin,
      part->count
    );
    if (sc != RTEMS_SUCCESSFUL) {
      free(part_path);

      return RTEMS_IO_ERROR;
    }

    *dest = part_path;
  }

  return RTEMS_SUCCESSFUL;
}

static rtems_status_code attach_and_mount_partitions(
  const char *disk_path,
  const rtems_bdpart_partition *partitions,
  size_t count
)
{
  rtems_status_code sc = RTEMS_SUCCESSFUL;
  size_t i = 0;

  for (i = 0; i < count; ++i) {
    partition part_desc = {
      .index = i,
      .begin = partitions [i].begin,
      .count = partitions [i].end - partitions [i].begin
    };
    char *part_path = NULL;

    sc = process_event(
      RTEMS_MEDIA_EVENT_PARTITION_ATTACH,
      disk_path,
      &part_path,
      partition_attach_worker,
      &part_desc
    );

    if (sc == RTEMS_SUCCESSFUL) {
      sc = do_mount(part_path, NULL, NULL, NULL);
    }

    free(part_path);
  }

  return sc;
}

static rtems_status_code partition_inquiry_worker(
  rtems_media_state state,
  const char *src,
  char **dest RTEMS_UNUSED,
  void *worker_arg
)
{
  rtems_status_code sc = RTEMS_SUCCESSFUL;

  if (state == RTEMS_MEDIA_STATE_READY) {
    partition_table *pt = worker_arg;
    rtems_bdpart_format format;

    sc = rtems_bdpart_read(src, &format, pt->partitions, pt->count);
    if (sc != RTEMS_SUCCESSFUL || *pt->count == 0) {
      return RTEMS_IO_ERROR;
    }
  }

  return RTEMS_SUCCESSFUL;
}

static rtems_status_code do_partition_inquiry(
  const char *src,
  char **dest_ptr,
  rtems_media_worker worker,
  void *worker_arg
)
{
  rtems_status_code sc = RTEMS_SUCCESSFUL;

  if (worker == NULL) {
    rtems_bdpart_partition partitions [RTEMS_BDPART_PARTITION_NUMBER_HINT];
    size_t count = RTEMS_BDPART_PARTITION_NUMBER_HINT;
    partition_table pt = {
     .partitions = partitions,
     .count = &count
    };

    sc = process_event(
      RTEMS_MEDIA_EVENT_PARTITION_INQUIRY,
      src,
      dest_ptr,
      partition_inquiry_worker,
      &pt
    );

    if (sc == RTEMS_SUCCESSFUL) {
      sc = attach_and_mount_partitions(src, partitions, count);
    }
  } else {
    sc = process_event(
      RTEMS_MEDIA_EVENT_PARTITION_INQUIRY,
      src,
      dest_ptr,
      worker,
      worker_arg
    );
  }

  return sc;
}

static rtems_status_code do_disk_attach(
  const char *src,
  char **dest_ptr,
  rtems_media_worker worker,
  void *worker_arg
)
{
  rtems_status_code sc = RTEMS_SUCCESSFUL;
  rtems_status_code rsc = RTEMS_SUCCESSFUL;
  char *disk_path = NULL;

  if (worker != NULL) {
    rsc = process_event(
      RTEMS_MEDIA_EVENT_DISK_ATTACH,
      src,
      &disk_path,
      worker,
      worker_arg
    );
    
    if (rsc == RTEMS_SUCCESSFUL) {
      sc = do_mount(disk_path, NULL, NULL, NULL);

      if (sc != RTEMS_SUCCESSFUL) {
        do_partition_inquiry(disk_path, NULL, NULL, NULL);
      }
    }
  } else {
    rsc = RTEMS_INVALID_ADDRESS;
  }

  if (dest_ptr != NULL && rsc == RTEMS_SUCCESSFUL) {
    *dest_ptr = disk_path;
  } else {
    free(disk_path);
  }

  return rsc;
}

static rtems_status_code unmount_worker(
  rtems_media_state state,
  const char *src,
  char **dest RTEMS_UNUSED,
  void *worker_arg RTEMS_UNUSED
)
{
  rtems_status_code sc = RTEMS_SUCCESSFUL;

  if (state == RTEMS_MEDIA_STATE_READY) {
    int rv = unmount(src);

    if (rv == 0) {
      rv = rmdir(src);
      if (rv != 0) {
        sc = RTEMS_IO_ERROR;
      }
    } else {
      sc = RTEMS_IO_ERROR;
    }
  }

  return sc;
}

static rtems_status_code do_unmount(
  const char *src,
  char **dest_ptr,
  rtems_media_worker worker,
  void *worker_arg
)
{
  if (worker == NULL) {
    worker = unmount_worker;
    worker_arg = NULL;
  }

  return process_event(
    RTEMS_MEDIA_EVENT_UNMOUNT,
    src,
    dest_ptr,
    worker,
    worker_arg
  );
}

static rtems_status_code disk_detach_worker(
  rtems_media_state state,
  const char *src,
  char **dest RTEMS_UNUSED,
  void *worker_arg RTEMS_UNUSED
)
{
  rtems_status_code rsc = RTEMS_SUCCESSFUL;

  if (state == RTEMS_MEDIA_STATE_READY) {
    int rv = unlink(src);

    if (rv != 0) {
      rsc = RTEMS_IO_ERROR;
    }
  }

  return rsc;
}

static rtems_status_code detach_item(rtems_media_event event, media_item *item)
{
  rtems_status_code sc = RTEMS_SUCCESSFUL;
  rtems_status_code rsc = RTEMS_SUCCESSFUL;

  if (item->mount_path != NULL) {
    sc = do_unmount(item->mount_path, NULL, NULL, NULL);
    if (sc != RTEMS_SUCCESSFUL) {
      rsc = RTEMS_IO_ERROR;
    }
  }

  sc = process_event(event, item->disk_path, NULL, disk_detach_worker, NULL);
  if (sc != RTEMS_SUCCESSFUL) {
    rsc = RTEMS_IO_ERROR;
  }

  return rsc;
}

static rtems_status_code detach_parent_item(media_item *parent)
{
  rtems_status_code sc = RTEMS_SUCCESSFUL;
  rtems_status_code rsc = RTEMS_SUCCESSFUL;

  rtems_chain_node *node = rtems_chain_first(&media_item_chain);

  while (!rtems_chain_is_tail(&media_item_chain, node)) {
    media_item *child = (media_item *) node;

    node = rtems_chain_next(node);

    if (child->parent == parent) {
      sc = detach_item(RTEMS_MEDIA_EVENT_PARTITION_DETACH, child);
      if (sc != RTEMS_SUCCESSFUL) {
        rsc = RTEMS_IO_ERROR;
      }
    }
  }

  sc = detach_item(RTEMS_MEDIA_EVENT_DISK_DETACH, parent);
  if (sc != RTEMS_SUCCESSFUL) {
    rsc = RTEMS_IO_ERROR;
  }

  return rsc;
}

static rtems_status_code do_disk_detach(
  const char *src,
  char **dest_ptr,
  rtems_media_worker worker,
  void *worker_arg
)
{
  if (worker == NULL) {
    media_item *parent = get_media_item(src, NULL);

    if (parent != NULL) {
      return detach_parent_item(parent);
    }

    worker = disk_detach_worker;
    worker_arg = NULL;
  }

  return process_event(
    RTEMS_MEDIA_EVENT_DISK_DETACH,
    src,
    dest_ptr,
    worker,
    worker_arg
  );
}

static rtems_status_code do_partition_detach(
  const char *src,
  char **dest_ptr,
  rtems_media_worker worker,
  void *worker_arg
)
{
  if (worker == NULL) {
    media_item *item = get_media_item(src, NULL);

    if (item != NULL) {
      return detach_item(RTEMS_MEDIA_EVENT_PARTITION_DETACH, item);
    }

    worker = disk_detach_worker;
    worker_arg = NULL;
  }

  return process_event(
    RTEMS_MEDIA_EVENT_PARTITION_DETACH,
    src,
    dest_ptr,
    worker,
    worker_arg
  );
}

rtems_status_code rtems_media_post_event(
  rtems_media_event event,
  const char *src,
  char **dest_ptr,
  rtems_media_worker worker,
  void *worker_arg
)
{
  rtems_status_code sc = RTEMS_SUCCESSFUL;

  lock();

  switch (event) {
    case RTEMS_MEDIA_EVENT_DISK_ATTACH:
      sc = do_disk_attach(src, dest_ptr, worker, worker_arg);
      break;
    case RTEMS_MEDIA_EVENT_DISK_DETACH:
      sc = do_disk_detach(src, dest_ptr, worker, worker_arg);
      break;
    case RTEMS_MEDIA_EVENT_MOUNT:
      sc = do_mount(src, dest_ptr, worker, worker_arg);
      break;
    case RTEMS_MEDIA_EVENT_UNMOUNT:
      sc = do_unmount(src, dest_ptr, worker, worker_arg);
      break;
    case RTEMS_MEDIA_EVENT_PARTITION_INQUIRY:
      sc = do_partition_inquiry(src, dest_ptr, worker, worker_arg);
      break;
    case RTEMS_MEDIA_EVENT_PARTITION_ATTACH:
      sc = do_partition_attach(src, dest_ptr, worker, worker_arg);
      break;
    case RTEMS_MEDIA_EVENT_PARTITION_DETACH:
      sc = do_partition_detach(src, dest_ptr, worker, worker_arg);
      break;
    default:
      sc = RTEMS_INVALID_ID;
      break;
  }

  unlock();

  return sc;
}