Пример #1
0
/**
 * Initializes a loadable module. It calls `mod_install' to install the
 * `modlinkage' and `modldrv' structures.
 */
int _init(void)
{
  int error;
  error = ddi_soft_state_init(&quantis_soft_state_p,
                              sizeof(quantis_soft_state_t),
                              0);
  if (error != 0)
  {
    QUANTIS_ERROR("Could not initialize the soft state tree.\n");
    return error;
  }

  error = mod_install(&modlinkage);
  if (error != 0)
  {
    QUANTIS_ERROR("Could not install the modlinkage structure.\n");
    ddi_soft_state_fini(&quantis_soft_state_p);
    return error;
  }

  mutex_init(&quantis_mutex, NULL, MUTEX_DRIVER, NULL);
  card_count = 0;

  LOG_DEBUG0("Initialized the quantis driver\n");

  return error;
}
Пример #2
0
void input_flush_queue(buffer_queue *queue, int keep_critical)
{
    queue_item *item, *next, *prev=NULL;

    LOG_DEBUG0("Input queue flush requested");

    thread_mutex_lock(&queue->lock);
    if(!queue->head)
    {
        thread_mutex_unlock(&queue->lock);
        return;
    }

    item = queue->head;
    while(item)
    {
        next = item->next;

        if(!(keep_critical && item->buf->critical))
        {
            thread_mutex_lock(&ices_config->refcount_lock);
            item->buf->count--;
            if(!item->buf->count)
            {
                free(item->buf->buf);
                free(item->buf);
            }
            thread_mutex_unlock(&ices_config->refcount_lock);

            if(prev)
                prev->next = next;
            else
                queue->head = next;

            free(item);
            item = next;

            queue->length--;
        }
        else
        {
            prev = item;
            item = next;
        }
    }

    /* Now, fix up the tail pointer */
    queue->tail = NULL;
    item = queue->head;

    while(item)
    {
        queue->tail = item;
        item = item->next;
    }

    thread_mutex_unlock(&queue->lock);
}
Пример #3
0
void encode_clear(encoder_state *s)
{
    if(s)
    {
        LOG_DEBUG0("Clearing encoder engine");
        ogg_stream_clear(&s->os);
        vorbis_block_clear(&s->vb);
        vorbis_dsp_clear(&s->vd);
        vorbis_info_clear(&s->vi);
        free(s);
    }
}
Пример #4
0
void start_runners()
{
    struct runner **runnerptr = &ices_config->runners;
    struct runner *run;

    while (*runnerptr != NULL)
    {
        run = *runnerptr;

        if (run->not_running && !ices_config->shutdown)
        {
            LOG_DEBUG0("starting runner");
            create_runner_thread (run);
        }

        runnerptr = &run->next;
    }
}
Пример #5
0
ref_buffer *stream_wait_for_data(instance_t *stream)
{
    ref_buffer *buffer;
    queue_item *old;

    thread_mutex_lock(&stream->queue->lock);
    while(!stream->queue->head && !ices_config->shutdown && !stream->kill)
    {
        thread_mutex_unlock(&stream->queue->lock);
        thread_cond_wait(&ices_config->queue_cond);
        thread_mutex_lock(&stream->queue->lock);
    }

    if(ices_config->shutdown || stream->kill)
    {
        LOG_DEBUG0("Shutdown signalled: thread shutting down");
        thread_mutex_unlock(&stream->queue->lock);
        return NULL;
    }

    buffer = stream->queue->head->buf;
    old = stream->queue->head;

    stream->queue->head = stream->queue->head->next;
    if(!stream->queue->head)
        stream->queue->tail = NULL;

    free(old);
    stream->queue->length--;
    thread_mutex_unlock(&stream->queue->lock);

    /* ok, we pulled something off the queue and the queue is
     * now empty - this means we're probably keeping up, so
     * clear one of the errors. This way, very occasional errors
     * don't cause eventual shutdown
     */
    if(!stream->queue->head && stream->buffer_failures>0)
        stream->buffer_failures--;

    return buffer;
}
Пример #6
0
void *metadata_thread_signal(void *arg)
{
    char buf[1024];
    input_module_t *mod = arg;

    while(1)
    {
        char **md = NULL;
        int comments = 0;
        FILE *file;

        while(metadata_update_signalled == 0)
        {
            thread_cond_wait(&ices_config->event_pending_cond);
            if (ices_config->shutdown)
            {
                LOG_INFO0 ("metadata thread shutting down");
                return NULL;
            }
            LOG_DEBUG0("meta thread wakeup");
        }

        metadata_update_signalled = 0;

        file = fopen(ices_config->metadata_filename, "r");
        if(!file) {
            LOG_WARN2("Failed to open file \"%s\" for metadata update: %s", 
                    ices_config->metadata_filename, strerror(errno));
            continue;
        }

        LOG_DEBUG1("reading metadata from \"%s\"", ices_config->metadata_filename);
        while(fgets(buf, 1024, file))
        {
            if(buf[0] == '\n')
                break;
            else
            {
                if(buf[strlen(buf)-1] == '\n')
                    buf[strlen(buf)-1] = 0;
                md = realloc(md, (comments+2)*sizeof(char *));
                md[comments] = malloc(strlen(buf)+1);

                memcpy(md[comments], buf, strlen(buf)+1);
                comments++;
                LOG_INFO2 ("tag %d is %s", comments, buf);
            }
        }

        fclose(file);

        if(md) /* Don't update if there's nothing there */
        {
            md[comments]=0;

            /* Now, let's actually use the new data */
            LOG_INFO0("Updating metadata");
            mod->handle_event(mod,EVENT_METADATAUPDATE,md);
        }
        else
            LOG_INFO0("No metadata has been read");

    }
}
Пример #7
0
void input_loop(void)
{
    input_module_t *inmod=NULL;
    instance_t *instance, *prev, *next;
    queue_item *queued;
    int shutdown = 0;
    int current_module = 0;
    int valid_stream = 1;
    int inc_count;
    int not_waiting_for_critical;
    int foundmodule = 0;

    thread_cond_create(&ices_config->queue_cond);
    thread_cond_create(&ices_config->event_pending_cond);
    thread_mutex_create(&ices_config->refcount_lock);
    thread_mutex_create(&ices_config->flush_lock);

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

    while(ices_config->playlist_module && modules[current_module].open)
    {
        if(!strcmp(ices_config->playlist_module, modules[current_module].name))
        {
            foundmodule = 1;
            inmod = modules[current_module].open(ices_config->module_params);
            break;
        }
        current_module++;
    }

    if(!inmod)
    {
        if(foundmodule)
            LOG_ERROR1("Couldn't initialise input module \"%s\"", 
                    ices_config->playlist_module);
        else
            LOG_ERROR1("No input module named \"%s\" could be found", 
                    ices_config->playlist_module);
        return;
    }

    ices_config->inmod = inmod;


    /* ok, basic config stuff done. Now, we want to start all our listening
     * threads.
     */

    instance = ices_config->instances;

    while(instance) 
    {
        stream_description *arg = calloc(1, sizeof(stream_description));
        arg->stream = instance;
        arg->input = inmod;
        /*
        if(instance->savefilename != NULL)
            thread_create("savefile", savefile_stream, arg, 1);
         */
        thread_create("stream", ices_instance_stream, arg, 1);

        instance = instance->next;
    }
    /* treat as if a signal has arrived straight away */
    signal_usr1_handler (0);

    /* now we go into the main loop
     * We shut down the main thread ONLY once all the instances
     * have killed themselves.
     */
    while(!shutdown) 
    {
        ref_buffer *chunk = calloc(1, sizeof(ref_buffer));
        buffer_queue *current;
        int ret;

        instance = ices_config->instances;
        prev = NULL;

        while(instance)
        {
            /* if an instance has died, get rid of it
            ** this should be replaced with something that tries to 
            ** restart the instance, probably.
            */
            if (instance->died) 
            {
                LOG_DEBUG0("An instance died, removing it");
                next = instance->next;

                if (prev)
                    prev->next = next;
                else
                    ices_config->instances = next;

                /* Just in case, flush any existing buffers
                 * Locks shouldn't be needed, but lets be SURE */
                thread_mutex_lock(&ices_config->flush_lock);
                input_flush_queue(instance->queue, 0);
                thread_mutex_unlock(&ices_config->flush_lock);

                config_free_instance(instance);
                free(instance);

                instance = next;
                continue;
            }

            prev = instance;
            instance = instance->next;
        }

        instance = ices_config->instances;

        if(!instance)
        {
            shutdown = 1;
            free(chunk);
            continue;
        }

        if(ices_config->shutdown) /* We've been signalled to shut down, but */
        {                          /* the instances haven't done so yet... */
            timing_sleep(250); /* sleep for quarter of a second */
            free(chunk);
            continue;
        }

        /* If this is the first time through, set initial time. This should
         * be done before the call to inmod->getdata() below, in order to
         * properly keep time if this input module blocks.
         */
        if (control.starttime == 0)
            control.starttime = timing_get_time();

        /* get a chunk of data from the input module */
        ret = inmod->getdata(inmod->internal, chunk);

        /* input module signalled non-fatal error. Skip this chunk */
        if(ret==0)
        {
            free(chunk);
            continue;
        }

        /* Input module signalled fatal error, shut down - nothing we can do
         * from here */
        if(ret < 0)
        {
            ices_config->shutdown = 1;
            thread_cond_broadcast(&ices_config->queue_cond);
            free(chunk);
            continue;
        }

        if(chunk->critical)
            valid_stream = 1;

        if(ret < 0) {
            /* Tell the input module to go to the next track, hopefully allowing
             * resync. */
            ices_config->inmod->handle_event(ices_config->inmod,
                    EVENT_NEXTTRACK,NULL);
            valid_stream = 0;
        }

        inc_count = 0;
        not_waiting_for_critical = 0;

        if(valid_stream) 
        {
            while(instance)
            {
                if(instance->wait_for_critical && !chunk->critical)
                {
                    instance = instance->next;
                    continue;

                }

                not_waiting_for_critical = 1;

                if(instance->skip)
                {
                    instance = instance->next;
                    continue;
                }

                queued = malloc(sizeof(queue_item));

                queued->buf = chunk;
                current = instance->queue;

                inc_count++;

                thread_mutex_lock(&current->lock);

                if(current->head == NULL)
                {
                    current->head = current->tail = queued;
                    current->head->next = current->tail->next = NULL;
                }
                else
                {
                    current->tail->next = queued;
                    queued->next = NULL;
                    current->tail = queued;
                }

                current->length++;
                thread_mutex_unlock(&current->lock);

                instance = instance->next;
            }
        }

        /* If everything is waiting for a critical buffer, force one
         * early. (This will take effect on the next pass through)
         */
        if(valid_stream && !not_waiting_for_critical) {
            ices_config->inmod->handle_event(ices_config->inmod,
                    EVENT_NEXTTRACK,NULL);
            instance = ices_config->instances;
            while(instance) {
                thread_mutex_lock(&ices_config->flush_lock);
                input_flush_queue(instance->queue, 0);
                instance->wait_for_critical = 0;
                thread_mutex_unlock(&ices_config->flush_lock);
                instance = instance->next;
            }
        }

        /* Make sure we don't end up with a 0-refcount buffer that 
         * will never hit any of the free points. (this happens
         * if all threads are set to skip, for example).
         */
        thread_mutex_lock(&ices_config->refcount_lock);
        chunk->count += inc_count;
        if(!chunk->count)
        {
            free(chunk->buf);
            free(chunk);
        }
        thread_mutex_unlock(&ices_config->refcount_lock);

        if(valid_stream) {
            /* wake up the instances */
            thread_cond_broadcast(&ices_config->queue_cond);

        }
    }

    LOG_INFO0 ("All instances removed, shutting down...");

    ices_config->shutdown = 1;
    thread_cond_broadcast(&ices_config->event_pending_cond);
    timing_sleep(250); /* sleep for quarter of a second */

    thread_cond_destroy(&ices_config->queue_cond);
    thread_cond_destroy(&ices_config->event_pending_cond);
    thread_mutex_destroy(&ices_config->flush_lock);
    thread_mutex_destroy(&ices_config->refcount_lock);

    inmod->handle_event(inmod, EVENT_SHUTDOWN, NULL);

    return;
}
Пример #8
0
/**
 * At attach time, we allocate the soft state structure for the current
 * instance of the device.
 */
