static int tc_waitsample(FAR struct tc_dev_s *priv, FAR struct tc_sample_s *sample) { int ret; /* Pre-emption must be disabled when this is called to to prevent sampled * data from changing until it has been reported. */ sched_lock(); /* Now release the semaphore that manages mutually exclusive access to * the device structure. This may cause other tasks to become ready to * run, but they cannot run yet because pre-emption is disabled. */ nxsem_post(&priv->devsem); /* Try to get the a sample... if we cannot, then wait on the semaphore * that is posted when new sample data is availble. */ while (tc_sample(priv, sample) < 0) { /* Wait for a change in the touchscreen state */ priv->nwaiters++; ret = nxsem_wait(&priv->waitsem); priv->nwaiters--; if (ret < 0) { /* If we are awakened by a signal, then we need to return * the failure now. */ DEBUGASSERT(ret == -EINTR || ret == -ECANCELED); goto errout; } } /* Re-acquire the semaphore that manages mutually exclusive access to * the device structure. We may have to wait here. But we have our sample. * Interrupts and pre-emption will be re-enabled while we wait. */ ret = nxsem_wait(&priv->devsem); errout: /* Restore pre-emption. We might get suspended here but that is okay * because we already have our sample. Note: this means that if there * were two threads reading from the touchscreen for some reason, the data * might be read out of order. */ sched_unlock(); return ret; }
static int pwm_open(FAR struct file *filep) { FAR struct inode *inode = filep->f_inode; FAR struct pwm_upperhalf_s *upper = inode->i_private; uint8_t tmp; int ret; pwminfo("crefs: %d\n", upper->crefs); /* Get exclusive access to the device structures */ ret = nxsem_wait(&upper->exclsem); if (ret < 0) { goto errout; } /* Increment the count of references to the device. If this the first * time that the driver has been opened for this device, then initialize * the device. */ tmp = upper->crefs + 1; if (tmp == 0) { /* More than 255 opens; uint8_t overflows to zero */ ret = -EMFILE; goto errout_with_sem; } /* Check if this is the first time that the driver has been opened. */ if (tmp == 1) { FAR struct pwm_lowerhalf_s *lower = upper->dev; /* Yes.. perform one time hardware initialization. */ DEBUGASSERT(lower->ops->setup != NULL); pwminfo("calling setup\n"); ret = lower->ops->setup(lower); if (ret < 0) { goto errout_with_sem; } } /* Save the new open count on success */ upper->crefs = tmp; ret = OK; errout_with_sem: nxsem_post(&upper->exclsem); errout: return ret; }
void tiva_adc_lock(FAR struct tiva_adc_s *priv, int sse) { struct tiva_adc_sse_s *s = g_sses[SSE_IDX(priv->devno, sse)]; int ret; #ifdef CONFIG_DEBUG_ANALOG uint16_t loop_count = 0; #endif ainfo("Locking...\n"); do { ret = nxsem_wait(&s->exclsem); /* This should only fail if the wait was canceled by an signal (and the * worker thread will receive a lot of signals). */ DEBUGASSERT(ret == OK || ret == -EINTR); #ifdef CONFIG_DEBUG_ANALOG if (loop_count % 1000) { ainfo("loop=%d\n"); } ++loop_count; #endif } while (ret == -EINTR); }
static inline int syslog_dev_takesem(void) { pid_t me = getpid(); int ret; /* Does this thread already hold the semaphore? That could happen if * we were called recursively, i.e., if the logic kicked off by * file_write() where to generate more debug output. Return an * error in that case. */ if (g_syslog_dev.sl_holder == me) { /* Return an error (instead of deadlocking) */ return -EWOULDBLOCK; } /* Either the semaphore is available or is currently held by another * thread. Wait for it to become available. */ ret = nxsem_wait(&g_syslog_dev.sl_sem); if (ret < 0) { return ret; } /* We hold the semaphore. We can safely mark ourself as the holder * of the semaphore. */ g_syslog_dev.sl_holder = me; return OK; }
static int ads7843e_open(FAR struct file *filep) { #ifdef CONFIG_ADS7843E_REFCNT FAR struct inode *inode; FAR struct ads7843e_dev_s *priv; uint8_t tmp; int ret; iinfo("Opening\n"); DEBUGASSERT(filep); inode = filep->f_inode; DEBUGASSERT(inode && inode->i_private); priv = (FAR struct ads7843e_dev_s *)inode->i_private; /* Get exclusive access to the driver data structure */ ret = nxsem_wait(&priv->devsem); if (ret < 0) { /* This should only happen if the wait was cancelled by an signal */ DEBUGASSERT(ret == -EINTR || ret == -ECANCELED); return ret; } /* Increment the reference count */ tmp = priv->crefs + 1; if (tmp == 0) { /* More than 255 opens; uint8_t overflows to zero */ ret = -EMFILE; goto errout_with_sem; } /* When the reference increments to 1, this is the first open event * on the driver.. and an opportunity to do any one-time initialization. */ /* Save the new open count on success */ priv->crefs = tmp; errout_with_sem: nxsem_post(&priv->devsem); return ret; #else iinfo("Opening\n"); return OK; #endif }
int up_hrttimer_usleep(unsigned int usec) { struct hrt_s hrt; nxsem_init(&hrt.sem, 0, 0); hrt.usec = usec; hrt_usleep_add(&hrt); nxsem_wait(&hrt.sem); return 0; }
static int ft80x_close(FAR struct file *filep) { #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS FAR struct inode *inode; FAR struct ft80x_dev_s *priv; int ret; DEBUGASSERT(filep != NULL); inode = filep->f_inode; DEBUGASSERT(inode != NULL && inode->i_private != NULL); priv = inode->i_private; lcdinfo("crefs: %d\n", priv->crefs); /* Get exclusive access to the device structures */ ret = nxsem_wait(&priv->exclsem); if (ret < 0) { goto errout; } /* Will the count decrement to zero? */ if (priv->crefs <= 1) { /* Yes.. if the driver has been unlinked, then we need to destroy the * driver instance. */ priv->crefs = 0; if (priv->unlinked) { ft80x_destroy(priv); return OK; } } else { /* NO.. decrement the number of references to the driver. */ priv->crefs--; } ret = OK; nxsem_post(&priv->exclsem); errout: return ret; #else return OK; #endif }
static int ads7843e_ioctl(FAR struct file *filep, int cmd, unsigned long arg) { FAR struct inode *inode; FAR struct ads7843e_dev_s *priv; int ret; iinfo("cmd: %d arg: %ld\n", cmd, arg); DEBUGASSERT(filep); inode = filep->f_inode; DEBUGASSERT(inode && inode->i_private); priv = (FAR struct ads7843e_dev_s *)inode->i_private; /* Get exclusive access to the driver data structure */ ret = nxsem_wait(&priv->devsem); if (ret < 0) { /* This should only happen if the wait was cancelled by an signal */ DEBUGASSERT(ret == -EINTR || ret == -ECANCELED); return ret; } /* Process the IOCTL by command */ switch (cmd) { case TSIOC_SETFREQUENCY: /* arg: Pointer to uint32_t frequency value */ { FAR uint32_t *ptr = (FAR uint32_t *)((uintptr_t)arg); DEBUGASSERT(priv->config != NULL && ptr != NULL); priv->config->frequency = SPI_SETFREQUENCY(priv->spi, *ptr); } break; case TSIOC_GETFREQUENCY: /* arg: Pointer to uint32_t frequency value */ { FAR uint32_t *ptr = (FAR uint32_t *)((uintptr_t)arg); DEBUGASSERT(priv->config != NULL && ptr != NULL); *ptr = priv->config->frequency; } break; default: ret = -ENOTTY; break; } nxsem_post(&priv->devsem); return ret; }
static int smps_open(FAR struct file *filep) { FAR struct inode *inode = filep->f_inode; FAR struct smps_dev_s *dev = inode->i_private; uint8_t tmp; int ret; /* If the port is the middle of closing, wait until the close is finished */ ret = nxsem_wait(&dev->closesem); if (ret >= 0) { /* Increment the count of references to the device. If this the first * time that the driver has been opened for this device, then initialize * the device. */ tmp = dev->ocount + 1; if (tmp == 0) { /* More than 255 opens; uint8_t overflows to zero */ ret = -EMFILE; } else { /* Check if this is the first time that the driver has been opened. */ if (tmp == 1) { /* Yes.. perform one time hardware initialization. */ irqstate_t flags = enter_critical_section(); ret = dev->ops->setup(dev); if (ret == OK) { /* Save the new open count on success */ dev->ocount = tmp; } leave_critical_section(flags); } } nxsem_post(&dev->closesem); } return OK; }
static inline int btn_takesem(sem_t *sem) { int ret; /* Take a count from the semaphore, possibly waiting */ ret = nxsem_wait(sem); /* The only case that an error should occur here is if the wait * was awakened by a signal */ DEBUGASSERT(ret == OK || ret == -EINTR); return ret; }
static int ft80x_open(FAR struct file *filep) { #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS FAR struct inode *inode; FAR struct ft80x_dev_s *priv; uint8_t tmp; int ret; DEBUGASSERT(filep != NULL); inode = filep->f_inode; DEBUGASSERT(inode != NULL && inode->i_private != NULL); priv = inode->i_private; lcdinfo("crefs: %d\n", priv->crefs); /* Get exclusive access to the device structures */ ret = nxsem_wait(&priv->exclsem); if (ret < 0) { goto errout; } /* Increment the count of references to the device */ tmp = priv->crefs + 1; if (tmp == 0) { /* More than 255 opens; uint8_t overflows to zero */ ret = -EMFILE; goto errout_with_sem; } /* Save the new open count */ priv->crefs = tmp; ret = OK; errout_with_sem: nxsem_post(&priv->exclsem); errout: return ret; #else return OK; #endif }
static FAR char *unique_chardev(void) { struct stat statbuf; char devbuf[16]; uint32_t devno; int ret; /* Loop until we get a unique device name */ for (; ; ) { /* Get the semaphore protecting the path number */ do { ret = nxsem_wait(&g_devno_sem); /* The only case that an error should occur here is if the wait * was awakened by a signal. */ DEBUGASSERT(ret == OK || ret == -EINTR); } while (ret == -EINTR); /* Get the next device number and release the semaphore */ devno = ++g_devno; nxsem_post(&g_devno_sem); /* Construct the full device number */ devno &= 0xffffff; snprintf(devbuf, 16, "/dev/tmp%06lx", (unsigned long)devno); /* Make sure that file name is not in use */ ret = stat(devbuf, &statbuf); if (ret < 0) { DEBUGASSERT(errno == ENOENT); return strdup(devbuf); } /* It is in use, try again */ } }
static int pwm_close(FAR struct file *filep) { FAR struct inode *inode = filep->f_inode; FAR struct pwm_upperhalf_s *upper = inode->i_private; int ret; pwminfo("crefs: %d\n", upper->crefs); /* Get exclusive access to the device structures */ ret = nxsem_wait(&upper->exclsem); if (ret < 0) { goto errout; } /* Decrement the references to the driver. If the reference count will * decrement to 0, then uninitialize the driver. */ if (upper->crefs > 1) { upper->crefs--; } else { FAR struct pwm_lowerhalf_s *lower = upper->dev; /* There are no more references to the port */ upper->crefs = 0; /* Disable the PWM device */ DEBUGASSERT(lower->ops->shutdown != NULL); pwminfo("calling shutdown: %d\n"); lower->ops->shutdown(lower); } ret = OK; nxsem_post(&upper->exclsem); errout: return ret; }
static ssize_t ft80x_write(FAR struct file *filep, FAR const char *buffer, size_t len) { FAR struct inode *inode; FAR struct ft80x_dev_s *priv; int ret; lcdinfo("buffer: %p len %lu\n", buffer, (unsigned long)len); DEBUGASSERT(buffer != NULL && ((uintptr_t)buffer & 3) == 0 && len > 0 && (len & 3) == 0 && len <= FT80X_RAM_DL_SIZE); DEBUGASSERT(filep != NULL); inode = filep->f_inode; DEBUGASSERT(inode != NULL && inode->i_private != NULL); priv = inode->i_private; if (buffer == NULL || ((uintptr_t)buffer & 3) != 0 || len == 0 || (len & 3) != 0 || (len + filep->f_pos) > FT80X_RAM_DL_SIZE) { return -EINVAL; } /* Get exclusive access to the device structures */ ret = nxsem_wait(&priv->exclsem); if (ret < 0) { return ret; } /* Note that there is no check if the driver was opened read-only. That * would be a silly thing to do. */ /* The write method is functionally equivalent to the FT80X_IOC_CREATEDL * IOCTL command: It simply copies the display list in the user buffer to * the FT80x display list memory. */ ft80x_write_memory(priv, FT80X_RAM_DL + filep->f_pos, buffer, len); filep->f_pos += len; nxsem_post(&priv->exclsem); return len; }
static void _sdc_semtake(FAR sem_t *sem) { int ret; do { /* Take the semaphore (perhaps waiting) */ ret = nxsem_wait(sem); /* The only case that an error should occur here is if the wait was * awakened by a signal. */ DEBUGASSERT(ret == OK || ret == -EINTR); } while (ret == -EINTR); }
static void pty_semtake(FAR struct pty_devpair_s *devpair) { int ret; do { /* Take the semaphore (perhaps waiting) */ ret = nxsem_wait(&devpair->pp_exclsem); /* The only case that an error should occur here is if the wait was * awakened by a signal. */ DEBUGASSERT(ret == OK || ret == -EINTR); } while (ret == -EINTR); }
static int tc_ioctl(FAR struct file *filep, int cmd, unsigned long arg) { #if 1 iinfo("cmd: %d arg: %ld\n", cmd, arg); return -ENOTTY; /* None yet supported */ #else FAR struct inode *inode; FAR struct tc_dev_s *priv; int ret; iinfo("cmd: %d arg: %ld\n", cmd, arg); DEBUGASSERT(filep); inode = filep->f_inode; DEBUGASSERT(inode && inode->i_private); priv = (FAR struct tc_dev_s *)inode->i_private; /* Get exclusive access to the driver data structure */ ret = nxsem_wait(&priv->devsem); if (ret < 0) { /* This should only happen if the wait was canceled by an signal */ DEBUGASSERT(ret == -EINTR || ret == -ECANCELED); return ret; } /* Process the IOCTL by command */ switch (cmd) { /* ADD IOCTL COMMAND CASES HERE */ default: ret = -ENOTTY; break; } nxsem_post(&priv->devsem); return ret; #endif }
static int mtdconfig_open(FAR struct file *filep) { FAR struct inode *inode = filep->f_inode; FAR struct mtdconfig_struct_s *dev = inode->i_private; int ret; /* Get exclusive access to the device */ ret = nxsem_wait(&dev->exclsem); if (ret < 0) { ferr("ERROR: nxsem_wait failed: %d\n", ret); DEBUGASSERT(ret == -EINTR || ret == -ECANCELED); goto errout; } dev->readoff = 0; errout: return ret; }
static int ads7843e_close(FAR struct file *filep) { #ifdef CONFIG_ADS7843E_REFCNT FAR struct inode *inode; FAR struct ads7843e_dev_s *priv; int ret; iinfo("Closing\n"); DEBUGASSERT(filep); inode = filep->f_inode; DEBUGASSERT(inode && inode->i_private); priv = (FAR struct ads7843e_dev_s *)inode->i_private; /* Get exclusive access to the driver data structure */ ret = nxsem_wait(&priv->devsem); if (ret < 0) { /* This should only happen if the wait was canceled by an signal */ DEBUGASSERT(ret == -EINTR || ret == -ECANCELED); return ret; } /* Decrement the reference count unless it would decrement a negative * value. When the count decrements to zero, there are no further * open references to the driver. */ if (priv->crefs >= 1) { priv->crefs--; } nxsem_post(&priv->devsem); #endif iinfo("Closing\n"); return OK; }
int bcmf_sdpcm_queue_frame(FAR struct bcmf_dev_s *priv, struct bcmf_frame_s *frame, bool control) { FAR struct bcmf_sdio_dev_s *sbus = (FAR struct bcmf_sdio_dev_s *)priv->bus; struct bcmf_sdio_frame *sframe = (struct bcmf_sdio_frame *)frame; struct bcmf_sdpcm_header *header = (struct bcmf_sdpcm_header *)sframe->data; /* Prepare sw header */ memset(header, 0, sizeof(struct bcmf_sdpcm_header)); header->size = frame->len; header->checksum = ~header->size; header->data_offset = (uint8_t)(frame->data - frame->base); if (control) { header->channel = SDPCM_CONTROL_CHANNEL; } else { header->channel = SDPCM_DATA_CHANNEL; } /* Add frame in tx queue */ if (nxsem_wait(&sbus->queue_mutex) < 0) { PANIC(); } bcmf_dqueue_push(&sbus->tx_queue, &sframe->list_entry); nxsem_post(&sbus->queue_mutex); /* Notify bcmf thread tx frame is ready */ nxsem_post(&sbus->thread_signal); return OK; }
struct bcmf_frame_s *bcmf_sdpcm_get_rx_frame(FAR struct bcmf_dev_s *priv) { dq_entry_t *entry; struct bcmf_sdio_frame *sframe; FAR struct bcmf_sdio_dev_s *sbus = (FAR struct bcmf_sdio_dev_s *)priv->bus; if (nxsem_wait(&sbus->queue_mutex) < 0) { PANIC(); } entry = bcmf_dqueue_pop_tail(&sbus->rx_queue); nxsem_post(&sbus->queue_mutex); if (entry == NULL) { return NULL; } sframe = container_of(entry, struct bcmf_sdio_frame, list_entry); return &sframe->header; }
static int smps_close(FAR struct file *filep) { FAR struct inode *inode = filep->f_inode; FAR struct smps_dev_s *dev = inode->i_private; irqstate_t flags; int ret; ret = nxsem_wait(&dev->closesem); if (ret >= 0) { /* Decrement the references to the driver. If the reference count will * decrement to 0, then uninitialize the driver. */ if (dev->ocount > 1) { dev->ocount--; nxsem_post(&dev->closesem); } else { /* There are no more references to the port */ dev->ocount = 0; /* Free the IRQ and disable the SMPS device */ flags = enter_critical_section(); /* Disable interrupts */ dev->ops->shutdown(dev); /* Disable the SMPS */ leave_critical_section(flags); nxsem_post(&dev->closesem); } } return ret; }
static int tc_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup) { FAR struct inode *inode; FAR struct tc_dev_s *priv; int ret; int i; iinfo("setup: %d\n", (int)setup); DEBUGASSERT(filep && fds); inode = filep->f_inode; DEBUGASSERT(inode && inode->i_private); priv = (FAR struct tc_dev_s *)inode->i_private; /* Are we setting up the poll? Or tearing it down? */ ret = nxsem_wait(&priv->devsem); if (ret < 0) { /* This should only happen if the wait was canceled by an signal */ DEBUGASSERT(ret == -EINTR || ret == -ECANCELED); return ret; } if (setup) { /* Ignore waits that do not include POLLIN */ if ((fds->events & POLLIN) == 0) { ierr("ERROR: Missing POLLIN: revents: %08x\n", fds->revents); ret = -EDEADLK; goto errout; } /* This is a request to set up the poll. Find an available * slot for the poll structure reference */ for (i = 0; i < CONFIG_TOUCHSCREEN_NPOLLWAITERS; i++) { /* Find an available slot */ if (!priv->fds[i]) { /* Bind the poll structure and this slot */ priv->fds[i] = fds; fds->priv = &priv->fds[i]; break; } } if (i >= CONFIG_TOUCHSCREEN_NPOLLWAITERS) { ierr("ERROR: No availabled slot found: %d\n", i); fds->priv = NULL; ret = -EBUSY; goto errout; } /* Should we immediately notify on any of the requested events? */ if (priv->penchange) { tc_notify(priv); } } else if (fds->priv) { /* This is a request to tear down the poll. */ struct pollfd **slot = (struct pollfd **)fds->priv; DEBUGASSERT(slot != NULL); /* Remove all memory of the poll setup */ *slot = NULL; fds->priv = NULL; } errout: nxsem_post(&priv->devsem); return ret; }
static int pty_open(FAR struct file *filep) { FAR struct inode *inode; FAR struct pty_dev_s *dev; FAR struct pty_devpair_s *devpair; int ret; DEBUGASSERT(filep != NULL && filep->f_inode != NULL); inode = filep->f_inode; dev = inode->i_private; DEBUGASSERT(dev != NULL && dev->pd_devpair != NULL); devpair = dev->pd_devpair; /* Wait if this is an attempt to open the slave device and the slave * device is locked. */ if (!dev->pd_master) { /* Slave... Check if the slave driver is locked. We need to lock the * scheduler while we are running to prevent asyncrhonous modification * of pp_locked by pty_ioctl(). */ sched_lock(); while (devpair->pp_locked) { /* Wait until unlocked. We will also most certainly suspend here. */ (void)nxsem_wait(&devpair->pp_slavesem); /* Get exclusive access to the device structure. This might also * cause suspension. */ pty_semtake(devpair); /* Check again in case something happened asynchronously while we * were suspended. */ if (devpair->pp_locked) { /* This cannot suspend because we have the scheduler locked. * So pp_locked cannot change asyncrhonously between this test * and the redundant test at the top of the loop. */ pty_semgive(devpair); } } sched_unlock(); } else { /* Master ... Get exclusive access to the device structure */ pty_semtake(devpair); } #ifndef CONFIG_PSEUDOTERM_SUSV1 /* If one side of the driver has been unlinked, then refuse further * opens. * * NOTE: We ignore this case in the SUSv1 case. In the SUSv1 case, the * master side is always unlinked. */ if (devpair->pp_unlinked) { ret = -EIDRM; } else #endif { /* Increment the count of open references on the driver */ devpair->pp_nopen++; DEBUGASSERT(devpair->pp_nopen > 0); ret = OK; } pty_semgive(devpair); return ret; }
int bcmf_sdpcm_sendframe(FAR struct bcmf_dev_s *priv) { int ret; bool is_txframe; dq_entry_t *entry; struct bcmf_sdio_frame *sframe; struct bcmf_sdpcm_header *header; FAR struct bcmf_sdio_dev_s *sbus = (FAR struct bcmf_sdio_dev_s *)priv->bus; if (sbus->tx_queue.tail == NULL) { /* No more frames to send */ return -ENODATA; } if (sbus->tx_seq == sbus->max_seq) { // TODO handle this case wlerr("No credit to send frame\n"); return -EAGAIN; } if (nxsem_wait(&sbus->queue_mutex) < 0) { PANIC(); } entry = sbus->tx_queue.tail; sframe = container_of(entry, struct bcmf_sdio_frame, list_entry); header = (struct bcmf_sdpcm_header *)sframe->header.base; /* Set frame sequence id */ header->sequence = sbus->tx_seq++; // wlinfo("Send frame %p\n", sframe); // bcmf_hexdump(sframe->header.base, sframe->header.len, // (unsigned long)sframe->header.base); ret = bcmf_transfer_bytes(sbus, true, 2, 0, sframe->header.base, sframe->header.len); if (ret != OK) { wlinfo("fail send frame %d\n", ret); ret = -EIO; goto exit_abort; // TODO handle retry count and remove frame from queue + abort TX } /* Frame sent, remove it from queue */ bcmf_dqueue_pop_tail(&sbus->tx_queue); nxsem_post(&sbus->queue_mutex); is_txframe = sframe->tx; /* Free frame buffer */ bcmf_sdio_free_frame(priv, sframe); if (is_txframe) { /* Notify upper layer at least one TX buffer is available */ bcmf_netdev_notify_tx_done(priv); } return OK; exit_abort: // bcmf_sdpcm_txfail(sbus, false); nxsem_post(&sbus->queue_mutex); return ret; }
int bcmf_sdpcm_readframe(FAR struct bcmf_dev_s *priv) { int ret; uint16_t len, checksum; struct bcmf_sdpcm_header *header; struct bcmf_sdio_frame *sframe; FAR struct bcmf_sdio_dev_s *sbus = (FAR struct bcmf_sdio_dev_s *)priv->bus; /* Request free frame buffer */ sframe = bcmf_sdio_allocate_frame(priv, false, false); if (sframe == NULL) { wlinfo("fail alloc\n"); return -EAGAIN; } header = (struct bcmf_sdpcm_header *)sframe->data; /* Read header */ ret = bcmf_transfer_bytes(sbus, false, 2, 0, (uint8_t *)header, 4); if (ret != OK) { wlinfo("failread size\n"); ret = -EIO; goto exit_abort; } len = header->size; checksum = header->checksum; /* All zero means no more to read */ if (!(len | checksum)) { ret = -ENODATA; goto exit_free_frame; } if (((~len & 0xffff) ^ checksum) || len < sizeof(struct bcmf_sdpcm_header)) { wlerr("Invalid header checksum or len %x %x\n", len, checksum); ret = -EINVAL; goto exit_abort; } if (len > sframe->header.len) { wlerr("Frame is too large, cancel %d %d\n", len, sframe->header.len); ret = -ENOMEM; goto exit_abort; } /* Read remaining frame data */ ret = bcmf_transfer_bytes(sbus, false, 2, 0, (uint8_t *)header + 4, len - 4); if (ret != OK) { ret = -EIO; goto exit_abort; } // wlinfo("Receive frame %p %d\n", sframe, len); // bcmf_hexdump((uint8_t *)header, header->size, (unsigned int)header); /* Process and validate header */ ret = bcmf_sdpcm_process_header(sbus, header); if (ret != OK) { wlerr("Error while processing header %d\n", ret); ret = -EINVAL; goto exit_free_frame; } /* Update frame structure */ sframe->header.len = header->size; sframe->header.data += header->data_offset; /* Process received frame content */ switch (header->channel & 0x0f) { case SDPCM_CONTROL_CHANNEL: ret = bcmf_cdc_process_control_frame(priv, &sframe->header); goto exit_free_frame; case SDPCM_EVENT_CHANNEL: if (header->data_offset == header->size) { /* Empty event, ignore */ ret = OK; } else { ret = bcmf_bdc_process_event_frame(priv, &sframe->header); } goto exit_free_frame; case SDPCM_DATA_CHANNEL: /* Queue frame and notify network layer frame is available */ if (nxsem_wait(&sbus->queue_mutex) < 0) { PANIC(); } bcmf_dqueue_push(&sbus->rx_queue, &sframe->list_entry); nxsem_post(&sbus->queue_mutex); bcmf_netdev_notify_rx(priv); /* Upper layer have to free all received frames */ ret = OK; break; default: wlerr("Got unexpected message type %d\n", header->channel); ret = -EINVAL; goto exit_free_frame; } return ret; exit_abort: bcmf_sdpcm_rxfail(sbus, false); exit_free_frame: bcmf_sdio_free_frame(priv, sframe); return ret; }
static int oneshot_ioctl(FAR struct file *filep, int cmd, unsigned long arg) { FAR struct inode *inode; FAR struct oneshot_dev_s *priv; int ret; tmrinfo("cmd=%d arg=%08lx\n", cmd, (unsigned long)arg); DEBUGASSERT(filep != NULL && filep->f_inode != NULL); inode = filep->f_inode; priv = (FAR struct oneshot_dev_s *)inode->i_private; DEBUGASSERT(priv != NULL); /* Get exclusive access to the device structures */ ret = nxsem_wait(&priv->od_exclsem); if (ret < 0) { return ret; } /* Handle oneshot timer ioctl commands */ switch (cmd) { /* OSIOC_MAXDELAY - Return the maximum delay that can be supported * by this timer. * Argument: A referenct to a struct timespec in * which the maximum time will be returned. */ case OSIOC_MAXDELAY: { FAR struct timespec *ts = (FAR struct timespec *)((uintptr_t)arg); DEBUGASSERT(ts != NULL); ret = ONESHOT_MAX_DELAY(priv->od_lower, ts); } break; /* OSIOC_START - Start the oneshot timer * Argument: A reference to struct oneshot_start_s */ case OSIOC_START: { FAR struct oneshot_start_s *start; pid_t pid; start = (FAR struct oneshot_start_s *)((uintptr_t)arg); DEBUGASSERT(start != NULL); /* Save signalling information */ priv->od_signo = start->signo; priv->od_arg = start->arg; pid = start->pid; if (pid == 0) { pid = getpid(); } priv->od_pid = pid; /* Start the oneshot timer */ ret = ONESHOT_START(priv->od_lower, oneshot_callback, priv, &start->ts); } break; /* OSIOC_CANCEL - Stop the timer * Argument: A reference to a struct timespec in * which the time remaining will be returned. */ case OSIOC_CANCEL: { FAR struct timespec *ts = (FAR struct timespec *)((uintptr_t)arg); /* Cancel the oneshot timer */ ret = ONESHOT_CANCEL(priv->od_lower, ts); } break; /* OSIOC_CURRENT - Get the current time * Argument: A reference to a struct timespec in * which the current time will be returned. */ case OSIOC_CURRENT: { FAR struct timespec *ts = (FAR struct timespec *)((uintptr_t)arg); /* Get the current time */ ret = ONESHOT_CURRENT(priv->od_lower, ts); } break; default: { tmrerr("ERROR: Unrecognized cmd: %d arg: %ld\n", cmd, arg); ret = -ENOTTY; } break; } nxsem_post(&priv->od_exclsem); return ret; }
static ssize_t tc_read(FAR struct file *filep, FAR char *buffer, size_t len) { FAR struct inode *inode; FAR struct tc_dev_s *priv; FAR struct touch_sample_s *report; struct tc_sample_s sample; int ret; DEBUGASSERT(filep); inode = filep->f_inode; DEBUGASSERT(inode && inode->i_private); priv = (FAR struct tc_dev_s *)inode->i_private; /* Verify that the caller has provided a buffer large enough to receive * the touch data. */ if (len < SIZEOF_TOUCH_SAMPLE_S(1)) { /* We could provide logic to break up a touch report into segments and * handle smaller reads... but why? */ return -ENOSYS; } /* Get exclusive access to the driver data structure */ ret = nxsem_wait(&priv->devsem); if (ret < 0) { /* This should only happen if the wait was canceled by an signal */ DEBUGASSERT(ret == -EINTR || ret == -ECANCELED); return ret; } /* Try to read sample data. */ ret = tc_sample(priv, &sample); if (ret < 0) { /* Sample data is not available now. We would ave to wait to get * receive sample data. If the user has specified the O_NONBLOCK * option, then just return an error. */ if (filep->f_oflags & O_NONBLOCK) { ret = -EAGAIN; goto errout; } /* Wait for sample data */ ret = tc_waitsample(priv, &sample); if (ret < 0) { /* We might have been awakened by a signal */ goto errout; } } /* In any event, we now have sampled touchscreen data that we can report * to the caller. */ report = (FAR struct touch_sample_s *)buffer; memset(report, 0, SIZEOF_TOUCH_SAMPLE_S(1)); report->npoints = 1; report->point[0].id = sample.id; report->point[0].x = sample.x; report->point[0].y = sample.y; /* Report the appropriate flags */ if (sample.contact == CONTACT_UP) { /* Pen is now up. Is the positional data valid? This is important to * know because the release will be sent to the window based on its * last positional data. */ if (sample.valid) { report->point[0].flags = TOUCH_UP | TOUCH_ID_VALID | TOUCH_POS_VALID | TOUCH_PRESSURE_VALID; } else { report->point[0].flags = TOUCH_UP | TOUCH_ID_VALID; } } else { if (sample.contact == CONTACT_DOWN) { /* First contact */ report->point[0].flags = TOUCH_DOWN | TOUCH_ID_VALID | TOUCH_POS_VALID; } else /* if (sample->contact == CONTACT_MOVE) */ { /* Movement of the same contact */ report->point[0].flags = TOUCH_MOVE | TOUCH_ID_VALID | TOUCH_POS_VALID; } } ret = SIZEOF_TOUCH_SAMPLE_S(1); errout: nxsem_post(&priv->devsem); return ret; }
static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg) { FAR struct inode *inode; FAR struct ft80x_dev_s *priv; int ret; DEBUGASSERT(filep != NULL); inode = filep->f_inode; DEBUGASSERT(inode != NULL && inode->i_private != NULL); priv = inode->i_private; lcdinfo("cmd: %d arg: %lu\n", cmd, arg); /* Get exclusive access to the device structures */ ret = nxsem_wait(&priv->exclsem); if (ret < 0) { return ret; } /* Handle built-in ioctl commands */ switch (cmd) { /* FT80X_IOC_CREATEDL: * Description: Write a display list to the FT80x display list memory * Description: Write a display list to the FT80x display list memory * starting at offset zero. This may or may not be the * entire display list. Display lists may be created * incrementally, starting with FT80X_IOC_CREATEDL and * finishing the display list using FT80XIO_APPENDDL * Argument: A reference to a display list structure instance. * See struct ft80x_displaylist_s. * Returns: None */ case FT80X_IOC_CREATEDL: /* Set the file position to zero and fall through to "append" the new * display list data at offset 0. */ filep->f_pos = 0; /* FALLTHROUGH */ /* FT80X_IOC_APPENDDL: * Description: Write additional display list entries to the FT80x * display list memory at the current display list offset. * This IOCTL command permits display lists to be completed * incrementally, starting with FT80X_IOC_CREATEDL and * finishing the display list using FT80XIO_APPENDDL. * Argument: A reference to a display list structure instance. See * struct ft80x_displaylist_s. * Returns: None */ case FT80X_IOC_APPENDDL: { FAR struct ft80x_displaylist_s *dl = (FAR struct ft80x_displaylist_s *)((uintptr_t)arg); if (dl == NULL || ((uintptr_t)&dl->cmd & 3) != 0 || (dl->dlsize & 3) != 0 || dl->dlsize + filep->f_pos > FT80X_RAM_DL_SIZE) { ret = -EINVAL; } else { /* Check if there is a display list. It might be useful for * the application to issue FT80X_IOC_CREATEDL with no data in * order to initialize the display list, then form all of the * list entries with FT80X_IOC_APPENDDL. */ if (dl->dlsize > 0) { /* This IOCTL command simply copies the display list * provided into the FT80x display list memory. */ ft80x_write_memory(priv, FT80X_RAM_DL + filep->f_pos, &dl->cmd, dl->dlsize); filep->f_pos += dl->dlsize; } ret = OK; } } break; /* FT80X_IOC_GETRAMDL: * Description: Read a 32-bit value from the display list. * Argument: A reference to an instance of struct ft80x_relmem_s. * Returns: The 32-bit value read from the display list. */ case FT80X_IOC_GETRAMDL: { FAR struct ft80x_relmem_s *ramdl = (FAR struct ft80x_relmem_s *)((uintptr_t)arg); if (ramdl == NULL || ((uintptr_t)ramdl->offset & 3) != 0 || ramdl->offset >= FT80X_RAM_DL_SIZE) { ret = -EINVAL; } else { ft80x_read_memory(priv, FT80X_RAM_DL + ramdl->offset, ramdl->value, ramdl->nbytes); ret = OK; } } break; /* FT80X_IOC_PUTRAMG * Description: Write byte data to FT80x graphics memory (RAM_G) * Argument: A reference to an instance of struct ft80x_relmem_s. * Returns: None. */ case FT80X_IOC_PUTRAMG: { FAR struct ft80x_relmem_s *ramg = (FAR struct ft80x_relmem_s *)((uintptr_t)arg); if (ramg == NULL || (ramg->offset + ramg->nbytes) >= FT80X_RAM_G_SIZE) { ret = -EINVAL; } else { ft80x_write_memory(priv, FT80X_RAM_G + ramg->offset, ramg->value, ramg->nbytes); ret = OK; } } break; /* FT80X_IOC_PUTRAMCMD * Description: Write 32-bit aligned data to FT80x FIFO (RAM_CMD) * Argument: A reference to an instance of struct ft80x_relmem_s below. * Returns: None. */ case FT80X_IOC_PUTRAMCMD: { FAR struct ft80x_relmem_s *ramcmd = (FAR struct ft80x_relmem_s *)((uintptr_t)arg); if (ramcmd == NULL || ((uintptr_t)ramcmd->offset & 3) != 0 /* || ramcmd->offset >= FT80X_CMDFIFO_SIZE */ ) { ret = -EINVAL; } else { ft80x_write_memory(priv, FT80X_RAM_CMD + ramcmd->offset, ramcmd->value, ramcmd->nbytes); ret = OK; } } break; /* FT80X_IOC_GETREG8: * Description: Read an 8-bit register value from the FT80x. * Argument: A reference to an instance of struct ft80x_register_s. * Returns: The 8-bit value read from the register. */ case FT80X_IOC_GETREG8: { FAR struct ft80x_register_s *reg = (FAR struct ft80x_register_s *)((uintptr_t)arg); if (reg == NULL || ((uintptr_t)reg->addr & 3) != 0) { ret = -EINVAL; } else { reg->value.u8 = ft80x_read_byte(priv, reg->addr); ret = OK; } } break; /* FT80X_IOC_GETREG16: * Description: Read a 16-bit register value from the FT80x. * Argument: A reference to an instance of struct ft80x_register_s. * Returns: The 16-bit value read from the register. */ case FT80X_IOC_GETREG16: { FAR struct ft80x_register_s *reg = (FAR struct ft80x_register_s *)((uintptr_t)arg); if (reg == NULL || ((uintptr_t)reg->addr & 3) != 0) { ret = -EINVAL; } else { reg->value.u16 = ft80x_read_hword(priv, reg->addr); ret = OK; } } break; /* FT80X_IOC_GETREG32: * Description: Read a 32-bit register value from the FT80x. * Argument: A reference to an instance of struct ft80x_register_s. * Returns: The 32-bit value read from the register. */ case FT80X_IOC_GETREG32: { FAR struct ft80x_register_s *reg = (FAR struct ft80x_register_s *)((uintptr_t)arg); if (reg == NULL || ((uintptr_t)reg->addr & 3) != 0) { ret = -EINVAL; } else { reg->value.u32 = ft80x_read_word(priv, reg->addr); ret = OK; } } break; /* FT80X_IOC_GETREGS: * Description: Read multiple 32-bit register values from the FT80x. * Argument: A reference to an instance of struct ft80x_registers_s. * Returns: The 32-bit values read from the consecutive registers . */ case FT80X_IOC_GETREGS: { FAR struct ft80x_registers_s *regs = (FAR struct ft80x_registers_s *)((uintptr_t)arg); if (regs == NULL || ((uintptr_t)regs->addr & 3) != 0) { ret = -EINVAL; } else { ft80x_read_memory(priv, regs->addr, regs->value, (size_t)regs->nregs << 2); ret = OK; } } break; /* FT80X_IOC_PUTREG8: * Description: Write an 8-bit register value to the FT80x. * Argument: A reference to an instance of struct ft80x_register_s. * Returns: None. */ case FT80X_IOC_PUTREG8: { FAR struct ft80x_register_s *reg = (FAR struct ft80x_register_s *)((uintptr_t)arg); if (reg == NULL || ((uintptr_t)reg->addr & 3) != 0) { ret = -EINVAL; } else { ft80x_write_byte(priv, reg->addr, reg->value.u8); ret = OK; } } break; /* FT80X_IOC_PUTREG16: * Description: Write a 16-bit register value to the FT80x. * Argument: A reference to an instance of struct ft80x_register_s. * Returns: None. */ case FT80X_IOC_PUTREG16: { FAR struct ft80x_register_s *reg = (FAR struct ft80x_register_s *)((uintptr_t)arg); if (reg == NULL || ((uintptr_t)reg->addr & 3) != 0) { ret = -EINVAL; } else { ft80x_write_hword(priv, reg->addr, reg->value.u16); ret = OK; } } break; /* FT80X_IOC_PUTREG32: * Description: Write a 32-bit register value to the FT80x. * Argument: A reference to an instance of struct ft80x_register_s. * Returns: None. */ case FT80X_IOC_PUTREG32: { FAR struct ft80x_register_s *reg = (FAR struct ft80x_register_s *)((uintptr_t)arg); if (reg == NULL || ((uintptr_t)reg->addr & 3) != 0) { ret = -EINVAL; } else { ft80x_write_word(priv, reg->addr, reg->value.u32); ret = OK; } } break; /* FT80X_IOC_PUTREGS: * Description: Write multiple 32-bit register values to the FT80x. * Argument: A reference to an instance of struct ft80x_registers_s. * Returns: None. */ case FT80X_IOC_PUTREGS: { FAR struct ft80x_registers_s *regs = (FAR struct ft80x_registers_s *)((uintptr_t)arg); if (regs == NULL || ((uintptr_t)regs->addr & 3) != 0) { ret = -EINVAL; } else { ft80x_write_memory(priv, regs->addr, regs->value, (size_t)regs->nregs << 2); ret = OK; } } break; /* FT80X_IOC_EVENTNOTIFY: * Description: Setup to receive a signal when an event occurs. * Argument: A reference to an instance of struct ft80x_notify_s. * Returns: None */ case FT80X_IOC_EVENTNOTIFY: { FAR struct ft80x_notify_s *notify = (FAR struct ft80x_notify_s *)((uintptr_t)arg); if (notify == NULL || !GOOD_SIGNO(notify->signo) || notify->pid < 0 || (unsigned int)notify->event >= FT80X_INT_NEVENTS) { ret = -EINVAL; } else { FAR struct ft80x_eventinfo_s *info = &priv->notify[notify->event]; uint32_t regval; /* Are we enabling or disabling */ if (notify->enable) { /* Make sure that arguments are valid for the enable */ if (notify->signo == 0 || notify->pid == 0) { ret = -EINVAL; } else { /* Setup the new notification information */ info->signo = notify->signo; info->pid = notify->pid; info->enable = true; /* Enable interrupts associated with the event */ regval = ft80x_read_word(priv, FT80X_REG_INT_MASK); regval |= (1 << notify->event); ft80x_write_word(priv, FT80X_REG_INT_MASK, regval); ret = OK; } } else { /* Disable the notification */ info->signo = 0; info->pid = 0; info->enable = false; /* Disable interrupts associated with the event */ regval = ft80x_read_word(priv, FT80X_REG_INT_MASK); regval &= ~(1 << notify->event); ft80x_write_word(priv, FT80X_REG_INT_MASK, regval); ret = OK; } } } break; /* FT80X_IOC_FADE: * Description: Change the backlight intensity with a controllable * fade. * Argument: A reference to an instance of struct ft80x_fade_s. * Returns: None. */ case FT80X_IOC_FADE: { FAR const struct ft80x_fade_s *fade = (FAR const struct ft80x_fade_s *)((uintptr_t)arg); if (fade == NULL || fade->duty > 100 || fade->delay < MIN_FADE_DELAY || fade->delay > MAX_FADE_DELAY) { ret = -EINVAL; } else { ret = ft80x_fade(priv, fade); } } break; /* FT80X_IOC_AUDIO: * Description: Enable/disable an external audio amplifer. * Argument: 0=disable; 1=enable. * Returns: None. */ case FT80X_IOC_AUDIO: { #if defined(CONFIG_LCD_FT80X_AUDIO_MCUSHUTDOWN) /* Amplifier is controlled by an MCU GPIO pin */ DEBUGASSERT(priv->lower->attach != NULL && priv->lower->audio != NULL); DEBUGASSERT(arg == 0 || arg == 1); priv->lower->audio(priv->lower, (arg != 0)); ret = OK; #elif defined(CONFIG_LCD_FT80X_AUDIO_GPIOSHUTDOWN) /* Amplifier is controlled by an FT80x GPIO pin */ uint8_t regval8; DEBUGASSERT(arg == 0 || arg == 1); regval8 = ft80x_read_byte(priv, FT80X_REG_GPIO); /* Active low logic assumed */ if (arg == 0) { regval8 |= (1 << CONFIG_LCD_FT80X_AUDIO_GPIO); } else { regval8 &= ~(1 << CONFIG_LCD_FT80X_AUDIO_GPIO); } ft80x_write_byte(priv, FT80X_REG_GPIO, regval8); ret = OK; #else /* Amplifier is not controllable. */ DEBUGASSERT(arg == 0 || arg == 1); return OK; #endif } break; /* Unrecognized IOCTL command */ default: lcderr("ERROR: Unrecognized cmd: %d arg: %ld\n", cmd, arg); ret = -ENOTTY; break; } nxsem_post(&priv->exclsem); return ret; }
static void ft80x_interrupt_work(FAR void *arg) { FAR struct ft80x_dev_s *priv = (FAR struct ft80x_dev_s *)arg; uint32_t intflags; uint32_t regval; int ret; DEBUGASSERT(priv != NULL); /* Get exclusive access to the device structures */ do { ret = nxsem_wait(&priv->exclsem); DEBUGASSERT(ret == OK || ret == -EINTR); } while (ret < 0); /* Get the set of pending interrupts. Note that simply reading this * register is sufficient to clear all pending interrupts. */ intflags = ft80x_read_word(priv, FT80X_REG_INT_FLAGS); /* And process each pending interrupt. * * REVISIT: No interrupt sources are ever enabled in the current * implementation. */ if ((intflags & FT80X_INT_SWAP) != 0) { /* Display swap occurred */ lcdinfo("Display swap occurred\n"); ft80x_notify(priv, FT80X_NOTIFY_SWAP, 0); } if ((intflags & FT80X_INT_TOUCH) != 0) { /* Touch-screen touch detected */ lcdinfo("Touch-screen touch detected\n"); ft80x_notify(priv, FT80X_NOTIFY_TOUCH, 0); } if ((intflags & FT80X_INT_TAG) != 0) { /* Touch-screen tag value change */ lcdinfo("Touch-screen tag value change\n"); #ifdef CONFIG_LCD_FT800 regval = ft80x_read_word(priv, FT80X_REG_TOUCH_TAG); #else regval = ft80x_read_word(priv, FT80X_REG_CTOUCH_TAG); #endif ft80x_notify(priv, FT80X_NOTIFY_TAG, (int)(regval & TOUCH_TAG_MASK)); } if ((intflags & FT80X_INT_SOUND) != 0) { /* Sound effect ended */ lcdinfo(" Sound effect ended\n"); ft80x_notify(priv, FT80X_NOTIFY_SOUND, 0); } if ((intflags & FT80X_INT_PLAYBACK) != 0) { /* Audio playback ended */ lcdinfo("Audio playback ended\n"); ft80x_notify(priv, FT80X_NOTIFY_PLAYBACK, 0); } if ((intflags & FT80X_INT_CMDEMPTY) != 0) { /* Command FIFO empty */ lcdinfo("Command FIFO empty\n"); ft80x_notify(priv, FT80X_NOTIFY_CMDEMPTY, 0); } if ((intflags & FT80X_INT_CMDFLAG) != 0) { /* Command FIFO flag */ lcdinfo("Command FIFO flag\n"); ft80x_notify(priv, FT80X_NOTIFY_CMDFLAG, 0); } if ((intflags & FT80X_INT_CONVCOMPLETE) != 0) { /* Touch-screen conversions completed */ lcdinfo(" Touch-screen conversions completed\n"); ft80x_notify(priv, FT80X_NOTIFY_CONVCOMPLETE, 0); } /* Re-enable interrupts */ DEBUGASSERT(priv->lower != NULL && priv->lower->enable != NULL); priv->lower->enable(priv->lower, true); nxsem_post(&priv->exclsem); }