/** * 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; }
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); }
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); } }
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; } }
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; }
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"); } }
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(¤t->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(¤t->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; }
/** * 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, ®size) != 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; } }
/** * Returns information about the loadable module by calling `mod_info'. */ int _info(struct modinfo *modinfop) { LOG_DEBUG0("_info\n"); return mod_info(&modlinkage, modinfop); }