BE ENGINEERING INSIGHTS: The Configuration Manager, Part II (Back into the fold)
By Victor Tsou

Last time I described how to access the configuration manager from the comfort of kernel space. Today I'll venture out into the uncharted regions of user space and show you how your applications can access this same information. Take my hand and follow my lead.

There's sample code to study; you can find it at <ftp://ftp.be.com/pub/samples/device_kit/listdev.zip>. As with last time, the relevant header file is <driver/config_manager.h>.

The /dev/misc/config device acts as the middleman between the configuration manager and user code. We've put together interface code that handles all the messiness for you. Rather than commit any energy to learning a one-shot interface, have faith and place your trust in these routines. Everything you need to know about this glue code can be divined from <cm_wrapper.h>.

The bulk of the first article concerned the mechanics of fetching information from the configuration manager. Rather than repeat myself, I'll spend time instead telling you how to make sense of this information.

The resource_descriptor is the basic unit of configuration information, describing an IRQ, DMA, I/O port, or memory used by a device. IRQs and DMAs are described by bitmasks, while I/O ports and memory are described by ranges. A line of source is worth a thousand words:

void print_mask(const char *name, resource_descriptor r)
{
  int i;
  for (i=0;i<32;i++)
    if (r.d.m.mask == (1 << i))
      break;
  if (i == 32) i = -1;

  printf("%s: %d\n", name, i);
}

void print_range(const char *name, resource_descriptor r)
{
  printf("%s: 0x%x - 0x%x\n", name, r.d.r.minbase,
    r.d.r.minbase + r.d.r.len - 1);
}

void print_resource_descriptor(resource_descriptor r)
{
  switch (r.type) {
    case B_IRQ_RESOURCE:
      print_mask("irq", r);
      break;
    case B_DMA_RESOURCE:
      print_mask("dma", r);
      break;
    case B_IO_PORT_RESOURCE:
      print_range("i/o ports", r);
      break;
    case B_MEMORY_RESOURCE:
      print_range("memory", r);
      break;
    default:
      printf("Unknown resource type (%d)\n", r.type);
      break;
  }
}

A device_configuration is an array of resource descriptors representing the resources assigned to the device. Behold:

void print_device_configuration(struct
  device_configuration *config)
{
  int i;
  for (i=0;inum_resources;i++)
    print_resource_descriptor(config->resources[i]);
}

The final structure of interest is possible_device_configurations, representing the space of configurations a device can take. It is an array of device_configurations, with each element representing a set of states the device can assume. Each resource_descriptor in a possible_device_configuration represents a set of possible values for a resource, rather than a single value, allowing for a compact description of possible resource configurations for a device.

Since a device_configuration is a variable-sized structure, you can't directly index the possible_device_configurations to obtain a given device_configuration. You have to be more clever, but only just. As you might expect:

void print_possible_device_configurations(struct
  possible_device_configurations *possible)
{
  #define NEXT_POSSIBLE(c) \
    (c) = (struct device_configuration *) \
    ((uchar *)(c) + \
    sizeof(struct device_configuration) + \
    (c)->num_resources * \
    sizeof(resource_descriptor))

  struct device configuration *config =
    possible->possible + 0;
  int i;
  for (i=0;i<possible->num_possible;i++) {
    print_device_configuration(config);
    NEXT_POSSIBLE(config);
  }
}

Each resource_descriptor in a possible_device_configurations may represent a set of possible resources, so the lower level functions will, sadly, need to be changed, leaving us with only the greasy middlemen, print_device_configuration and print_resource_descriptor, unchanged. Some parting words of advice:

void print_mask(const char *name, resource_descriptor r)
{
  bool first = true;
  int i;
  printf("%s: [", name);
  if (!r.d.m.mask)
    printf("none");
  for (i=0;i<32;i++)
    if (r.d.m.mask & (1 << i)) {
      printf("%s%d", first ? "" : ",", i);
      first = false;
    }
  printf("]\n");
}

void print_range(const char *name, resource_descriptor r)
{
  printf("%s: min %x max %x step %x length %x\n",
    name,
    r.d.r.minbase, r.d.r.maxbase,
    r.d.r.basealign, r.d.r.len);
}

Copyright ©1999 Be, Inc. Be is a registered trademark, and BeOS, BeBox, BeWare, GeekPort, the Be logo and the BeOS logo are trademarks of Be, Inc. All other trademarks mentioned are the property of their respective owners.