/* Enter a new state and submit the corresponding request to the device. */ static int submit_request(const struct sr_dev_inst *sdi, enum protocol_state state) { struct dev_context *devc; struct acquisition_state *acq; int ret; devc = sdi->priv; acq = devc->acquisition; devc->state = state; acq->xfer_out->length = 0; acq->reg_seq_pos = 0; acq->reg_seq_len = 0; /* Perform the model-specific action for the new state. */ ret = (*devc->model->prepare_request)(sdi); if (ret != SR_OK) { devc->transfer_error = TRUE; return ret; } if (acq->reg_seq_pos < acq->reg_seq_len) { if ((state & STATE_EXPECT_RESPONSE) != 0) next_reg_read(acq); else next_reg_write(acq); } return submit_transfer(devc, acq->xfer_out); }
int usb_send_interrupt_out(int usb_number, unsigned char* buffer, unsigned char length) { struct usb_state* state = usb_states+usb_number; if(!state->devh) { fprintf(stderr, "no usb device opened for index %d\n", usb_number); return -1; } unsigned char* buf = calloc(length, sizeof(unsigned char)); if(!buf) { fprintf(stderr, "calloc failed\n"); return -1; } memcpy(buf, buffer, length); if(state->type == C_TYPE_XONE_PAD && length > 2) { buf[2] = state->counter++; } struct libusb_transfer* transfer = libusb_alloc_transfer(0); transfer->flags = LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER; libusb_fill_interrupt_transfer(transfer, state->devh, controller[state->type].endpoints.out.address, buf, length, (libusb_transfer_cb_fn)usb_callback, usb_state_indexes+usb_number, 1000); return submit_transfer(transfer); }
/* USB input transfer completion callback. */ static void LIBUSB_CALL transfer_in_completed(struct libusb_transfer *transfer) { const struct sr_dev_inst *sdi; struct dev_context *devc; struct acquisition_state *acq; sdi = transfer->user_data; devc = sdi->priv; acq = devc->acquisition; if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { sr_err("Transfer from device failed (state %d): %s.", devc->state, libusb_error_name(transfer->status)); devc->transfer_error = TRUE; return; } if ((devc->state & STATE_EXPECT_RESPONSE) == 0) { sr_err("Unexpected completion of input transfer (state %d).", devc->state); devc->transfer_error = TRUE; return; } if (acq->reg_seq_pos < acq->reg_seq_len && !devc->cancel_requested) { /* Complete register read sequence. */ if (read_reg_response(acq) != SR_OK) { devc->transfer_error = TRUE; return; } /* Repeat until all queued registers have been read. */ if (++acq->reg_seq_pos < acq->reg_seq_len) { next_reg_read(acq); submit_transfer(devc, acq->xfer_out); return; } } switch (devc->state) { case STATE_STATUS_REQUEST: if (devc->cancel_requested) submit_request(sdi, STATE_STOP_CAPTURE); else handle_status_response(sdi); break; case STATE_LENGTH_REQUEST: if (devc->cancel_requested) submit_request(sdi, STATE_READ_FINISH); else handle_length_response(sdi); break; case STATE_READ_REQUEST: handle_read_response(sdi); break; default: sr_err("Unexpected device state %d.", devc->state); devc->transfer_error = TRUE; break; } }
/* The top-level code will have aquired the stream->lock for us */ int lusb_submit_stream_buffer(void *driver, struct bladerf_stream *stream, void *buffer, unsigned int timeout_ms, bool nonblock) { int status = 0; struct lusb_stream_data *stream_data = stream->backend_data; struct timespec timeout_abs; if (buffer == BLADERF_STREAM_SHUTDOWN) { if (stream_data->num_avail == stream_data->num_transfers) { stream->state = STREAM_DONE; } else { stream->state = STREAM_SHUTTING_DOWN; } return 0; } if (stream_data->num_avail == 0) { if (nonblock) { log_debug("Non-blocking buffer submission requested, but no " "transfers are currently available."); return BLADERF_ERR_WOULD_BLOCK; } if (timeout_ms != 0) { status = populate_abs_timeout(&timeout_abs, timeout_ms); if (status != 0) { return BLADERF_ERR_UNEXPECTED; } while (stream_data->num_avail == 0 && status == 0) { status = pthread_cond_timedwait(&stream->can_submit_buffer, &stream->lock, &timeout_abs); } } else { while (stream_data->num_avail == 0 && status == 0) { status = pthread_cond_wait(&stream->can_submit_buffer, &stream->lock); } } } if (status == ETIMEDOUT) { log_debug("%s: Timed out waiting for a transfer to become available.\n", __FUNCTION__); return BLADERF_ERR_TIMEOUT; } else if (status != 0) { return BLADERF_ERR_UNEXPECTED; } else { return submit_transfer(stream, buffer); } }
static int usb_poll_interrupt(int usb_number) { struct usb_state* state = usb_states+usb_number; struct libusb_transfer* transfer = libusb_alloc_transfer(0); transfer->flags = LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER ; unsigned int size = controller[state->type].endpoints.in.size; unsigned char* buf = calloc(size, sizeof(char)); libusb_fill_interrupt_transfer(transfer, state->devh, controller[state->type].endpoints.in.address, buf, size, (libusb_transfer_cb_fn)usb_callback, usb_state_indexes+usb_number, 1000); int ret = submit_transfer(transfer); if(ret != -1) { state->ack = 0; } return ret; }
int usb_send_control(int usb_number, unsigned char* buffer, unsigned char length) { struct usb_state* state = usb_states+usb_number; if(!state->devh) { fprintf(stderr, "no usb device opened for index %d\n", usb_number); return -1; } struct libusb_control_setup* control_setup = (struct libusb_control_setup*)buffer; if(control_setup->wLength > BUFFER_SIZE-LIBUSB_CONTROL_SETUP_SIZE) { fprintf(stderr, "wLength (%hu) is higher than %hu\n", control_setup->wLength, BUFFER_SIZE-LIBUSB_CONTROL_SETUP_SIZE); return -1; } unsigned int size = length; if(control_setup->bmRequestType & LIBUSB_ENDPOINT_IN) { size += control_setup->wLength; } unsigned char* buf = calloc(size, sizeof(char)); if(!buf) { fprintf(stderr, "calloc failed\n"); return -1; } memcpy(buf, buffer, length); struct libusb_transfer* transfer = libusb_alloc_transfer(0); transfer->flags = LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER; libusb_fill_control_transfer(transfer, state->devh, buf, (libusb_transfer_cb_fn)usb_callback, usb_state_indexes+usb_number, 1000); return submit_transfer(transfer); }
/* The top-level code will have aquired the stream->lock for us */ int lusb_submit_stream_buffer(void *driver, struct bladerf_stream *stream, void *buffer, unsigned int timeout_ms) { int status; struct lusb_stream_data *stream_data = stream->backend_data; struct timespec timeout_abs; if (buffer == BLADERF_STREAM_SHUTDOWN) { if (stream_data->num_avail_transfers == stream_data->num_transfers) { stream->state = STREAM_DONE; } else { stream->state = STREAM_SHUTTING_DOWN; } return 0; } status = populate_abs_timeout(&timeout_abs, timeout_ms); if (status != 0) { return BLADERF_ERR_UNEXPECTED; } while (stream_data->num_avail_transfers == 0 && status == 0) { status = pthread_cond_timedwait(&stream->can_submit_buffer, &stream->lock, &timeout_abs); } if (status == ETIMEDOUT) { return BLADERF_ERR_TIMEOUT; } else if (status != 0) { return BLADERF_ERR_UNEXPECTED; } else { return submit_transfer(stream, buffer); } }
static void LIBUSB_CALL lusb_stream_cb(struct libusb_transfer *transfer) { struct bladerf_stream *stream = transfer->user_data; void *next_buffer = NULL; struct bladerf_metadata metadata; struct lusb_stream_data *stream_data = stream->backend_data; size_t transfer_i; /* Currently unused - zero out for out own debugging sanity... */ memset(&metadata, 0, sizeof(metadata)); MUTEX_LOCK(&stream->lock); transfer_i = transfer_idx(stream_data, transfer); assert(stream_data->transfer_status[transfer_i] == TRANSFER_IN_FLIGHT || stream_data->transfer_status[transfer_i] == TRANSFER_CANCEL_PENDING); if (transfer_i >= stream_data->num_transfers) { log_error("Unable to find transfer"); stream->state = STREAM_SHUTTING_DOWN; } else { stream_data->transfer_status[transfer_i] = TRANSFER_AVAIL; stream_data->num_avail++; pthread_cond_signal(&stream->can_submit_buffer); } /* Check to see if the transfer has been cancelled or errored */ if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { /* Errored out for some reason .. */ stream->state = STREAM_SHUTTING_DOWN; switch(transfer->status) { case LIBUSB_TRANSFER_CANCELLED: /* We expect this case when we begin tearing down the stream */ break; case LIBUSB_TRANSFER_STALL: log_error("Hit stall for buffer %p\n", transfer->buffer); stream->error_code = BLADERF_ERR_IO; break; case LIBUSB_TRANSFER_ERROR: log_error("Got transfer error for buffer %p\n", transfer->buffer); stream->error_code = BLADERF_ERR_IO; break; case LIBUSB_TRANSFER_OVERFLOW : log_error("Got transfer over for buffer %p, " "transfer \"actual_length\" = %d\n", transfer->buffer, transfer->actual_length); stream->error_code = BLADERF_ERR_IO; break; case LIBUSB_TRANSFER_TIMED_OUT: stream->error_code = BLADERF_ERR_TIMEOUT; break; case LIBUSB_TRANSFER_NO_DEVICE: stream->error_code = BLADERF_ERR_NODEV; break; default: log_error( "Unexpected transfer status: %d\n", transfer->status ); break; } } if (stream->state == STREAM_RUNNING) { /* Sanity check for debugging purposes */ if (transfer->length != transfer->actual_length) { log_warning( "Received short transfer\n" ); } /* Call user callback requesting more data to transmit */ next_buffer = stream->cb( stream->dev, stream, &metadata, transfer->buffer, bytes_to_sc16q11(transfer->actual_length), stream->user_data); if (next_buffer == BLADERF_STREAM_SHUTDOWN) { stream->state = STREAM_SHUTTING_DOWN; } else if (next_buffer != BLADERF_STREAM_NO_DATA) { int status = submit_transfer(stream, next_buffer); if (status != 0) { /* If this fails, we probably have a serious problem...so just * shut it down. */ stream->state = STREAM_SHUTTING_DOWN; } } } /* Check to see if all the transfers have been cancelled, * and if so, clean up the stream */ if (stream->state == STREAM_SHUTTING_DOWN) { /* We know we're done when all of our transfers have returned to their * "available" states */ if (stream_data->num_avail == stream_data->num_transfers) { stream->state = STREAM_DONE; } else { cancel_all_transfers(stream); } } MUTEX_UNLOCK(&stream->lock); }
static int lusb_stream(void *driver, struct bladerf_stream *stream, bladerf_module module) { size_t i; int status = 0; void *buffer; struct bladerf_metadata metadata; struct bladerf *dev = stream->dev; struct bladerf_lusb *lusb = (struct bladerf_lusb *) driver; struct lusb_stream_data *stream_data = stream->backend_data; struct timeval tv = { 0, LIBUSB_HANDLE_EVENTS_TIMEOUT_NSEC }; /* Currently unused, so zero it out for a sanity check when debugging */ memset(&metadata, 0, sizeof(metadata)); MUTEX_LOCK(&stream->lock); /* Set up initial set of buffers */ for (i = 0; i < stream_data->num_transfers; i++) { if (module == BLADERF_MODULE_TX) { buffer = stream->cb(dev, stream, &metadata, NULL, stream->samples_per_buffer, stream->user_data); if (buffer == BLADERF_STREAM_SHUTDOWN) { /* If we have transfers in flight and the user prematurely * cancels the stream, we'll start shutting down */ if (stream_data->num_avail != stream_data->num_transfers) { stream->state = STREAM_SHUTTING_DOWN; } else { /* No transfers have been shipped out yet so we can * simply enter our "done" state */ stream->state = STREAM_DONE; } /* In either of the above we don't want to attempt to * get any more buffers from the user */ break; } } else { buffer = stream->buffers[i]; } if (buffer != BLADERF_STREAM_NO_DATA) { status = submit_transfer(stream, buffer); /* If we failed to submit any transfers, cancel everything in * flight. We'll leave the stream in the running state so we can * have libusb fire off callbacks with the cancelled status*/ if (status < 0) { stream->error_code = status; cancel_all_transfers(stream); } } } MUTEX_UNLOCK(&stream->lock); /* This loop is required so libusb can do callbacks and whatnot */ while (stream->state != STREAM_DONE) { status = libusb_handle_events_timeout(lusb->context, &tv); if (status < 0 && status != LIBUSB_ERROR_INTERRUPTED) { log_warning("unexpected value from events processing: " "%d: %s\n", status, libusb_error_name(status)); status = error_conv(status); } } return status; }
static int cyapi_stream(void *driver, struct bladerf_stream *stream, bladerf_module module) { int status; int idx = 0; long len; void *next_buffer; ULONG timeout_ms; bool success, done; struct stream_data *data = get_stream_data(stream); struct bladerf_cyapi *cyapi = get_backend_data(driver); struct bladerf_metadata meta; assert(stream->dev->transfer_timeout[stream->module] <= ULONG_MAX); if (stream->dev->transfer_timeout[stream->module] == 0) { timeout_ms = INFINITE; } else { timeout_ms = stream->dev->transfer_timeout[stream->module]; } switch (module) { case BLADERF_MODULE_RX: data->ep = get_ep(cyapi->dev, SAMPLE_EP_IN); break; case BLADERF_MODULE_TX: data->ep = get_ep(cyapi->dev, SAMPLE_EP_OUT); break; default: assert(!"Invalid module"); return BLADERF_ERR_UNEXPECTED; } if (data->ep == NULL) { log_debug("Failed to get EP handle.\n"); return BLADERF_ERR_UNEXPECTED; } data->ep->XferMode = XMODE_DIRECT; data->ep->Abort(); data->ep->Reset(); log_verbose("Starting stream...\n"); status = 0; done = false; memset(&meta, 0, sizeof(meta)); MUTEX_LOCK(&stream->lock); for (unsigned int i = 0; i < data->num_transfers && status == 0; i++) { if (module == BLADERF_MODULE_TX) { next_buffer = stream->cb(stream->dev, stream, &meta, NULL, stream->samples_per_buffer, stream->user_data); if (next_buffer == BLADERF_STREAM_SHUTDOWN) { done = true; break; } else if (next_buffer == BLADERF_STREAM_NO_DATA) { continue; } } else { next_buffer = stream->buffers[i]; } status = submit_transfer(stream, next_buffer); } MUTEX_UNLOCK(&stream->lock); if (status != 0) { goto out; } while (!done) { struct transfer *xfer; size_t i; i = data->inflight_i; xfer = &data->transfers[i]; success = data->ep->WaitForXfer(&xfer->event, timeout_ms); if (!success) { status = BLADERF_ERR_TIMEOUT; log_debug("Steam timed out.\n"); break; } len = 0; next_buffer = NULL; log_verbose("Got transfer complete in slot %u (buffer %p)\n", i, data->transfers[i].buffer); MUTEX_LOCK(&stream->lock); success = data->ep->FinishDataXfer(data->transfers[i].buffer, len, &data->transfers[i].event, xfer->handle); if (success) { next_buffer = stream->cb(stream->dev, stream, &meta, data->transfers[i].buffer, bytes_to_samples(stream->format, len), stream->user_data); } else { done = true; status = BLADERF_ERR_IO; log_debug("Failed to finish transfer %u, buf=%p.\n", (unsigned int)i, &data->transfers[i].buffer); } data->transfers[i].buffer = NULL; data->transfers[i].handle = NULL; data->num_avail++; pthread_cond_signal(&stream->can_submit_buffer); if (next_buffer == BLADERF_STREAM_SHUTDOWN) { done = true; } else if (next_buffer != BLADERF_STREAM_NO_DATA) { status = submit_transfer(stream, next_buffer); done = (status != 0); } data->inflight_i = next_idx(data, data->inflight_i); MUTEX_UNLOCK(&stream->lock); } out: MUTEX_LOCK(&stream->lock); stream->error_code = status; stream->state = STREAM_SHUTTING_DOWN; data->ep->Abort(); data->ep->Reset(); for (unsigned int i = 0; i < data->num_transfers; i++) { LONG len = 0; if (data->transfers[i].handle != NULL) { data->ep->FinishDataXfer(data->transfers[i].buffer, len, &data->transfers[i].event, data->transfers[i].handle); data->transfers[i].buffer = NULL; data->transfers[i].handle = NULL; data->num_avail++; } } assert(data->num_avail == data->num_transfers); stream->state = STREAM_DONE; log_verbose("Stream done (error_code = %d)\n", stream->error_code); MUTEX_UNLOCK(&stream->lock); return 0; }
/* USB output transfer completion callback. */ static void LIBUSB_CALL transfer_out_completed(struct libusb_transfer *transfer) { const struct sr_dev_inst *sdi; struct dev_context *devc; struct acquisition_state *acq; sdi = transfer->user_data; devc = sdi->priv; acq = devc->acquisition; if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { sr_err("Transfer to device failed (state %d): %s.", devc->state, libusb_error_name(transfer->status)); devc->transfer_error = TRUE; return; } /* If this was a read request, wait for the response. */ if ((devc->state & STATE_EXPECT_RESPONSE) != 0) { submit_transfer(devc, acq->xfer_in); return; } if (acq->reg_seq_pos < acq->reg_seq_len) acq->reg_seq_pos++; /* register write completed */ /* Repeat until all queued registers have been written. */ if (acq->reg_seq_pos < acq->reg_seq_len && !devc->cancel_requested) { next_reg_write(acq); submit_transfer(devc, acq->xfer_out); return; } switch (devc->state) { case STATE_START_CAPTURE: sr_info("Acquisition started."); if (!devc->cancel_requested) devc->state = STATE_STATUS_WAIT; else submit_request(sdi, STATE_STOP_CAPTURE); break; case STATE_STOP_CAPTURE: if (!devc->cancel_requested) submit_request(sdi, STATE_LENGTH_REQUEST); else devc->state = STATE_IDLE; break; case STATE_READ_PREPARE: if (acq->mem_addr_next < acq->mem_addr_stop && !devc->cancel_requested) submit_request(sdi, STATE_READ_REQUEST); else submit_request(sdi, STATE_READ_FINISH); break; case STATE_READ_FINISH: devc->state = STATE_IDLE; break; default: sr_err("Unexpected device state %d.", devc->state); devc->transfer_error = TRUE; break; } }