static int quantis_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
{
  int instance;
  quantis_soft_state_t *soft_state;
  ddi_device_acc_attr_t dev_acc_attr; /* Hold the device access attributes. */
  int nregs;
  off_t regsize;
  char msg[MAX_MSG_LEN];

  LOG_DEBUG0("attach\n");

  switch (cmd)
  {
    case DDI_ATTACH:
      instance = ddi_get_instance(dip);
      snprintf(msg,
               MAX_MSG_LEN,
               "Attaching the Quantis device %d.\n",
               instance);
      LOG_DEBUG0(msg);

      /*
       * PCI devices are self-identifying devices, so we check that we
       * indeed have a Quantis QRNG card by checking that we have one
       * register page with the correct size.
       */
      if (ddi_dev_nregs(dip, &nregs) != DDI_SUCCESS)
      {
        snprintf(msg,
                 MAX_MSG_LEN,
                 "Could not get the number of register for the Quantis device %d.\n",
                 instance);
        QUANTIS_ERROR(msg);
        return DDI_FAILURE;
      }

      if (nregs < 4)
      {
        snprintf(msg,
                 MAX_MSG_LEN,
                 "The Quantis device %d has %d PCI base registers, but should have at least 4.\n",
                 instance,
                 nregs);
        QUANTIS_ERROR(msg);
        return DDI_FAILURE;
      }

      if (ddi_dev_regsize(dip, QUANTIS_REG_IDX, &regsize) != DDI_SUCCESS)
      {
        snprintf(msg,
                 MAX_MSG_LEN,
                 "Could not get the register size for the Quantis device %d.\n",
                 instance);
        QUANTIS_ERROR(msg);
        return DDI_FAILURE;
      }

      if (regsize < (int)QUANTIS_REG_LENGTH)
      {
        snprintf(msg,
                 MAX_MSG_LEN,
                 "The size of the Quantice device (%d) registers file is %d bytes long, "
                 "but should be at least %u bytes long.\n",
                 instance,
                 (int)regsize,
                 (unsigned int)QUANTIS_REG_LENGTH);
        QUANTIS_ERROR(msg);
        return DDI_FAILURE;
      }

      LOG_DEBUG0("After test of the validity of the card, before soft state alloc.\n");
      if (ddi_soft_state_zalloc(quantis_soft_state_p, instance) != DDI_SUCCESS)
      {
        snprintf(msg,
                 MAX_MSG_LEN,
                 "Could not allocate soft state structure for the Quantis device %d.\n",
                 instance);
        QUANTIS_ERROR(msg);
        return DDI_FAILURE;
      }

      soft_state = (quantis_soft_state_t *)ddi_get_soft_state(quantis_soft_state_p,
                                                              instance);
      soft_state->dip = dip;
      ddi_set_driver_private(dip, (caddr_t)soft_state);
      soft_state->cnt = 0;

      /*
       * Initialize the mutex in the soft state. We have no interrupt,
       * so we can set `arg' to `NULL'
       */
      mutex_init(&soft_state->mutex, NULL, MUTEX_DRIVER, NULL);

      if (ddi_create_minor_node(dip,
                                ddi_get_name(dip),
                                S_IFCHR,
                                instance,
                                DDI_PSEUDO,
                                0) == DDI_FAILURE)
      {
        snprintf(msg,
                 MAX_MSG_LEN,
                 "Could not create minor node for the Quantis device %d.\n",
                 instance);
        QUANTIS_ERROR(msg);
        mutex_destroy(&soft_state->mutex);
        ddi_soft_state_free(quantis_soft_state_p, instance);
        return DDI_FAILURE;
      }
      LOG_DEBUG1("ddi_get_name %s\n", ddi_get_name(dip));

      dev_acc_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
      dev_acc_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
      dev_acc_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;

      if (ddi_regs_map_setup(dip,
                             QUANTIS_REG_IDX,
                             (caddr_t *)&soft_state->regs,
                             0,
                             QUANTIS_REG_LENGTH,
                             &dev_acc_attr,
                             &soft_state->regs_handle) != DDI_SUCCESS)
      {
        snprintf(msg,
                 MAX_MSG_LEN,
                 "Could not map the registers space of the Quantis device %d.\n",
                 instance);
        QUANTIS_ERROR(msg);
        mutex_destroy(&soft_state->mutex);
        ddi_soft_state_free(quantis_soft_state_p, instance);
        return DDI_FAILURE;
      }

      mutex_enter(&quantis_mutex);
      card_count++;
      mutex_exit(&quantis_mutex);

      LOG_DEBUG0("Just before mutex\n");
      mutex_enter(&soft_state->mutex);
      LOG_DEBUG0("Just before rng_reset.\n");
      quantis_rng_reset(soft_state);
      LOG_DEBUG0("Just before enable_modules.\n");
      quantis_rng_enable_modules(soft_state, quantis_rng_modules_mask(soft_state));
      LOG_DEBUG0("Just before release mutex.\n");
      mutex_exit(&soft_state->mutex);

      snprintf(msg,
               MAX_MSG_LEN,
               "Successfully attached the Quantis device %d. Currently, %d Quantis cards are available.\n",
               instance,
               card_count);
      QUANTIS_INFO(msg);

#     ifdef DEBUG
        ddi_report_dev(dip);
#     endif

      return DDI_SUCCESS;

    case DDI_SUSPEND:
    case DDI_PM_SUSPEND:
      return DDI_SUCCESS;

    default:
      return DDI_FAILURE;
  }
}
Пример #9
0
/**
 * Returns information about the loadable module by calling `mod_info'.
 */
int _info(struct modinfo *modinfop)
{
  LOG_DEBUG0("_info\n");

  return mod_info(&modlinkage, modinfop);
}